@instructure/ui-drilldown 11.7.2-snapshot-18 → 11.7.2-snapshot-19
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/CHANGELOG.md +12 -2
- package/es/Drilldown/v2/DrilldownGroup/index.js +55 -0
- package/es/Drilldown/v2/DrilldownGroup/props.js +26 -0
- package/es/Drilldown/v2/DrilldownOption/index.js +54 -0
- package/es/Drilldown/v2/DrilldownOption/props.js +26 -0
- package/es/Drilldown/v2/DrilldownPage/index.js +50 -0
- package/es/Drilldown/v2/DrilldownPage/props.js +26 -0
- package/es/Drilldown/v2/DrilldownSeparator/index.js +47 -0
- package/es/Drilldown/v2/DrilldownSeparator/props.js +26 -0
- package/es/Drilldown/v2/index.js +1358 -0
- package/es/Drilldown/v2/props.js +28 -0
- package/es/Drilldown/v2/styles.js +84 -0
- package/es/exports/b.js +28 -0
- package/lib/Drilldown/v2/DrilldownGroup/index.js +58 -0
- package/lib/Drilldown/v2/DrilldownGroup/props.js +31 -0
- package/lib/Drilldown/v2/DrilldownOption/index.js +58 -0
- package/lib/Drilldown/v2/DrilldownOption/props.js +31 -0
- package/lib/Drilldown/v2/DrilldownPage/index.js +56 -0
- package/lib/Drilldown/v2/DrilldownPage/props.js +31 -0
- package/lib/Drilldown/v2/DrilldownSeparator/index.js +51 -0
- package/lib/Drilldown/v2/DrilldownSeparator/props.js +31 -0
- package/lib/Drilldown/v2/index.js +1369 -0
- package/lib/Drilldown/v2/props.js +33 -0
- package/lib/Drilldown/v2/styles.js +90 -0
- package/lib/exports/b.js +40 -0
- package/package.json +28 -28
- package/src/Drilldown/v2/DrilldownGroup/index.tsx +64 -0
- package/src/Drilldown/v2/DrilldownGroup/props.ts +134 -0
- package/src/Drilldown/v2/DrilldownOption/index.tsx +65 -0
- package/src/Drilldown/v2/DrilldownOption/props.ts +211 -0
- package/src/Drilldown/v2/DrilldownPage/index.tsx +55 -0
- package/src/Drilldown/v2/DrilldownPage/props.ts +102 -0
- package/src/Drilldown/v2/DrilldownSeparator/index.tsx +57 -0
- package/src/Drilldown/v2/DrilldownSeparator/props.ts +56 -0
- package/src/Drilldown/v2/README.md +1445 -0
- package/src/Drilldown/v2/index.tsx +1681 -0
- package/src/Drilldown/v2/props.ts +361 -0
- package/src/Drilldown/v2/styles.ts +97 -0
- package/src/exports/b.ts +44 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/Drilldown/v2/DrilldownGroup/index.d.ts +41 -0
- package/types/Drilldown/v2/DrilldownGroup/index.d.ts.map +1 -0
- package/types/Drilldown/v2/DrilldownGroup/props.d.ts +69 -0
- package/types/Drilldown/v2/DrilldownGroup/props.d.ts.map +1 -0
- package/types/Drilldown/v2/DrilldownOption/index.d.ts +69 -0
- package/types/Drilldown/v2/DrilldownOption/index.d.ts.map +1 -0
- package/types/Drilldown/v2/DrilldownOption/props.d.ts +125 -0
- package/types/Drilldown/v2/DrilldownOption/props.d.ts.map +1 -0
- package/types/Drilldown/v2/DrilldownPage/index.d.ts +32 -0
- package/types/Drilldown/v2/DrilldownPage/index.d.ts.map +1 -0
- package/types/Drilldown/v2/DrilldownPage/props.d.ts +51 -0
- package/types/Drilldown/v2/DrilldownPage/props.d.ts.map +1 -0
- package/types/Drilldown/v2/DrilldownSeparator/index.d.ts +22 -0
- package/types/Drilldown/v2/DrilldownSeparator/index.d.ts.map +1 -0
- package/types/Drilldown/v2/DrilldownSeparator/props.d.ts +17 -0
- package/types/Drilldown/v2/DrilldownSeparator/props.d.ts.map +1 -0
- package/types/Drilldown/v2/index.d.ts +212 -0
- package/types/Drilldown/v2/index.d.ts.map +1 -0
- package/types/Drilldown/v2/props.d.ts +210 -0
- package/types/Drilldown/v2/props.d.ts.map +1 -0
- package/types/Drilldown/v2/styles.d.ts +15 -0
- package/types/Drilldown/v2/styles.d.ts.map +1 -0
- package/types/exports/b.d.ts +11 -0
- 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 };
|