@instructure/ui-drilldown 11.7.2-snapshot-18 → 11.7.2-snapshot-20

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +12 -2
  2. package/es/Drilldown/v2/DrilldownGroup/index.js +55 -0
  3. package/es/Drilldown/v2/DrilldownGroup/props.js +26 -0
  4. package/es/Drilldown/v2/DrilldownOption/index.js +54 -0
  5. package/es/Drilldown/v2/DrilldownOption/props.js +26 -0
  6. package/es/Drilldown/v2/DrilldownPage/index.js +50 -0
  7. package/es/Drilldown/v2/DrilldownPage/props.js +26 -0
  8. package/es/Drilldown/v2/DrilldownSeparator/index.js +47 -0
  9. package/es/Drilldown/v2/DrilldownSeparator/props.js +26 -0
  10. package/es/Drilldown/v2/index.js +1358 -0
  11. package/es/Drilldown/v2/props.js +28 -0
  12. package/es/Drilldown/v2/styles.js +84 -0
  13. package/es/exports/b.js +28 -0
  14. package/lib/Drilldown/v2/DrilldownGroup/index.js +58 -0
  15. package/lib/Drilldown/v2/DrilldownGroup/props.js +31 -0
  16. package/lib/Drilldown/v2/DrilldownOption/index.js +58 -0
  17. package/lib/Drilldown/v2/DrilldownOption/props.js +31 -0
  18. package/lib/Drilldown/v2/DrilldownPage/index.js +56 -0
  19. package/lib/Drilldown/v2/DrilldownPage/props.js +31 -0
  20. package/lib/Drilldown/v2/DrilldownSeparator/index.js +51 -0
  21. package/lib/Drilldown/v2/DrilldownSeparator/props.js +31 -0
  22. package/lib/Drilldown/v2/index.js +1369 -0
  23. package/lib/Drilldown/v2/props.js +33 -0
  24. package/lib/Drilldown/v2/styles.js +90 -0
  25. package/lib/exports/b.js +40 -0
  26. package/package.json +28 -28
  27. package/src/Drilldown/v2/DrilldownGroup/index.tsx +64 -0
  28. package/src/Drilldown/v2/DrilldownGroup/props.ts +134 -0
  29. package/src/Drilldown/v2/DrilldownOption/index.tsx +65 -0
  30. package/src/Drilldown/v2/DrilldownOption/props.ts +211 -0
  31. package/src/Drilldown/v2/DrilldownPage/index.tsx +55 -0
  32. package/src/Drilldown/v2/DrilldownPage/props.ts +102 -0
  33. package/src/Drilldown/v2/DrilldownSeparator/index.tsx +57 -0
  34. package/src/Drilldown/v2/DrilldownSeparator/props.ts +56 -0
  35. package/src/Drilldown/v2/README.md +1445 -0
  36. package/src/Drilldown/v2/index.tsx +1681 -0
  37. package/src/Drilldown/v2/props.ts +361 -0
  38. package/src/Drilldown/v2/styles.ts +97 -0
  39. package/src/exports/b.ts +44 -0
  40. package/tsconfig.build.tsbuildinfo +1 -1
  41. package/types/Drilldown/v2/DrilldownGroup/index.d.ts +41 -0
  42. package/types/Drilldown/v2/DrilldownGroup/index.d.ts.map +1 -0
  43. package/types/Drilldown/v2/DrilldownGroup/props.d.ts +69 -0
  44. package/types/Drilldown/v2/DrilldownGroup/props.d.ts.map +1 -0
  45. package/types/Drilldown/v2/DrilldownOption/index.d.ts +69 -0
  46. package/types/Drilldown/v2/DrilldownOption/index.d.ts.map +1 -0
  47. package/types/Drilldown/v2/DrilldownOption/props.d.ts +125 -0
  48. package/types/Drilldown/v2/DrilldownOption/props.d.ts.map +1 -0
  49. package/types/Drilldown/v2/DrilldownPage/index.d.ts +32 -0
  50. package/types/Drilldown/v2/DrilldownPage/index.d.ts.map +1 -0
  51. package/types/Drilldown/v2/DrilldownPage/props.d.ts +51 -0
  52. package/types/Drilldown/v2/DrilldownPage/props.d.ts.map +1 -0
  53. package/types/Drilldown/v2/DrilldownSeparator/index.d.ts +22 -0
  54. package/types/Drilldown/v2/DrilldownSeparator/index.d.ts.map +1 -0
  55. package/types/Drilldown/v2/DrilldownSeparator/props.d.ts +17 -0
  56. package/types/Drilldown/v2/DrilldownSeparator/props.d.ts.map +1 -0
  57. package/types/Drilldown/v2/index.d.ts +212 -0
  58. package/types/Drilldown/v2/index.d.ts.map +1 -0
  59. package/types/Drilldown/v2/props.d.ts +210 -0
  60. package/types/Drilldown/v2/props.d.ts.map +1 -0
  61. package/types/Drilldown/v2/styles.d.ts +15 -0
  62. package/types/Drilldown/v2/styles.d.ts.map +1 -0
  63. package/types/exports/b.d.ts +11 -0
  64. package/types/exports/b.d.ts.map +1 -0
@@ -0,0 +1,1358 @@
1
+ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
2
+ const _excluded = ["groupProps"],
3
+ _excluded2 = ["groupProps"],
4
+ _excluded3 = ["id", "themeOverride"];
5
+ var _dec, _dec2, _class, _Drilldown, _ChevronRightInstUIIc, _ChevronLeftInstUIIco, _CheckInstUIIcon, _Options$Separator, _Options$Separator2;
6
+ /*
7
+ * The MIT License (MIT)
8
+ *
9
+ * Copyright (c) 2015 - present Instructure, Inc.
10
+ *
11
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ * of this software and associated documentation files (the "Software"), to deal
13
+ * in the Software without restriction, including without limitation the rights
14
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ * copies of the Software, and to permit persons to whom the Software is
16
+ * furnished to do so, subject to the following conditions:
17
+ *
18
+ * The above copyright notice and this permission notice shall be included in all
19
+ * copies or substantial portions of the Software.
20
+ *
21
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ * SOFTWARE.
28
+ */
29
+
30
+ import { Children, Component } from 'react';
31
+ import { warn, error } from '@instructure/console';
32
+ import { contains, containsActiveElement } from '@instructure/ui-dom-utils';
33
+ import { deepEqual } from '@instructure/ui-utils';
34
+ import { callRenderProp, matchComponentTypes, omitProps, safeCloneElement, withDeterministicId } from '@instructure/ui-react-utils';
35
+ import { View } from '@instructure/ui-view/latest';
36
+ import { Options } from '@instructure/ui-options/latest';
37
+ import { Popover } from '@instructure/ui-popover/latest';
38
+ import { Selectable } from '@instructure/ui-selectable';
39
+ import { ChevronLeftInstUIIcon, ChevronRightInstUIIcon, CheckInstUIIcon } from '@instructure/ui-icons';
40
+ import { withStyle } from '@instructure/emotion';
41
+ import { DrilldownSeparator } from "./DrilldownSeparator/index.js";
42
+ import { DrilldownOption } from "./DrilldownOption/index.js";
43
+ import { DrilldownGroup } from "./DrilldownGroup/index.js";
44
+ import { DrilldownPage } from "./DrilldownPage/index.js";
45
+ import generateStyle from "./styles.js";
46
+ import { allowedProps } from "./props.js"; // Additional data we need to track on the Options,
47
+ // but shouldn't be settable via props
48
+ // Contains the Option ComponentElement and the extra data we need track on it,
49
+ // but don't want to expose as props
50
+ // Contains the props object of the Page
51
+ // with the `children` transformed into an array
52
+ // An object with the mapped Pages with their id as keys
53
+ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
54
+ import { createElement as _createElement } from "@emotion/react";
55
+ /**
56
+ ---
57
+ category: components
58
+ ---
59
+ **/
60
+ let Drilldown = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle), _dec(_class = _dec2(_class = (_Drilldown = class Drilldown extends Component {
61
+ constructor(props) {
62
+ super(props);
63
+ this._drilldownRef = null;
64
+ this._popover = null;
65
+ this._trigger = null;
66
+ this._containerElement = null;
67
+ this._id = void 0;
68
+ this._triggerId = void 0;
69
+ this._headerBackId = void 0;
70
+ this._headerTitleId = void 0;
71
+ this._headerTitleLabelId = void 0;
72
+ this._headerActionId = void 0;
73
+ // Array of visited page ids in "breadcrumbs" fashion
74
+ this._pageHistory = void 0;
75
+ // Map of the active options on the page (includes header options too)
76
+ this._activeOptionsMap = {};
77
+ this.ref = null;
78
+ this.handleRef = el => {
79
+ // ref and elementRef have to be set together for the same element
80
+ const elementRef = this.props.elementRef;
81
+ this.ref = el;
82
+ if (typeof elementRef === 'function') {
83
+ elementRef(el);
84
+ }
85
+ };
86
+ this.handleDrilldownRef = el => {
87
+ const drilldownRef = this.props.drilldownRef;
88
+ this._drilldownRef = el;
89
+ if (typeof drilldownRef === 'function') {
90
+ drilldownRef(el);
91
+ }
92
+
93
+ // setting ref for "non-popover" version, the drilldown itself
94
+ // (if a trigger is provided, the Popover sets the ref)
95
+ if (!this.props.trigger) {
96
+ this.handleRef(el);
97
+ }
98
+ };
99
+ this.show = event => {
100
+ if (this._popover) {
101
+ this._popover.show(event);
102
+ this.setState({
103
+ isShowingPopover: true
104
+ });
105
+ }
106
+ };
107
+ this.hide = event => {
108
+ if (this._popover) {
109
+ this._popover.hide(event);
110
+ this.setState({
111
+ isShowingPopover: false
112
+ });
113
+ this.reset();
114
+ }
115
+ };
116
+ this.handleOptionHighlight = (_event, {
117
+ id,
118
+ direction
119
+ }) => {
120
+ const rotateFocus = this.props.rotateFocus;
121
+ const highlightedOptionId = this.state.highlightedOptionId;
122
+
123
+ // if id exists, use that, or calculate from direction
124
+ let highlightId = this.getPageChildById(id) ? id : void 0;
125
+ if (!highlightId) {
126
+ if (!highlightedOptionId) {
127
+ // nothing highlighted yet, highlight first option
128
+ highlightId = this.activeOptionIds[0];
129
+ } else if (direction) {
130
+ // if it has direction, find next id based on it
131
+ const index = this.activeOptionIds.indexOf(highlightedOptionId);
132
+ const newIndex = index + direction;
133
+ highlightId = index > -1 ? this.activeOptionIds[newIndex] : void 0;
134
+ if (rotateFocus) {
135
+ const lastOptionsIndex = this.activeOptionIds.length - 1;
136
+ if (newIndex < 0) {
137
+ highlightId = this.activeOptionIds[lastOptionsIndex];
138
+ }
139
+ if (newIndex > lastOptionsIndex) {
140
+ highlightId = this.activeOptionIds[0];
141
+ }
142
+ }
143
+ }
144
+ }
145
+ if (highlightId) {
146
+ // only highlight if id exists as a valid option
147
+ this.setState({
148
+ highlightedOptionId: highlightId
149
+ }, () => {
150
+ this.focusOption(highlightId);
151
+ });
152
+ }
153
+ };
154
+ // Navigates to the page and also returns the new and old pageIds
155
+ this.goToPage = newPageId => {
156
+ var _this$pageMap;
157
+ if (!newPageId) {
158
+ warn(false, `Cannot go to page because there was no page id provided.`);
159
+ return void 0;
160
+ }
161
+
162
+ // TS complains that it cannot be true, but since it is an exposed method,
163
+ // it is better if we provide a warning for this case too
164
+ if (typeof newPageId !== 'string') {
165
+ warn(false, `Cannot go to page because parameter newPageId has to be string (valid page id). Current newPageId is "${typeof newPageId}".`);
166
+ return void 0;
167
+ }
168
+ if (!((_this$pageMap = this.pageMap) !== null && _this$pageMap !== void 0 && _this$pageMap[newPageId])) {
169
+ warn(false, `Cannot go to page because page with id: "${newPageId}" doesn't exist.`);
170
+ return void 0;
171
+ }
172
+
173
+ // the last page id in the history is the current one,
174
+ // it will become the "prevPage"
175
+ const prevPageId = this._pageHistory[this._pageHistory.length - 1];
176
+ const idxInHistory = this._pageHistory.indexOf(newPageId);
177
+ if (idxInHistory < 0) {
178
+ // if it is not in the page history, we have to add it
179
+ this._pageHistory.push(newPageId);
180
+ } else {
181
+ // if it was already in the history, we go back to that page,
182
+ // and clear the rest from the history
183
+ this._pageHistory.splice(idxInHistory + 1, this._pageHistory.length - 1);
184
+ }
185
+ this.setState({
186
+ activePageId: newPageId,
187
+ highlightedOptionId: void 0
188
+ });
189
+ return {
190
+ prevPageId,
191
+ newPageId
192
+ };
193
+ };
194
+ this.goToPreviousPage = () => {
195
+ if (!this.previousPage) {
196
+ warn(false, `There is no previous page to go to. The current page history is: [${this._pageHistory.join(', ')}].`);
197
+ return void 0;
198
+ }
199
+
200
+ // If there is a previous page, goToPage will succeed and return the data
201
+ const _ref = this.goToPage(this.previousPage.id),
202
+ newPageId = _ref.newPageId,
203
+ prevPageId = _ref.prevPageId;
204
+ return {
205
+ newPageId,
206
+ prevPageId
207
+ };
208
+ };
209
+ this.handleBackButtonClick = () => {
210
+ const _ref2 = this.currentPage,
211
+ onBackButtonClicked = _ref2.onBackButtonClicked;
212
+
213
+ // we only display the back button when there is a page to go back to
214
+ const _ref3 = this.goToPreviousPage(),
215
+ newPageId = _ref3.newPageId,
216
+ prevPageId = _ref3.prevPageId;
217
+ if (typeof onBackButtonClicked === 'function') {
218
+ onBackButtonClicked(newPageId, prevPageId);
219
+ }
220
+ };
221
+ this.handleOptionSelect = (event, {
222
+ id
223
+ }) => {
224
+ var _this$currentPage, _selectedOption$group;
225
+ const selectedOption = this.getPageChildById(id);
226
+ if (!id || !selectedOption) {
227
+ event.preventDefault();
228
+ event.stopPropagation();
229
+ return;
230
+ }
231
+ const isOptionDisabled = id !== this._headerBackId && (this.props.disabled || ((_this$currentPage = this.currentPage) === null || _this$currentPage === void 0 ? void 0 : _this$currentPage.disabled) || ((_selectedOption$group = selectedOption.groupProps) === null || _selectedOption$group === void 0 ? void 0 : _selectedOption$group.disabled) || selectedOption.props.disabled);
232
+ if (isOptionDisabled) {
233
+ event.preventDefault();
234
+ event.stopPropagation();
235
+ return;
236
+ }
237
+ const _this$props = this.props,
238
+ shouldHideOnSelect = _this$props.shouldHideOnSelect,
239
+ onSelect = _this$props.onSelect;
240
+ const groupProps = selectedOption.groupProps,
241
+ selectedOptionChild = _objectWithoutProperties(selectedOption, _excluded);
242
+ const _selectedOptionChild$ = selectedOptionChild.props,
243
+ subPageId = _selectedOptionChild$.subPageId,
244
+ href = _selectedOptionChild$.href,
245
+ value = _selectedOptionChild$.value,
246
+ onOptionClick = _selectedOptionChild$.onOptionClick;
247
+ if (typeof onOptionClick === 'function') {
248
+ onOptionClick(event, {
249
+ optionId: id,
250
+ drilldown: this,
251
+ ...this.exposedNavigationProps
252
+ });
253
+ }
254
+ if (subPageId) {
255
+ this.goToPage(subPageId);
256
+ }
257
+ if (event.type === 'keydown' && href) {
258
+ var _this$_drilldownRef;
259
+ const optionEl = (_this$_drilldownRef = this._drilldownRef) === null || _this$_drilldownRef === void 0 ? void 0 : _this$_drilldownRef.querySelector(`#${CSS.escape(id)}`);
260
+ const isLink = optionEl.tagName.toLowerCase() === 'a';
261
+
262
+ // we need this check because in some cases
263
+ // we ignore href prop in renderOption()
264
+ if (isLink && optionEl !== null && optionEl !== void 0 && optionEl.href) {
265
+ optionEl.click();
266
+ }
267
+ }
268
+ if (groupProps !== null && groupProps !== void 0 && groupProps.selectableType) {
269
+ this.handleGroupOptionSelected(event, selectedOption);
270
+ } else {
271
+ // TODO workaround for react 19 default props
272
+ const optionWithDefaultProps = {
273
+ ...selectedOptionChild,
274
+ props: {
275
+ ...selectedOptionChild.props,
276
+ role: 'menuitem'
277
+ }
278
+ };
279
+ if (typeof onSelect === 'function') {
280
+ onSelect(event, {
281
+ value,
282
+ isSelected: true,
283
+ selectedOption: optionWithDefaultProps,
284
+ drilldown: this
285
+ });
286
+ }
287
+ }
288
+
289
+ // should prevent closing on page navigation
290
+ if (shouldHideOnSelect && !subPageId && id !== this._headerBackId) {
291
+ this.hide(event);
292
+ }
293
+ };
294
+ // Setting extra logic for keyboard navigation.
295
+ // Enter, Esc and up/down/home/end keys are handled by Selectable.
296
+ this.handleKeyDown = event => {
297
+ const id = event.target.id;
298
+ const option = this.getPageChildById(id);
299
+
300
+ // On Space...
301
+ if ([' ', 'space', 'Space'].includes(event.key)) {
302
+ // we need to preventDefault so the page doesn't scroll on Space
303
+ event.preventDefault();
304
+ event.stopPropagation();
305
+
306
+ // for options, Space it has to work as Enter (get selected)
307
+ if (option) {
308
+ this.handleOptionSelect(event, {
309
+ id
310
+ });
311
+ }
312
+ }
313
+
314
+ // On Right arrow...
315
+ if (event.key === 'ArrowRight') {
316
+ // if the option has subpage, we open it
317
+ if (option !== null && option !== void 0 && option.props.subPageId) {
318
+ this.handleOptionSelect(event, {
319
+ id
320
+ });
321
+ }
322
+ }
323
+
324
+ // On Left arrow...
325
+ if (event.key === 'ArrowLeft') {
326
+ var _this$_popover;
327
+ // if it is possible, we go a level up in the history
328
+ if (this._pageHistory.length > 1) {
329
+ this.handleBackButtonClick();
330
+ }
331
+
332
+ // if on root page and popover is open, we close it
333
+ if (this.isOnRootPage && (_this$_popover = this._popover) !== null && _this$_popover !== void 0 && _this$_popover.shown) {
334
+ this._popover.hide(event);
335
+ }
336
+ }
337
+ };
338
+ this.handleToggle = (event, shown) => {
339
+ const _this$props2 = this.props,
340
+ onToggle = _this$props2.onToggle,
341
+ trigger = _this$props2.trigger;
342
+ if (trigger && shown && this.currentPage) {
343
+ var _this$getFirstOption;
344
+ const actionLabel = callRenderProp(this.currentPage.renderActionLabel);
345
+ // Use action ID if exists, otherwise first non-action option's ID
346
+ const targetId = actionLabel ? this._headerActionId : (_this$getFirstOption = this.getFirstOption()) === null || _this$getFirstOption === void 0 ? void 0 : _this$getFirstOption.props.id;
347
+ setTimeout(() => {
348
+ this.setState({
349
+ highlightedOptionId: targetId
350
+ });
351
+ }, 10);
352
+ }
353
+ this.setState({
354
+ isShowingPopover: shown
355
+ });
356
+ if (typeof onToggle === 'function') {
357
+ onToggle(event, {
358
+ shown,
359
+ drilldown: this,
360
+ ...this.exposedNavigationProps
361
+ });
362
+ }
363
+ };
364
+ this.getFirstOption = () => {
365
+ var _this$currentPage2;
366
+ const children = Children.toArray((_this$currentPage2 = this.currentPage) === null || _this$currentPage2 === void 0 ? void 0 : _this$currentPage2.children);
367
+ const child = children[0];
368
+ if (!child) return void 0;
369
+
370
+ // If it's a regular option, return it
371
+ if (matchComponentTypes(child, [DrilldownOption])) {
372
+ return child;
373
+ }
374
+ // If it's a group, get its options
375
+ if (matchComponentTypes(child, [Drilldown.Group])) {
376
+ const groupOptions = Children.toArray(child.props.children);
377
+ return groupOptions[0];
378
+ }
379
+ return void 0;
380
+ };
381
+ this.state = {
382
+ isShowingPopover: props.trigger ? !!props.show : false,
383
+ activePageId: props.rootPageId,
384
+ highlightedOptionId: void 0,
385
+ lastSelectedId: void 0,
386
+ selectedGroupOptionsMap: this.getSelectedGroupOptionsMap()
387
+ };
388
+ this._pageHistory = [props.rootPageId];
389
+ this._id = props.id || props.deterministicId();
390
+ this._triggerId = props.deterministicId('Drilldown-Trigger');
391
+ this._headerBackId = props.deterministicId('DrilldownHeader-Back');
392
+ this._headerTitleId = props.deterministicId('DrilldownHeader-Title');
393
+ this._headerTitleLabelId = props.deterministicId('DrilldownHeader-Title-Label');
394
+ this._headerActionId = props.deterministicId('DrilldownHeader-Action');
395
+ }
396
+ componentDidMount() {
397
+ var _this$props$makeStyle, _this$props3;
398
+ (_this$props$makeStyle = (_this$props3 = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props3, this.makeStylesVariables);
399
+ }
400
+ componentDidUpdate(_prevProps, prevState) {
401
+ var _this$props$makeStyle2, _this$props4;
402
+ (_this$props$makeStyle2 = (_this$props4 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props4, this.makeStylesVariables);
403
+ if (prevState.activePageId !== this.state.activePageId) {
404
+ // on page change with mouse navigation, some option can get rendered
405
+ // under the cursor and get focused, so we need to wait a tick to see
406
+ // if anything gets focused, otherwise we focus the whole drilldown
407
+ setTimeout(() => {
408
+ if (!this.focused()) {
409
+ this.focus();
410
+ }
411
+ }, 0);
412
+ }
413
+
414
+ // if the current page was removed
415
+ if (!this.currentPage) {
416
+ if (this.previousPage) {
417
+ this.goToPreviousPage();
418
+ } else {
419
+ this.goToPage(this.props.rootPageId);
420
+ }
421
+ }
422
+ if (this.state.highlightedOptionId && !this.getPageChildById(this.state.highlightedOptionId)) {
423
+ this.setState({
424
+ highlightedOptionId: void 0
425
+ });
426
+ }
427
+
428
+ // This block syncs the internal state if the selectedOptions prop changes
429
+ // selectedOptions prop values always win over internal state.
430
+ let shouldUpdateState = false;
431
+ const nextSelectionMap = {
432
+ ...this.state.selectedGroupOptionsMap
433
+ };
434
+ this.pages.forEach(page => {
435
+ this.getChildrenArray(page.props.children).forEach(child => {
436
+ if (matchComponentTypes(child, [DrilldownGroup])) {
437
+ var _this$getChildrenArra;
438
+ const _child$props = child.props,
439
+ groupId = _child$props.id,
440
+ selectableType = _child$props.selectableType,
441
+ selectedOptions = _child$props.selectedOptions,
442
+ groupChildren = _child$props.children;
443
+ if (!selectableType || !Array.isArray(selectedOptions)) return;
444
+ const newGroupMap = new Map();
445
+ (_this$getChildrenArra = this.getChildrenArray(groupChildren)) === null || _this$getChildrenArra === void 0 ? void 0 : _this$getChildrenArra.forEach(groupChild => {
446
+ if (matchComponentTypes(groupChild, [DrilldownOption])) {
447
+ const _groupChild$props = groupChild.props,
448
+ optionId = _groupChild$props.id,
449
+ optionValue = _groupChild$props.value;
450
+ if (selectedOptions.includes(optionValue)) {
451
+ newGroupMap.set(optionId, optionValue);
452
+ }
453
+ }
454
+ });
455
+ const currentGroupMapInState = this.state.selectedGroupOptionsMap[groupId] || new Map();
456
+ if (!deepEqual(this.getNormalizedMap(newGroupMap), this.getNormalizedMap(currentGroupMapInState))) {
457
+ nextSelectionMap[groupId] = newGroupMap;
458
+ shouldUpdateState = true;
459
+ }
460
+ }
461
+ });
462
+ });
463
+ if (shouldUpdateState) {
464
+ this.setState({
465
+ selectedGroupOptionsMap: nextSelectionMap
466
+ });
467
+ }
468
+ }
469
+ get makeStylesVariables() {
470
+ return {
471
+ hasHighlightedOption: !!this.state.highlightedOptionId
472
+ };
473
+ }
474
+ get activeOptionIds() {
475
+ const orderedKeys = Object.keys(this._activeOptionsMap).sort((a, b) => {
476
+ return this._activeOptionsMap[a].index - this._activeOptionsMap[b].index;
477
+ });
478
+ return orderedKeys;
479
+ }
480
+ get activeOptions() {
481
+ return Object.values(this._activeOptionsMap);
482
+ }
483
+ get pages() {
484
+ const children = this.props.children;
485
+ return Children.toArray(children || []);
486
+ }
487
+ get pageMap() {
488
+ const children = this.props.children;
489
+ if (!children) {
490
+ return void 0;
491
+ }
492
+ const map = {};
493
+ this.pages.forEach(page => {
494
+ const props = page.props;
495
+ const children = props.children;
496
+ map[props.id] = {
497
+ ...props,
498
+ children: Children.toArray(children || [])
499
+ };
500
+ });
501
+ return map;
502
+ }
503
+ get isOnRootPage() {
504
+ return this.state.activePageId === this.props.rootPageId;
505
+ }
506
+ get currentPage() {
507
+ return this.getPageById(this.state.activePageId);
508
+ }
509
+ get previousPage() {
510
+ const previousPageId = this._pageHistory[this._pageHistory.length - 2];
511
+ return this.getPageById(previousPageId);
512
+ }
513
+
514
+ // Returns the navigation methods and the page history.
515
+ // These are used in some callbacks to expose the navigation logic.
516
+ get exposedNavigationProps() {
517
+ const goToPage = this.goToPage,
518
+ goToPreviousPage = this.goToPreviousPage;
519
+
520
+ // we make a copy of the array so the original history
521
+ // cannot be modified from the outside
522
+ const pageHistory = [...this._pageHistory];
523
+ return {
524
+ pageHistory,
525
+ goToPage,
526
+ goToPreviousPage
527
+ };
528
+ }
529
+ get currentPageAriaLabel() {
530
+ var _this$currentPage3;
531
+ // return, if explicitly set
532
+ if (this.props['aria-labelledby']) {
533
+ return this.props['aria-labelledby'];
534
+ }
535
+
536
+ // if it has title, point to the title label content
537
+ if ((_this$currentPage3 = this.currentPage) !== null && _this$currentPage3 !== void 0 && _this$currentPage3.renderTitle) {
538
+ return this._headerTitleLabelId;
539
+ }
540
+
541
+ // if root page has no title, try the trigger, if exists
542
+ if (this.isOnRootPage && this.props.trigger) {
543
+ return this._triggerId;
544
+ }
545
+ return void 0;
546
+ }
547
+ getChildrenArray(children) {
548
+ if (!children) {
549
+ return [];
550
+ }
551
+ return Array.isArray(children) ? children : [children];
552
+ }
553
+ getPageById(id) {
554
+ return this.pageMap && id ? this.pageMap[id] : void 0;
555
+ }
556
+ getPageChildById(id) {
557
+ return id ? this._activeOptionsMap[id] : void 0;
558
+ }
559
+ getNormalizedMap(map) {
560
+ return Array.from(map.entries());
561
+ }
562
+
563
+ /**
564
+ * Initializes the map of selected options for each group on initial render.
565
+ *
566
+ * This function establishes the selection state based on a clear precedence:
567
+ * 1. **Controlled Mode**: If a `Drilldown.Group` has the `selectedOptions` prop
568
+ * (as an array), it is treated as the absolute source of truth.
569
+ *
570
+ * 2. **Uncontrolled Mode**: If `selectedOptions` is not provided, the selection
571
+ * is determined by `defaultSelected` props, with the following priority:
572
+ * a. The `defaultSelected` boolean on an individual `Drilldown.Option`.
573
+ * b. The `defaultSelected` array of values on the `Drilldown.Group`.
574
+ *
575
+ * It also validates that 'single' selection groups do not mistakenly receive
576
+ * multiple selected or default values.
577
+ *
578
+ * @returns {SelectedGroupOptionsMap} An object where keys are group IDs and
579
+ * values are Maps of the selected { optionId: optionValue } pairs for that group.
580
+ */
581
+ getSelectedGroupOptionsMap() {
582
+ const selectedGroupOptionsMap = {};
583
+ this.pages.forEach(page => {
584
+ const children = page.props.children;
585
+ this.getChildrenArray(children).forEach(child => {
586
+ if (matchComponentTypes(child, [DrilldownGroup])) {
587
+ var _this$getChildrenArra2;
588
+ const _child$props2 = child.props,
589
+ groupId = _child$props2.id,
590
+ selectableType = _child$props2.selectableType,
591
+ selectedOptions = _child$props2.selectedOptions,
592
+ _child$props2$default = _child$props2.defaultSelected,
593
+ defaultSelected = _child$props2$default === void 0 ? [] : _child$props2$default,
594
+ groupChildren = _child$props2.children;
595
+ if (!selectableType) return;
596
+ selectedGroupOptionsMap[groupId] = new Map();
597
+ if (selectableType === 'single') {
598
+ if (Array.isArray(selectedOptions) && selectedOptions.length > 1) {
599
+ error(false, `Radio type selectable groups can have only one item selected! Group "${groupId}" has multiple values: [${selectedOptions.join(', ')}]!`);
600
+ return;
601
+ }
602
+ if (defaultSelected.length > 1) {
603
+ error(false, `Radio type selectable groups can have only one default item selected! Group "${groupId}" has multiple values: [${defaultSelected.join(', ')}]!`);
604
+ return;
605
+ }
606
+ }
607
+ (_this$getChildrenArra2 = this.getChildrenArray(groupChildren)) === null || _this$getChildrenArra2 === void 0 ? void 0 : _this$getChildrenArra2.forEach(groupChild => {
608
+ if (matchComponentTypes(groupChild, [DrilldownOption])) {
609
+ const _groupChild$props2 = groupChild.props,
610
+ optionId = _groupChild$props2.id,
611
+ optionValue = _groupChild$props2.value,
612
+ optionDefaultSelected = _groupChild$props2.defaultSelected;
613
+ if (optionValue == null) return;
614
+ let isSelected = false;
615
+ // If the group is controlled via the `selectedOptions` prop, it is the source of truth.
616
+ // `defaultSelected` values are ignored.
617
+ if (Array.isArray(selectedOptions)) {
618
+ isSelected = selectedOptions.includes(optionValue);
619
+ // Second strongest is the `defaultSelected` value on the option itself.
620
+ } else if (optionDefaultSelected === false) {
621
+ isSelected = false;
622
+ } else {
623
+ // Last is the `defaultSelected` array on the group.
624
+ const isGroupDefaultSelected = defaultSelected.includes(optionValue);
625
+ isSelected = optionDefaultSelected || isGroupDefaultSelected;
626
+ }
627
+ if (isSelected) {
628
+ selectedGroupOptionsMap[groupId].set(optionId, optionValue);
629
+ }
630
+ }
631
+ });
632
+ }
633
+ });
634
+ });
635
+ return selectedGroupOptionsMap;
636
+ }
637
+ get selectedGroupOptionIdsArray() {
638
+ return Object.values(this.state.selectedGroupOptionsMap).map(groupIdMap => Array.from(groupIdMap.keys())).flat();
639
+ }
640
+ get headerChildren() {
641
+ const currentPage = this.currentPage;
642
+ const _this$props5 = this.props,
643
+ styles = _this$props5.styles,
644
+ deterministicId = _this$props5.deterministicId;
645
+ const headerChildren = [];
646
+ if (!currentPage) {
647
+ return headerChildren;
648
+ }
649
+ const children = currentPage.children,
650
+ renderBackButtonLabel = currentPage.renderBackButtonLabel,
651
+ renderTitle = currentPage.renderTitle,
652
+ renderActionLabel = currentPage.renderActionLabel,
653
+ onHeaderActionClicked = currentPage.onHeaderActionClicked,
654
+ withoutHeaderSeparator = currentPage.withoutHeaderSeparator;
655
+
656
+ // Back navigation option
657
+ if (this.previousPage) {
658
+ const prevPageTitle = callRenderProp(this.previousPage.renderTitle);
659
+ const backButtonLabel = callRenderProp(renderBackButtonLabel, prevPageTitle);
660
+ headerChildren.push(_jsx(DrilldownOption, {
661
+ id: this._headerBackId,
662
+ onOptionClick: this.handleBackButtonClick,
663
+ children: _jsx("div", {
664
+ css: styles === null || styles === void 0 ? void 0 : styles.headerBack,
665
+ role: "presentation",
666
+ children: backButtonLabel
667
+ })
668
+ }));
669
+ }
670
+
671
+ // Header title
672
+ if (renderTitle) {
673
+ const title = callRenderProp(renderTitle);
674
+ if (title) {
675
+ headerChildren.push(_jsx(DrilldownOption, {
676
+ id: this._headerTitleId,
677
+ role: "presentation",
678
+ "aria-hidden": "true",
679
+ children: _jsx("div", {
680
+ css: styles === null || styles === void 0 ? void 0 : styles.headerTitle,
681
+ id: this._headerTitleLabelId,
682
+ children: title
683
+ })
684
+ }));
685
+ }
686
+ }
687
+
688
+ // Action label
689
+ if (renderActionLabel) {
690
+ const actionLabel = callRenderProp(renderActionLabel);
691
+ if (actionLabel) {
692
+ headerChildren.push(_jsx(DrilldownOption, {
693
+ id: this._headerActionId,
694
+ themeOverride: {
695
+ color: styles === null || styles === void 0 ? void 0 : styles.headerActionColor
696
+ },
697
+ onOptionClick: event => {
698
+ if (typeof onHeaderActionClicked === 'function') {
699
+ onHeaderActionClicked(event);
700
+ }
701
+ },
702
+ children: actionLabel
703
+ }));
704
+ }
705
+ }
706
+
707
+ // header separator
708
+ if (headerChildren.length > 0 && children.length > 0 && !withoutHeaderSeparator) {
709
+ headerChildren.push(_jsx(DrilldownSeparator, {
710
+ id: deterministicId('DrilldownHeader-Separator')
711
+ }));
712
+ }
713
+ return headerChildren;
714
+ }
715
+ get shown() {
716
+ return this.props.trigger ? this.state.isShowingPopover : true;
717
+ }
718
+ containsDuplicateChild(children) {
719
+ let containsDuplicate = false;
720
+ const childMap = new Map();
721
+ for (const child of children) {
722
+ var _child$props3;
723
+ if (child && typeof child === 'object' && (_child$props3 = child.props) !== null && _child$props3 !== void 0 && _child$props3.id) {
724
+ if (!childMap.has(child.props.id)) {
725
+ childMap.set(child.props.id, true);
726
+ } else {
727
+ warn(false, `Duplicate id: "${child.props.id}"! Make sure all options have unique ids, otherwise they won't be rendered.`);
728
+ return containsDuplicate = true;
729
+ }
730
+ }
731
+ }
732
+ return containsDuplicate;
733
+ }
734
+ reset() {
735
+ this._activeOptionsMap = {};
736
+ this.setState({
737
+ highlightedOptionId: void 0
738
+ });
739
+ }
740
+ focus() {
741
+ if (this.shown) {
742
+ var _this$_drilldownRef2, _this$_drilldownRef3;
743
+ error(!!((_this$_drilldownRef2 = this._drilldownRef) !== null && _this$_drilldownRef2 !== void 0 && _this$_drilldownRef2.focus), '[Drilldown] Could not focus the drilldown.');
744
+ (_this$_drilldownRef3 = this._drilldownRef) === null || _this$_drilldownRef3 === void 0 ? void 0 : _this$_drilldownRef3.focus();
745
+ } else {
746
+ var _this$_trigger;
747
+ error(!!((_this$_trigger = this._trigger) !== null && _this$_trigger !== void 0 && _this$_trigger.focus), '[Drilldown] Could not focus the trigger.');
748
+ this._trigger.focus();
749
+ }
750
+ }
751
+ focused() {
752
+ if (this.shown) {
753
+ return containsActiveElement(this._drilldownRef);
754
+ } else {
755
+ return containsActiveElement(this._trigger);
756
+ }
757
+ }
758
+ focusOption(id) {
759
+ const container = this._containerElement;
760
+ const optionElement = container === null || container === void 0 ? void 0 : container.querySelector(`[id="${CSS.escape(id)}"]`);
761
+ optionElement === null || optionElement === void 0 ? void 0 : optionElement.focus();
762
+ }
763
+ handleGroupOptionSelected(event, selectedOption) {
764
+ this.setState(oldState => {
765
+ var _oldState$selectedGro;
766
+ const _selectedOption$props = selectedOption.props,
767
+ optionId = _selectedOption$props.id,
768
+ value = _selectedOption$props.value;
769
+ const _ref4 = selectedOption.groupProps,
770
+ groupId = _ref4.id,
771
+ selectableType = _ref4.selectableType;
772
+ let newState = new Map(oldState.selectedGroupOptionsMap[groupId]);
773
+ if (selectableType === 'multiple' && Boolean((_oldState$selectedGro = oldState.selectedGroupOptionsMap[groupId]) === null || _oldState$selectedGro === void 0 ? void 0 : _oldState$selectedGro.has(optionId))) {
774
+ // toggle off, if already selected
775
+ newState.delete(optionId);
776
+ } else {
777
+ if (selectableType === 'multiple') {
778
+ // "checkbox"
779
+ newState.set(optionId, value);
780
+ } else if (selectableType === 'single') {
781
+ // "radio"
782
+ newState = new Map();
783
+ newState.set(optionId, value);
784
+ }
785
+ }
786
+ return {
787
+ ...oldState,
788
+ selectedGroupOptionsMap: {
789
+ ...oldState.selectedGroupOptionsMap,
790
+ [groupId]: newState
791
+ }
792
+ };
793
+ }, () => {
794
+ const value = selectedOption.props.value;
795
+ const _ref5 = selectedOption.groupProps,
796
+ groupId = _ref5.id,
797
+ groupOnSelect = _ref5.onSelect;
798
+ const onSelect = this.props.onSelect;
799
+ const groupProps = selectedOption.groupProps,
800
+ option = _objectWithoutProperties(selectedOption, _excluded2);
801
+ const selectedOptionValuesInGroup = [...this.state.selectedGroupOptionsMap[groupId].values()];
802
+ if (typeof groupOnSelect === 'function') {
803
+ groupOnSelect(event, {
804
+ value: selectedOptionValuesInGroup,
805
+ isSelected: selectedOptionValuesInGroup.includes(value),
806
+ selectedOption: option,
807
+ drilldown: this
808
+ });
809
+ }
810
+ if (typeof onSelect === 'function') {
811
+ onSelect(event, {
812
+ value: selectedOptionValuesInGroup,
813
+ isSelected: selectedOptionValuesInGroup.includes(value),
814
+ selectedOption: option,
815
+ drilldown: this
816
+ });
817
+ }
818
+ });
819
+ }
820
+ renderList(getOptionProps, getDisabledOptionProps) {
821
+ const currentPage = this.currentPage,
822
+ headerChildren = this.headerChildren;
823
+ if (!currentPage || this.containsDuplicateChild(currentPage.children)) {
824
+ return null;
825
+ }
826
+ const pageChildren = [...headerChildren, ...currentPage.children];
827
+
828
+ // for tracking if the last item was a Separator or not
829
+ let lastItemWasSeparator = false;
830
+ return pageChildren.map((child, index) => {
831
+ /**
832
+ * --- RENDER GROUP ---
833
+ */
834
+ if (matchComponentTypes(child, [DrilldownGroup])) {
835
+ const isFirstChild = index === 0;
836
+ const isLastChild = index === pageChildren.length - 1;
837
+ const afterSeparator = lastItemWasSeparator;
838
+ const needsFirstSeparator = !child.props.withoutSeparators && !isFirstChild && !afterSeparator;
839
+ const needsLastSeparator = !child.props.withoutSeparators && !isLastChild;
840
+ lastItemWasSeparator = needsLastSeparator;
841
+ return this.renderGroup(child, getOptionProps, getDisabledOptionProps,
842
+ // for rendering separators appropriately
843
+ needsFirstSeparator, needsLastSeparator);
844
+
845
+ /**
846
+ * --- RENDER SEPARATOR ---
847
+ */
848
+ } else if (matchComponentTypes(child, [DrilldownSeparator])) {
849
+ // if the last item was separator, we don't want to duplicate it
850
+ if (lastItemWasSeparator) {
851
+ return null;
852
+ }
853
+ lastItemWasSeparator = true;
854
+ return this.renderSeparator(child);
855
+
856
+ /**
857
+ * --- RENDER OPTION ---
858
+ */
859
+ } else if (matchComponentTypes(child, [DrilldownOption])) {
860
+ lastItemWasSeparator = false;
861
+ return this.renderOption(child, getOptionProps, getDisabledOptionProps);
862
+ } else {
863
+ return null;
864
+ }
865
+ });
866
+ }
867
+ renderSeparator(separator) {
868
+ const _separator$props = separator.props,
869
+ id = _separator$props.id,
870
+ themeOverride = _separator$props.themeOverride,
871
+ props = _objectWithoutProperties(_separator$props, _excluded3);
872
+ return _createElement(Options.Separator, {
873
+ ...props,
874
+ id: id,
875
+ key: id,
876
+ role: "separator"
877
+ // we pass the themeOverride to Options.Separator
878
+ ,
879
+ themeOverride: themeOverride
880
+ });
881
+ }
882
+ renderOption(option, getOptionProps, getDisabledOptionProps, groupProps) {
883
+ var _this$currentPage4, _optionProps$renderBe, _optionProps$renderBe2, _optionProps$renderAf, _optionProps$renderAf2;
884
+ const styles = this.props.styles;
885
+ let isSelected = false;
886
+ const _option$props = option.props,
887
+ id = _option$props.id,
888
+ children = _option$props.children,
889
+ href = _option$props.href,
890
+ _option$props$as = _option$props.as,
891
+ as = _option$props$as === void 0 ? 'li' : _option$props$as,
892
+ _option$props$role = _option$props.role,
893
+ role = _option$props$role === void 0 ? 'menuitem' : _option$props$role,
894
+ subPageId = _option$props.subPageId,
895
+ _option$props$disable = _option$props.disabled,
896
+ disabled = _option$props$disable === void 0 ? false : _option$props$disable,
897
+ renderLabelInfo = _option$props.renderLabelInfo,
898
+ renderBeforeLabel = _option$props.renderBeforeLabel,
899
+ renderAfterLabel = _option$props.renderAfterLabel,
900
+ _option$props$beforeL = _option$props.beforeLabelContentVAlign,
901
+ beforeLabelContentVAlign = _option$props$beforeL === void 0 ? 'start' : _option$props$beforeL,
902
+ _option$props$afterLa = _option$props.afterLabelContentVAlign,
903
+ afterLabelContentVAlign = _option$props$afterLa === void 0 ? 'start' : _option$props$afterLa,
904
+ description = _option$props.description,
905
+ descriptionRole = _option$props.descriptionRole,
906
+ elementRef = _option$props.elementRef,
907
+ themeOverride = _option$props.themeOverride;
908
+ if (!id) {
909
+ warn(false, `Drilldown.Option without id won't be rendered. It is needed to internally track the options.`);
910
+ return null;
911
+ }
912
+
913
+ // Props passed to the Option.Item
914
+ let optionProps = {
915
+ // passthrough props
916
+ ...omitProps(option.props, [...DrilldownOption.allowedProps, ...Options.Item.allowedProps]),
917
+ // props from selectable
918
+ ...getOptionProps({
919
+ id,
920
+ // aria-selected is only valid for these roles, otherwise we need to unset it
921
+ ...(role && !['gridcell', 'option', 'row', 'tab', 'columnheader', 'rowheader', 'treeitem'].includes(role) && {
922
+ 'aria-selected': void 0
923
+ })
924
+ }),
925
+ // we pass the themeOverride to Options.Item
926
+ themeOverride,
927
+ // directly passed props
928
+ renderBeforeLabel,
929
+ renderAfterLabel,
930
+ beforeLabelContentVAlign,
931
+ afterLabelContentVAlign,
932
+ description,
933
+ descriptionRole,
934
+ as,
935
+ role,
936
+ elementRef,
937
+ variant: 'default',
938
+ tabIndex: -1
939
+ };
940
+
941
+ // extra data we need track on the option,
942
+ // but don't want to expose as props
943
+ const optionData = {
944
+ groupProps: groupProps
945
+ };
946
+ const isOptionDisabled = id !== this._headerBackId && (
947
+ // Back nav is never disabled
948
+ this.props.disabled || ((_this$currentPage4 = this.currentPage) === null || _this$currentPage4 === void 0 ? void 0 : _this$currentPage4.disabled) || (groupProps === null || groupProps === void 0 ? void 0 : groupProps.disabled) || disabled);
949
+
950
+ // display option as disabled
951
+ if (isOptionDisabled) {
952
+ optionProps.variant = 'disabled';
953
+ optionProps = {
954
+ ...optionProps,
955
+ ...getDisabledOptionProps()
956
+ };
957
+ }
958
+
959
+ // track as valid active option if not the title and the map doesn't already contain the id
960
+ if (id !== this._headerTitleId && !this._activeOptionsMap[id]) {
961
+ // store index to know the order of ids later; js objects doesn't preserve order
962
+ this._activeOptionsMap[id] = {
963
+ ...option,
964
+ ...optionData,
965
+ index: Object.keys(this._activeOptionsMap).length + 1
966
+ };
967
+ }
968
+ const customRole = role !== DrilldownOption.defaultProps.role ? role : void 0;
969
+
970
+ // BEFORE/AFTER elements:
971
+ // we set a few manually on Options.Item,
972
+ // the rest are passed directly
973
+ if (subPageId) {
974
+ optionProps.renderAfterLabel = _ChevronRightInstUIIc || (_ChevronRightInstUIIc = _jsx(ChevronRightInstUIIcon, {}));
975
+ optionProps['aria-haspopup'] = true;
976
+ optionProps.role = customRole || 'menuitem';
977
+ warn(!renderAfterLabel, `The prop "renderAfterLabel" is reserved on item with id: "${id}". When it has "subPageId" provided, a navigation arrow will render after the label.`);
978
+ }
979
+ if (id === this._headerBackId) {
980
+ optionProps.renderBeforeLabel = _ChevronLeftInstUIIco || (_ChevronLeftInstUIIco = _jsx(ChevronLeftInstUIIcon, {}));
981
+ }
982
+ const isOptionControlled = typeof option.props.selected === 'boolean';
983
+ if ((groupProps !== null && groupProps !== void 0 && groupProps.selectableType || isOptionControlled) && groupProps) {
984
+ if (!isOptionControlled) {
985
+ var _this$state$selectedG;
986
+ isSelected = Boolean((_this$state$selectedG = this.state.selectedGroupOptionsMap[groupProps.id]) === null || _this$state$selectedG === void 0 ? void 0 : _this$state$selectedG.has(id));
987
+ } else {
988
+ isSelected = Boolean(option.props.selected);
989
+ }
990
+ optionProps['aria-checked'] = isSelected;
991
+ optionProps.renderBeforeLabel = _jsx("span", {
992
+ style: {
993
+ visibility: isSelected ? 'visible' : 'hidden'
994
+ },
995
+ children: _CheckInstUIIcon || (_CheckInstUIIcon = _jsx(CheckInstUIIcon, {}))
996
+ });
997
+ warn(!renderBeforeLabel, `The prop "renderBeforeLabel" is reserved on item with id: "${id}". When this option is a selectable member of a Drilldown.Group, selection indicator will render before the label.`);
998
+
999
+ // setting aria roles and attributes for selectable group items
1000
+ if (groupProps.selectableType === 'single') {
1001
+ optionProps.role = customRole || 'menuitemradio';
1002
+ }
1003
+ if (groupProps.selectableType === 'multiple') {
1004
+ optionProps.role = customRole || 'menuitemcheckbox';
1005
+ }
1006
+ }
1007
+ // display option as highlighted
1008
+ if (id === this.state.highlightedOptionId) {
1009
+ optionProps.variant = 'highlighted';
1010
+ if (isOptionDisabled) {
1011
+ optionProps.variant = 'highlighted-disabled';
1012
+ }
1013
+ }
1014
+ if (href) {
1015
+ if (subPageId) {
1016
+ warn(false, `Drilldown.Option with id "${id}" has subPageId, so it will ignore the "href" property.`);
1017
+ } else if (groupProps !== null && groupProps !== void 0 && groupProps.selectableType) {
1018
+ warn(false, `Drilldown.Option with id "${id}" is in a selectable group, so it will ignore the "href" property.`);
1019
+ } else {
1020
+ optionProps.href = href;
1021
+ }
1022
+ }
1023
+ const optionLabel = callRenderProp(children, {
1024
+ id,
1025
+ variant: optionProps.variant,
1026
+ isSelected
1027
+ });
1028
+ if (!optionLabel) {
1029
+ warn(false, `There are no "children" prop provided for option with id: "${id}", so it won't be rendered.`);
1030
+ return null;
1031
+ }
1032
+ const renderLabelProps = {
1033
+ variant: optionProps.variant,
1034
+ vAlign: afterLabelContentVAlign,
1035
+ as,
1036
+ role: optionProps.role,
1037
+ isSelected
1038
+ };
1039
+
1040
+ // we need to bind our own option props the render functions
1041
+ if (typeof optionProps.renderBeforeLabel === 'function' && !((_optionProps$renderBe = optionProps.renderBeforeLabel) !== null && _optionProps$renderBe !== void 0 && (_optionProps$renderBe2 = _optionProps$renderBe.prototype) !== null && _optionProps$renderBe2 !== void 0 && _optionProps$renderBe2.isReactComponent)) {
1042
+ optionProps.renderBeforeLabel = optionProps.renderBeforeLabel.bind(null, renderLabelProps);
1043
+ }
1044
+ if (typeof optionProps.renderAfterLabel === 'function' && !((_optionProps$renderAf = optionProps.renderAfterLabel) !== null && _optionProps$renderAf !== void 0 && (_optionProps$renderAf2 = _optionProps$renderAf.prototype) !== null && _optionProps$renderAf2 !== void 0 && _optionProps$renderAf2.isReactComponent)) {
1045
+ optionProps.renderAfterLabel = optionProps.renderAfterLabel.bind(null, renderLabelProps);
1046
+ }
1047
+ const labelInfo = renderLabelInfo && callRenderProp(renderLabelInfo, renderLabelProps);
1048
+ const vAlignMap = {
1049
+ start: 'flex-start',
1050
+ center: 'center',
1051
+ end: 'flex-end'
1052
+ };
1053
+ const labelAriaId = `${id}__label`;
1054
+ const infoAriaId = `${id}__info`;
1055
+ const labelledby = option.props['aria-labelledby'] || labelAriaId;
1056
+ const describedby = option.props['aria-describedby'] || (labelInfo ? infoAriaId : void 0);
1057
+ return _createElement(Options.Item, {
1058
+ ...optionProps,
1059
+ key: id,
1060
+ "aria-labelledby": labelledby,
1061
+ "aria-describedby": describedby
1062
+ }, _jsxs("div", {
1063
+ css: styles === null || styles === void 0 ? void 0 : styles.optionContainer,
1064
+ role: "none",
1065
+ children: [_jsx("span", {
1066
+ css: styles === null || styles === void 0 ? void 0 : styles.optionContent,
1067
+ role: "none",
1068
+ id: labelAriaId,
1069
+ children: optionLabel
1070
+ }), labelInfo ? _jsx("span", {
1071
+ css: styles === null || styles === void 0 ? void 0 : styles.optionLabelInfo,
1072
+ role: "presentation",
1073
+ style: {
1074
+ alignSelf: vAlignMap[afterLabelContentVAlign]
1075
+ },
1076
+ children: _jsx("span", {
1077
+ id: infoAriaId,
1078
+ children: labelInfo
1079
+ })
1080
+ }) : null]
1081
+ }));
1082
+ }
1083
+ renderGroup(group, getOptionProps, getDisabledOptionProps, needsFirstSeparator, needsLastSeparator) {
1084
+ const _group$props = group.props,
1085
+ id = _group$props.id,
1086
+ children = _group$props.children,
1087
+ renderGroupTitle = _group$props.renderGroupTitle,
1088
+ themeOverride = _group$props.themeOverride,
1089
+ _group$props$role = _group$props.role,
1090
+ role = _group$props$role === void 0 ? 'group' : _group$props$role,
1091
+ as = _group$props.as,
1092
+ elementRef = _group$props.elementRef;
1093
+ if (!children) {
1094
+ return null;
1095
+ }
1096
+ const groupChildren = [];
1097
+
1098
+ // add a separator above
1099
+ if (needsFirstSeparator) {
1100
+ groupChildren.push(_Options$Separator || (_Options$Separator = _jsx(Options.Separator, {}, "drilldown-options-separator")));
1101
+ }
1102
+
1103
+ // create a sublist as a group
1104
+ // (a wrapping list item will be created by Options)
1105
+ groupChildren.push(_jsx(Options, {
1106
+ id: id,
1107
+ role: role,
1108
+ as: as || this.props.as,
1109
+ renderLabel: renderGroupTitle,
1110
+ elementRef: elementRef
1111
+ // we pass the themeOverride to Options
1112
+ ,
1113
+ themeOverride: themeOverride,
1114
+ children: this.getChildrenArray(children).map(child => {
1115
+ if (matchComponentTypes(child, [DrilldownSeparator])) {
1116
+ return this.renderSeparator(child);
1117
+ } else if (matchComponentTypes(child, [DrilldownOption])) {
1118
+ return this.renderOption(child, getOptionProps, getDisabledOptionProps, group.props);
1119
+ } else {
1120
+ return null;
1121
+ }
1122
+ })
1123
+ }, id));
1124
+
1125
+ // add a separator below
1126
+ if (needsLastSeparator) {
1127
+ groupChildren.push(_Options$Separator2 || (_Options$Separator2 = _jsx(Options.Separator, {}, "drilldown-options-separator-2")));
1128
+ }
1129
+ return groupChildren;
1130
+ }
1131
+ renderPage() {
1132
+ const _this$props6 = this.props,
1133
+ styles = _this$props6.styles,
1134
+ overflowY = _this$props6.overflowY,
1135
+ overflowX = _this$props6.overflowX,
1136
+ height = _this$props6.height,
1137
+ width = _this$props6.width,
1138
+ minHeight = _this$props6.minHeight,
1139
+ minWidth = _this$props6.minWidth,
1140
+ maxHeight = _this$props6.maxHeight,
1141
+ maxWidth = _this$props6.maxWidth,
1142
+ role = _this$props6.role,
1143
+ as = _this$props6.as,
1144
+ label = _this$props6.label,
1145
+ trigger = _this$props6.trigger;
1146
+ if (!this.currentPage) {
1147
+ return null;
1148
+ }
1149
+ return _jsx(Selectable, {
1150
+ isShowingOptions: this.shown,
1151
+ highlightedOptionId: this.state.highlightedOptionId,
1152
+ selectedOptionId: this.selectedGroupOptionIdsArray,
1153
+ onRequestShowOptions: this.show,
1154
+ onRequestHideOptions: this.hide,
1155
+ onRequestSelectOption: this.handleOptionSelect,
1156
+ onRequestHighlightOption: this.handleOptionHighlight,
1157
+ onRequestHighlightFirstOption: event => {
1158
+ const firstOptionId = this.activeOptionIds[0];
1159
+ this.handleOptionHighlight(event, {
1160
+ id: firstOptionId
1161
+ });
1162
+ },
1163
+ onRequestHighlightLastOption: event => {
1164
+ const lastOptionId = this.activeOptionIds[this.activeOptionIds.length - 1];
1165
+ this.handleOptionHighlight(event, {
1166
+ id: lastOptionId
1167
+ });
1168
+ },
1169
+ children: ({
1170
+ // TODO: figure out what other Selectable props we need, if we want to add a Select version for drilldown:
1171
+ // getRootProps, - we probably don't need this
1172
+ // getLabelProps, - do we need label?
1173
+ // getDescriptionProps, - might be nice for assistiveText like in Select
1174
+ // getInputProps, - hidden input for a11y? role="combobox" might be needed
1175
+ getTriggerProps,
1176
+ getListProps,
1177
+ getOptionProps,
1178
+ getDisabledOptionProps
1179
+ }) => _jsx(View
1180
+ // if there is a trigger the border needs to be rendered by the <Popover>
1181
+ // (because it has an arrow)
1182
+ , {
1183
+ ...(trigger ? {} : {
1184
+ borderWidth: 'small'
1185
+ }),
1186
+ as: "div",
1187
+ "data-cid": "Drilldown",
1188
+ elementRef: this.handleDrilldownRef,
1189
+ tabIndex: 0,
1190
+ css: styles === null || styles === void 0 ? void 0 : styles.drilldown,
1191
+ position: "relative",
1192
+ borderRadius: "small",
1193
+ width: width,
1194
+ minWidth: maxWidth,
1195
+ maxWidth: maxWidth,
1196
+ role: role,
1197
+ "aria-label": label,
1198
+ "aria-labelledby": this.currentPageAriaLabel,
1199
+ ...getTriggerProps({
1200
+ id: this._id,
1201
+ // We need to override these aria attributes added by Selectable,
1202
+ // since Drilldown is not a combobox and has no popup
1203
+ 'aria-haspopup': false,
1204
+ 'aria-expanded': void 0,
1205
+ onKeyDown: this.handleKeyDown,
1206
+ onBlur: event => {
1207
+ const target = event.currentTarget;
1208
+ const related = event.relatedTarget;
1209
+ const containsRelated = contains(target, related);
1210
+ if (!related || related === this._drilldownRef || related !== target && !containsRelated) {
1211
+ this.setState({
1212
+ highlightedOptionId: void 0
1213
+ });
1214
+ }
1215
+ },
1216
+ onMouseLeave: () => {
1217
+ this.setState({
1218
+ highlightedOptionId: void 0
1219
+ });
1220
+ }
1221
+ }),
1222
+ children: _jsx(View, {
1223
+ as: "div",
1224
+ overflowY: overflowY,
1225
+ overflowX: overflowX,
1226
+ height: height,
1227
+ width: width,
1228
+ minHeight: minHeight,
1229
+ minWidth: minWidth,
1230
+ maxHeight: maxHeight,
1231
+ maxWidth: maxWidth,
1232
+ css: styles === null || styles === void 0 ? void 0 : styles.container,
1233
+ borderRadius: "small",
1234
+ role: "presentation",
1235
+ elementRef: element => {
1236
+ this._containerElement = element;
1237
+ },
1238
+ children: _jsx(Options, {
1239
+ ...getListProps(),
1240
+ role: "presentation",
1241
+ as: as,
1242
+ children: this.renderList(getOptionProps, getDisabledOptionProps)
1243
+ })
1244
+ })
1245
+ })
1246
+ });
1247
+ }
1248
+ render() {
1249
+ var _styles$drilldown;
1250
+ // clear temporary option store
1251
+ this._activeOptionsMap = {};
1252
+ const _this$props7 = this.props,
1253
+ show = _this$props7.show,
1254
+ defaultShow = _this$props7.defaultShow,
1255
+ placement = _this$props7.placement,
1256
+ withArrow = _this$props7.withArrow,
1257
+ shouldContainFocus = _this$props7.shouldContainFocus,
1258
+ shouldReturnFocus = _this$props7.shouldReturnFocus,
1259
+ trigger = _this$props7.trigger,
1260
+ mountNode = _this$props7.mountNode,
1261
+ constrain = _this$props7.constrain,
1262
+ positionTarget = _this$props7.positionTarget,
1263
+ positionContainerDisplay = _this$props7.positionContainerDisplay,
1264
+ popoverRef = _this$props7.popoverRef,
1265
+ disabled = _this$props7.disabled,
1266
+ onDismiss = _this$props7.onDismiss,
1267
+ onFocus = _this$props7.onFocus,
1268
+ onMouseOver = _this$props7.onMouseOver,
1269
+ offsetX = _this$props7.offsetX,
1270
+ offsetY = _this$props7.offsetY,
1271
+ shouldSetAriaExpanded = _this$props7.shouldSetAriaExpanded,
1272
+ styles = _this$props7.styles;
1273
+ const borderColor = styles === null || styles === void 0 ? void 0 : (_styles$drilldown = styles.drilldown) === null || _styles$drilldown === void 0 ? void 0 : _styles$drilldown.borderColor;
1274
+ return trigger ? _jsx(Popover, {
1275
+ "data-cid": "Drilldown",
1276
+ themeOverride: {
1277
+ // use here own theme's color
1278
+ borderColor: borderColor
1279
+ },
1280
+ shouldSetAriaExpanded: shouldSetAriaExpanded,
1281
+ isShowingContent: show,
1282
+ defaultIsShowingContent: defaultShow,
1283
+ shouldCloseOnDocumentClick: true,
1284
+ onHideContent: (event, {
1285
+ documentClick
1286
+ }) => {
1287
+ if (typeof onDismiss === 'function') {
1288
+ onDismiss(event, documentClick);
1289
+ }
1290
+ this.reset();
1291
+ this.handleToggle(event, false);
1292
+ },
1293
+ onShowContent: event => this.handleToggle(event, true),
1294
+ mountNode: mountNode || this.ref,
1295
+ placement: placement,
1296
+ withArrow: withArrow,
1297
+ positionTarget: positionTarget,
1298
+ positionContainerDisplay: positionContainerDisplay,
1299
+ constrain: constrain,
1300
+ shouldContainFocus: shouldContainFocus,
1301
+ shouldReturnFocus: shouldReturnFocus,
1302
+ id: this._id,
1303
+ on: ['click'],
1304
+ onFocus: onFocus,
1305
+ onMouseOver: onMouseOver,
1306
+ offsetX: offsetX,
1307
+ offsetY: offsetY,
1308
+ defaultFocusElement: () => {
1309
+ var _this$getFirstOption2, _this$_popover2, _this$_popover2$_cont;
1310
+ if (!this.currentPage) return null;
1311
+ const actionLabel = callRenderProp(this.currentPage.renderActionLabel);
1312
+ // Use action ID if exists, otherwise first non-action option's ID
1313
+ const targetId = actionLabel ? this._headerActionId : (_this$getFirstOption2 = this.getFirstOption()) === null || _this$getFirstOption2 === void 0 ? void 0 : _this$getFirstOption2.props.id;
1314
+ if (!targetId) return null;
1315
+ return (_this$_popover2 = this._popover) === null || _this$_popover2 === void 0 ? void 0 : (_this$_popover2$_cont = _this$_popover2._contentElement) === null || _this$_popover2$_cont === void 0 ? void 0 : _this$_popover2$_cont.querySelector(`#${CSS.escape(targetId)}`);
1316
+ },
1317
+ elementRef: element => {
1318
+ // setting ref for "Popover" version, the popover root
1319
+ // (if there is no trigger, we set it in handleDrilldownRef)
1320
+ this.handleRef(element);
1321
+ },
1322
+ ref: el => {
1323
+ this._popover = el;
1324
+ if (typeof popoverRef === 'function') {
1325
+ popoverRef(el);
1326
+ }
1327
+ },
1328
+ renderTrigger: safeCloneElement(trigger, {
1329
+ ref: el => {
1330
+ this._trigger = el;
1331
+ },
1332
+ 'aria-haspopup': this.props.role,
1333
+ id: this._triggerId,
1334
+ disabled: !!(trigger.props.disabled || disabled),
1335
+ 'aria-disabled': trigger.props.disabled || disabled ? 'true' : void 0
1336
+ }),
1337
+ children: this.renderPage()
1338
+ }) : this.renderPage();
1339
+ }
1340
+ }, _Drilldown.displayName = "Drilldown", _Drilldown.componentId = 'Drilldown', _Drilldown.allowedProps = allowedProps, _Drilldown.defaultProps = {
1341
+ disabled: false,
1342
+ rotateFocus: true,
1343
+ as: 'ul',
1344
+ role: 'menu',
1345
+ overflowX: 'auto',
1346
+ overflowY: 'auto',
1347
+ placement: 'bottom center',
1348
+ defaultShow: false,
1349
+ shouldHideOnSelect: true,
1350
+ shouldContainFocus: false,
1351
+ shouldReturnFocus: true,
1352
+ withArrow: true,
1353
+ offsetX: 0,
1354
+ offsetY: 0,
1355
+ shouldSetAriaExpanded: true
1356
+ }, _Drilldown.Group = DrilldownGroup, _Drilldown.Option = DrilldownOption, _Drilldown.Page = DrilldownPage, _Drilldown.Separator = DrilldownSeparator, _Drilldown)) || _class) || _class);
1357
+ export default Drilldown;
1358
+ export { Drilldown };