@cloudscape-design/components-themeable 3.0.1106 → 3.0.1108
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/lib/internal/manifest.json +1 -1
- package/lib/internal/scss/internal/components/expand-toggle-button/styles.scss +6 -2
- package/lib/internal/scss/internal/generated/custom-css-properties/index.scss +1 -1
- package/lib/internal/scss/internal/styles/utils/styles-reset.scss +1 -0
- package/lib/internal/scss/tree-view/tree-item/styles.scss +38 -21
- package/lib/internal/template/internal/base-component/styles.scoped.css +1 -1
- package/lib/internal/template/internal/components/expand-toggle-button/index.d.ts +3 -1
- package/lib/internal/template/internal/components/expand-toggle-button/index.d.ts.map +1 -1
- package/lib/internal/template/internal/components/expand-toggle-button/index.js +2 -2
- package/lib/internal/template/internal/components/expand-toggle-button/index.js.map +1 -1
- package/lib/internal/template/internal/components/expand-toggle-button/styles.css.js +4 -3
- package/lib/internal/template/internal/components/expand-toggle-button/styles.scoped.css +13 -13
- package/lib/internal/template/internal/components/expand-toggle-button/styles.selectors.js +4 -3
- package/lib/internal/template/internal/components/structured-item/index.d.ts +3 -1
- package/lib/internal/template/internal/components/structured-item/index.d.ts.map +1 -1
- package/lib/internal/template/internal/components/structured-item/index.js +2 -2
- package/lib/internal/template/internal/components/structured-item/index.js.map +1 -1
- package/lib/internal/template/internal/environment.js +2 -2
- package/lib/internal/template/internal/environment.json +2 -2
- package/lib/internal/template/tree-view/internal.d.ts.map +1 -1
- package/lib/internal/template/tree-view/internal.js +10 -4
- package/lib/internal/template/tree-view/internal.js.map +1 -1
- package/lib/internal/template/tree-view/keyboard-navigation/index.d.ts +31 -0
- package/lib/internal/template/tree-view/keyboard-navigation/index.d.ts.map +1 -0
- package/lib/internal/template/tree-view/keyboard-navigation/index.js +224 -0
- package/lib/internal/template/tree-view/keyboard-navigation/index.js.map +1 -0
- package/lib/internal/template/tree-view/keyboard-navigation/utils.d.ts +7 -0
- package/lib/internal/template/tree-view/keyboard-navigation/utils.d.ts.map +1 -0
- package/lib/internal/template/tree-view/keyboard-navigation/utils.js +40 -0
- package/lib/internal/template/tree-view/keyboard-navigation/utils.js.map +1 -0
- package/lib/internal/template/tree-view/styles.css.js +2 -2
- package/lib/internal/template/tree-view/styles.scoped.css +3 -2
- package/lib/internal/template/tree-view/styles.selectors.js +2 -2
- package/lib/internal/template/tree-view/tree-item/focus-target.d.ts +5 -0
- package/lib/internal/template/tree-view/tree-item/focus-target.d.ts.map +1 -0
- package/lib/internal/template/tree-view/tree-item/focus-target.js +11 -0
- package/lib/internal/template/tree-view/tree-item/focus-target.js.map +1 -0
- package/lib/internal/template/tree-view/tree-item/index.d.ts +4 -1
- package/lib/internal/template/tree-view/tree-item/index.d.ts.map +1 -1
- package/lib/internal/template/tree-view/tree-item/index.js +11 -9
- package/lib/internal/template/tree-view/tree-item/index.js.map +1 -1
- package/lib/internal/template/tree-view/tree-item/styles.css.js +9 -5
- package/lib/internal/template/tree-view/tree-item/styles.scoped.css +46 -11
- package/lib/internal/template/tree-view/tree-item/styles.selectors.js +9 -5
- package/lib/internal/template/tree-view/utils.d.ts +11 -0
- package/lib/internal/template/tree-view/utils.d.ts.map +1 -0
- package/lib/internal/template/tree-view/utils.js +20 -0
- package/lib/internal/template/tree-view/utils.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import React, { useRef } from 'react';
|
|
4
|
+
import { useEffect, useMemo } from 'react';
|
|
5
|
+
import { useStableCallback } from '@cloudscape-design/component-toolkit/internal';
|
|
6
|
+
import { SingleTabStopNavigationProvider, } from '@cloudscape-design/component-toolkit/internal';
|
|
7
|
+
import { getAllFocusables } from '../../internal/components/focus-lock/utils';
|
|
8
|
+
import { KeyCode } from '../../internal/keycode';
|
|
9
|
+
import handleKey, { isEventLike } from '../../internal/utils/handle-key';
|
|
10
|
+
import { nodeBelongs } from '../../internal/utils/node-belongs';
|
|
11
|
+
import { findTreeItemByIndex, findTreeItemContentById, getClosestTreeItem, getToggleButtonOfTreeItem, isElementDisabled, isTreeItemToggle, } from './utils';
|
|
12
|
+
import treeItemStyles from '../tree-item/styles.css.js';
|
|
13
|
+
export function KeyboardNavigationProvider({ getTreeView, children, }) {
|
|
14
|
+
const navigationAPI = useRef(null);
|
|
15
|
+
const keyboardNavigation = useMemo(() => new KeyboardNavigationProcessor(navigationAPI), []);
|
|
16
|
+
const getTreeViewStable = useStableCallback(getTreeView);
|
|
17
|
+
// Initialize the processor with the treeView container assuming it is mounted synchronously and only once.
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const treeView = getTreeViewStable();
|
|
20
|
+
if (treeView) {
|
|
21
|
+
keyboardNavigation.init(treeView);
|
|
22
|
+
return keyboardNavigation.cleanup;
|
|
23
|
+
}
|
|
24
|
+
}, [keyboardNavigation, getTreeViewStable]);
|
|
25
|
+
// Notify the processor of the new render.
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
keyboardNavigation.refresh();
|
|
28
|
+
});
|
|
29
|
+
return (React.createElement(SingleTabStopNavigationProvider, { ref: navigationAPI, getNextFocusTarget: keyboardNavigation.getNextFocusTarget, onUnregisterActive: keyboardNavigation.onUnregisterActive, navigationActive: true }, children));
|
|
30
|
+
}
|
|
31
|
+
export class KeyboardNavigationProcessor {
|
|
32
|
+
constructor(navigationAPI) {
|
|
33
|
+
// Props
|
|
34
|
+
this._treeView = null;
|
|
35
|
+
// State
|
|
36
|
+
this.focusedTreeItem = null;
|
|
37
|
+
this.cleanup = () => {
|
|
38
|
+
// Do nothing before initialized.
|
|
39
|
+
};
|
|
40
|
+
this.onUnregisterActive = () => {
|
|
41
|
+
// If the focused tree-item or tree-item focusable appears to be no longer attached to the tree-view we need to re-apply
|
|
42
|
+
// focus to a tree-item focusable with the same position or to the tree-item toggle.
|
|
43
|
+
// istanbul ignore next - tested via integration tests
|
|
44
|
+
if (this.treeView && this.focusedTreeItem && !nodeBelongs(this.treeView, this.focusedTreeItem.element)) {
|
|
45
|
+
const nextFocusableElement = this.getNextFocusableTreeItemContent(this.treeView, this.focusedTreeItem, 0);
|
|
46
|
+
if (nextFocusableElement) {
|
|
47
|
+
nextFocusableElement === null || nextFocusableElement === void 0 ? void 0 : nextFocusableElement.focus();
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
this.moveFocusBetweenTreeItems(this.treeView, this.focusedTreeItem, 0);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
this.getNextFocusTarget = () => {
|
|
55
|
+
if (!this.treeView) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const treeItem = this.focusedTreeItem;
|
|
59
|
+
const firstTreeItemToggle = this.treeView.querySelector(`.${treeItemStyles['tree-item-focus-target']}`);
|
|
60
|
+
let focusTarget = firstTreeItemToggle;
|
|
61
|
+
// Focus on the element that was focused before.
|
|
62
|
+
if (treeItem) {
|
|
63
|
+
focusTarget = this.getNextFocusableTreeItem(this.treeView, treeItem, 0);
|
|
64
|
+
}
|
|
65
|
+
return focusTarget;
|
|
66
|
+
};
|
|
67
|
+
this.onFocusin = (treeView, event) => {
|
|
68
|
+
var _a;
|
|
69
|
+
if (!(event.target instanceof HTMLElement)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
this.updateFocusedTreeItem(treeView, event.target);
|
|
73
|
+
if (!this.focusedTreeItem) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
(_a = this._navigationAPI.current) === null || _a === void 0 ? void 0 : _a.updateFocusTarget();
|
|
77
|
+
};
|
|
78
|
+
this.onKeydown = (treeView, event) => {
|
|
79
|
+
const keys = [
|
|
80
|
+
KeyCode.up,
|
|
81
|
+
KeyCode.down,
|
|
82
|
+
KeyCode.left,
|
|
83
|
+
KeyCode.right,
|
|
84
|
+
KeyCode.pageUp,
|
|
85
|
+
KeyCode.pageDown,
|
|
86
|
+
KeyCode.home,
|
|
87
|
+
KeyCode.end,
|
|
88
|
+
];
|
|
89
|
+
if (!this.focusedTreeItem || !this.isRegistered(document.activeElement) || keys.indexOf(event.keyCode) === -1) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const from = this.focusedTreeItem;
|
|
93
|
+
if (isEventLike(event)) {
|
|
94
|
+
handleKey(event, {
|
|
95
|
+
onBlockStart: () => this.moveFocusBetweenTreeItems(treeView, from, -1, event),
|
|
96
|
+
onBlockEnd: () => this.moveFocusBetweenTreeItems(treeView, from, 1, event),
|
|
97
|
+
onInlineEnd: () => {
|
|
98
|
+
// If focus is on the toggle, move focus to the first element inside the tree-item
|
|
99
|
+
if (isTreeItemToggle(from.element)) {
|
|
100
|
+
return this.moveFocusInsideTreeItem(treeView, from, 0, event);
|
|
101
|
+
}
|
|
102
|
+
return this.moveFocusInsideTreeItem(treeView, from, 1, event);
|
|
103
|
+
},
|
|
104
|
+
onInlineStart: () => {
|
|
105
|
+
// If focus is on the toggle, move focus to the last element inside the tree-item
|
|
106
|
+
if (isTreeItemToggle(from.element)) {
|
|
107
|
+
return this.moveFocusToTheLastElementInsideTreeItem(treeView, from, event);
|
|
108
|
+
}
|
|
109
|
+
return this.moveFocusInsideTreeItem(treeView, from, -1, event);
|
|
110
|
+
},
|
|
111
|
+
onPageUp: () => this.moveFocusBetweenTreeItems(treeView, from, -10, event),
|
|
112
|
+
onPageDown: () => this.moveFocusBetweenTreeItems(treeView, from, 10, event),
|
|
113
|
+
onHome: () => this.moveFocusBetweenTreeItems(treeView, from, -Infinity, event),
|
|
114
|
+
onEnd: () => this.moveFocusBetweenTreeItems(treeView, from, Infinity, event),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
this._navigationAPI = navigationAPI;
|
|
119
|
+
}
|
|
120
|
+
init(treeView) {
|
|
121
|
+
this._treeView = treeView;
|
|
122
|
+
const controller = new AbortController();
|
|
123
|
+
treeView.addEventListener('focusin', event => this.onFocusin(treeView, event), { signal: controller.signal });
|
|
124
|
+
treeView.addEventListener('keydown', event => this.onKeydown(treeView, event), { signal: controller.signal });
|
|
125
|
+
this.cleanup = () => {
|
|
126
|
+
controller.abort();
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
refresh() {
|
|
130
|
+
// Timeout ensures the newly rendered content elements are registered.
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
var _a, _b;
|
|
133
|
+
if (this.treeView) {
|
|
134
|
+
// Update focused tree-item in case tree-items change.
|
|
135
|
+
this.updateFocusedTreeItem(this.treeView, (_a = this.focusedTreeItem) === null || _a === void 0 ? void 0 : _a.element);
|
|
136
|
+
(_b = this._navigationAPI.current) === null || _b === void 0 ? void 0 : _b.updateFocusTarget();
|
|
137
|
+
}
|
|
138
|
+
}, 0);
|
|
139
|
+
}
|
|
140
|
+
get treeView() {
|
|
141
|
+
return this._treeView;
|
|
142
|
+
}
|
|
143
|
+
getFocusablesFrom(target) {
|
|
144
|
+
const isElementRegistered = (element) => { var _a; return (_a = this._navigationAPI.current) === null || _a === void 0 ? void 0 : _a.isRegistered(element); };
|
|
145
|
+
return getAllFocusables(target).filter(el => isElementRegistered(el) && !isElementDisabled(el));
|
|
146
|
+
}
|
|
147
|
+
isRegistered(element) {
|
|
148
|
+
var _a, _b;
|
|
149
|
+
return !element || ((_b = (_a = this._navigationAPI.current) === null || _a === void 0 ? void 0 : _a.isRegistered(element)) !== null && _b !== void 0 ? _b : false);
|
|
150
|
+
}
|
|
151
|
+
updateFocusedTreeItem(treeView, focusedElement) {
|
|
152
|
+
var _a;
|
|
153
|
+
if (!focusedElement) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const treeItem = getClosestTreeItem(focusedElement);
|
|
157
|
+
if (!treeItem) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const treeItemContent = findTreeItemContentById(treeView, treeItem.id);
|
|
161
|
+
this.focusedTreeItem = {
|
|
162
|
+
treeItemId: treeItem.id,
|
|
163
|
+
treeItemIndex: parseInt((_a = treeItem.getAttribute('data-awsui-tree-item-index')) !== null && _a !== void 0 ? _a : ''),
|
|
164
|
+
element: focusedElement,
|
|
165
|
+
elementIndex: treeItemContent ? this.getFocusablesFrom(treeItemContent).indexOf(focusedElement) : 0,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
getNextFocusableTreeItem(treeView, from, by) {
|
|
169
|
+
const targetTreeItemIndex = from.treeItemIndex + by;
|
|
170
|
+
const targetTreeItem = findTreeItemByIndex(treeView, targetTreeItemIndex, by);
|
|
171
|
+
// Return the toggle of the tree-item
|
|
172
|
+
return getToggleButtonOfTreeItem(targetTreeItem);
|
|
173
|
+
}
|
|
174
|
+
moveFocusInsideTreeItem(treeView, from, by, event) {
|
|
175
|
+
const nextFocusableElement = this.getNextFocusableTreeItemContent(treeView, from, by);
|
|
176
|
+
if (nextFocusableElement) {
|
|
177
|
+
// Prevent default only if there are focusables inside
|
|
178
|
+
event === null || event === void 0 ? void 0 : event.preventDefault();
|
|
179
|
+
nextFocusableElement === null || nextFocusableElement === void 0 ? void 0 : nextFocusableElement.focus();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
moveFocusBetweenTreeItems(treeView, from, by, event) {
|
|
183
|
+
event === null || event === void 0 ? void 0 : event.preventDefault();
|
|
184
|
+
const isToggleFocused = isTreeItemToggle(from.element);
|
|
185
|
+
// If toggle is not focused (focus is inside the tree-item),
|
|
186
|
+
// pressing up or down arrow keys should move focus to the toggle
|
|
187
|
+
const nextFocusableTreeItem = this.getNextFocusableTreeItem(treeView, from, isToggleFocused ? by : 0);
|
|
188
|
+
nextFocusableTreeItem === null || nextFocusableTreeItem === void 0 ? void 0 : nextFocusableTreeItem.focus();
|
|
189
|
+
}
|
|
190
|
+
moveFocusToTheLastElementInsideTreeItem(treeView, from, event) {
|
|
191
|
+
const treeItem = findTreeItemContentById(treeView, from.treeItemId);
|
|
192
|
+
if (!treeItem) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
const treeItemFocusables = this.getFocusablesFrom(treeItem);
|
|
196
|
+
const focusableElement = treeItemFocusables[treeItemFocusables.length - 1];
|
|
197
|
+
if (focusableElement) {
|
|
198
|
+
// Prevent default only if there are focusables inside
|
|
199
|
+
event === null || event === void 0 ? void 0 : event.preventDefault();
|
|
200
|
+
focusableElement === null || focusableElement === void 0 ? void 0 : focusableElement.focus();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
getNextFocusableTreeItemContent(treeView, from, by) {
|
|
204
|
+
const treeItem = findTreeItemContentById(treeView, from.treeItemId);
|
|
205
|
+
if (!treeItem) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const treeItemFocusables = this.getFocusablesFrom(treeItem);
|
|
209
|
+
const targetElementIndex = isTreeItemToggle(from.element) ? by : from.elementIndex + by;
|
|
210
|
+
// Move focus to the tree-item toggle if
|
|
211
|
+
// left arrow key is pressed while focused on the first element inside the tree-item, or
|
|
212
|
+
// right arrow key is pressed while focused on the last element inside the tree-item
|
|
213
|
+
const isTargetToggle = (from.elementIndex === 0 && by < 0) || (targetElementIndex === treeItemFocusables.length && by > 0);
|
|
214
|
+
if (isTargetToggle) {
|
|
215
|
+
return this.getNextFocusableTreeItem(treeView, from, 0);
|
|
216
|
+
}
|
|
217
|
+
const isValidIndex = targetElementIndex < treeItemFocusables.length;
|
|
218
|
+
if (isValidIndex) {
|
|
219
|
+
return treeItemFocusables[targetElementIndex];
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/tree-view/keyboard-navigation/index.tsx"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AACtC,OAAO,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAClF,OAAO,EAEL,+BAA+B,GAChC,MAAM,+CAA+C,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,SAAS,EAAE,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,EAClB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,cAAc,MAAM,4BAA4B,CAAC;AAExD,MAAM,UAAU,0BAA0B,CAAC,EACzC,WAAW,EACX,QAAQ,GAIT;IACC,MAAM,aAAa,GAAG,MAAM,CAA6B,IAAI,CAAC,CAAC;IAE/D,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,2BAA2B,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC;IAE7F,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAEzD,2GAA2G;IAC3G,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAC;QACrC,IAAI,QAAQ,EAAE;YACZ,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAClC,OAAO,kBAAkB,CAAC,OAAO,CAAC;SACnC;IACH,CAAC,EAAE,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAE5C,0CAA0C;IAC1C,SAAS,CAAC,GAAG,EAAE;QACb,kBAAkB,CAAC,OAAO,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,OAAO,CACL,oBAAC,+BAA+B,IAC9B,GAAG,EAAE,aAAa,EAClB,kBAAkB,EAAE,kBAAkB,CAAC,kBAAkB,EACzD,kBAAkB,EAAE,kBAAkB,CAAC,kBAAkB,EACzD,gBAAgB,EAAE,IAAI,IAErB,QAAQ,CACuB,CACnC,CAAC;AACJ,CAAC;AASD,MAAM,OAAO,2BAA2B;IAQtC,YAAY,aAA6D;QAPzE,QAAQ;QACA,cAAS,GAA4B,IAAI,CAAC;QAGlD,QAAQ;QACA,oBAAe,GAA2B,IAAI,CAAC;QAkBhD,YAAO,GAAG,GAAG,EAAE;YACpB,iCAAiC;QACnC,CAAC,CAAC;QAaK,uBAAkB,GAAG,GAAG,EAAE;YAC/B,wHAAwH;YACxH,oFAAoF;YACpF,sDAAsD;YACtD,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,eAAe,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE;gBACtG,MAAM,oBAAoB,GAAG,IAAI,CAAC,+BAA+B,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;gBAC1G,IAAI,oBAAoB,EAAE;oBACxB,oBAAoB,aAApB,oBAAoB,uBAApB,oBAAoB,CAAE,KAAK,EAAE,CAAC;iBAC/B;qBAAM;oBACL,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;iBACxE;aACF;QACH,CAAC,CAAC;QAEK,uBAAkB,GAAG,GAAG,EAAE;YAC/B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;gBAClB,OAAO,IAAI,CAAC;aACb;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC;YACtC,MAAM,mBAAmB,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CACrD,IAAI,cAAc,CAAC,wBAAwB,CAAC,EAAE,CACnB,CAAC;YAE9B,IAAI,WAAW,GAAuB,mBAAmB,CAAC;YAE1D,gDAAgD;YAChD,IAAI,QAAQ,EAAE;gBACZ,WAAW,GAAG,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;aACzE;YAED,OAAO,WAAW,CAAC;QACrB,CAAC,CAAC;QAmCM,cAAS,GAAG,CAAC,QAA0B,EAAE,KAAiB,EAAE,EAAE;;YACpE,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,YAAY,WAAW,CAAC,EAAE;gBAC1C,OAAO;aACR;YAED,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YACnD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;gBACzB,OAAO;aACR;YAED,MAAA,IAAI,CAAC,cAAc,CAAC,OAAO,0CAAE,iBAAiB,EAAE,CAAC;QACnD,CAAC,CAAC;QAEM,cAAS,GAAG,CAAC,QAA0B,EAAE,KAAoB,EAAE,EAAE;YACvE,MAAM,IAAI,GAAG;gBACX,OAAO,CAAC,EAAE;gBACV,OAAO,CAAC,IAAI;gBACZ,OAAO,CAAC,IAAI;gBACZ,OAAO,CAAC,KAAK;gBACb,OAAO,CAAC,MAAM;gBACd,OAAO,CAAC,QAAQ;gBAChB,OAAO,CAAC,IAAI;gBACZ,OAAO,CAAC,GAAG;aACZ,CAAC;YAEF,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE;gBAC7G,OAAO;aACR;YAED,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC;YAElC,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE;gBACtB,SAAS,CAAC,KAAK,EAAE;oBACf,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC;oBAC7E,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC;oBAC1E,WAAW,EAAE,GAAG,EAAE;wBAChB,kFAAkF;wBAClF,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;4BAClC,OAAO,IAAI,CAAC,uBAAuB,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;yBAC/D;wBACD,OAAO,IAAI,CAAC,uBAAuB,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;oBAChE,CAAC;oBACD,aAAa,EAAE,GAAG,EAAE;wBAClB,iFAAiF;wBACjF,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;4BAClC,OAAO,IAAI,CAAC,uCAAuC,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;yBAC5E;wBACD,OAAO,IAAI,CAAC,uBAAuB,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;oBACjE,CAAC;oBACD,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC;oBAC1E,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC;oBAC3E,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;oBAC9E,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC;iBAC7E,CAAC,CAAC;aACJ;QACH,CAAC,CAAC;QAxJA,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;IACtC,CAAC;IAEM,IAAI,CAAC,QAA0B;QACpC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QAEzC,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9G,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAE9G,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE;YAClB,UAAU,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC,CAAC;IACJ,CAAC;IAMM,OAAO;QACZ,sEAAsE;QACtE,UAAU,CAAC,GAAG,EAAE;;YACd,IAAI,IAAI,CAAC,QAAQ,EAAE;gBACjB,sDAAsD;gBACtD,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAA,IAAI,CAAC,eAAe,0CAAE,OAAO,CAAC,CAAC;gBACzE,MAAA,IAAI,CAAC,cAAc,CAAC,OAAO,0CAAE,iBAAiB,EAAE,CAAC;aAClD;QACH,CAAC,EAAE,CAAC,CAAC,CAAC;IACR,CAAC;IAoCD,IAAY,QAAQ;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAEO,iBAAiB,CAAC,MAAmB;QAC3C,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,EAAE,WAAC,OAAA,MAAA,IAAI,CAAC,cAAc,CAAC,OAAO,0CAAE,YAAY,CAAC,OAAO,CAAC,CAAA,EAAA,CAAC;QACrG,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC;IAClG,CAAC;IAEO,YAAY,CAAC,OAAuB;;QAC1C,OAAO,CAAC,OAAO,IAAI,CAAC,MAAA,MAAA,IAAI,CAAC,cAAc,CAAC,OAAO,0CAAE,YAAY,CAAC,OAAO,CAAC,mCAAI,KAAK,CAAC,CAAC;IACnF,CAAC;IAEO,qBAAqB,CAAC,QAA0B,EAAE,cAA4B;;QACpF,IAAI,CAAC,cAAc,EAAE;YACnB,OAAO;SACR;QAED,MAAM,QAAQ,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,EAAE;YACb,OAAO;SACR;QAED,MAAM,eAAe,GAAG,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEvE,IAAI,CAAC,eAAe,GAAG;YACrB,UAAU,EAAE,QAAQ,CAAC,EAAE;YACvB,aAAa,EAAE,QAAQ,CAAC,MAAA,QAAQ,CAAC,YAAY,CAAC,4BAA4B,CAAC,mCAAI,EAAE,CAAC;YAClF,OAAO,EAAE,cAAc;YACvB,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;SACpG,CAAC;IACJ,CAAC;IA2DO,wBAAwB,CAAC,QAA0B,EAAE,IAAqB,EAAE,EAAU;QAC5F,MAAM,mBAAmB,GAAG,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACpD,MAAM,cAAc,GAAG,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAC;QAE9E,qCAAqC;QACrC,OAAO,yBAAyB,CAAC,cAAc,CAAC,CAAC;IACnD,CAAC;IAEO,uBAAuB,CAAC,QAA0B,EAAE,IAAqB,EAAE,EAAU,EAAE,KAAa;QAC1G,MAAM,oBAAoB,GAAG,IAAI,CAAC,+BAA+B,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAEtF,IAAI,oBAAoB,EAAE;YACxB,sDAAsD;YACtD,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,cAAc,EAAE,CAAC;YACxB,oBAAoB,aAApB,oBAAoB,uBAApB,oBAAoB,CAAE,KAAK,EAAE,CAAC;SAC/B;IACH,CAAC;IAEO,yBAAyB,CAAC,QAA0B,EAAE,IAAqB,EAAE,EAAU,EAAE,KAAa;QAC5G,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,cAAc,EAAE,CAAC;QACxB,MAAM,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEvD,4DAA4D;QAC5D,iEAAiE;QACjE,MAAM,qBAAqB,GAAG,IAAI,CAAC,wBAAwB,CAAC,QAAQ,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtG,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,KAAK,EAAE,CAAC;IACjC,CAAC;IAEO,uCAAuC,CAAC,QAA0B,EAAE,IAAqB,EAAE,KAAa;QAC9G,MAAM,QAAQ,GAAG,uBAAuB,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACpE,IAAI,CAAC,QAAQ,EAAE;YACb,OAAO,IAAI,CAAC;SACb;QAED,MAAM,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAE5D,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE3E,IAAI,gBAAgB,EAAE;YACpB,sDAAsD;YACtD,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,cAAc,EAAE,CAAC;YACxB,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,KAAK,EAAE,CAAC;SAC3B;IACH,CAAC;IAEO,+BAA+B,CAAC,QAA0B,EAAE,IAAqB,EAAE,EAAU;QACnG,MAAM,QAAQ,GAAG,uBAAuB,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACpE,IAAI,CAAC,QAAQ,EAAE;YACb,OAAO,IAAI,CAAC;SACb;QAED,MAAM,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAE5D,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QAExF,wCAAwC;QACxC,wFAAwF;QACxF,oFAAoF;QACpF,MAAM,cAAc,GAClB,CAAC,IAAI,CAAC,YAAY,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,kBAAkB,KAAK,kBAAkB,CAAC,MAAM,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QACtG,IAAI,cAAc,EAAE;YAClB,OAAO,IAAI,CAAC,wBAAwB,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;SACzD;QAED,MAAM,YAAY,GAAG,kBAAkB,GAAG,kBAAkB,CAAC,MAAM,CAAC;QACpE,IAAI,YAAY,EAAE;YAChB,OAAO,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;SAC/C;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport React, { useRef } from 'react';\nimport { useEffect, useMemo } from 'react';\n\nimport { useStableCallback } from '@cloudscape-design/component-toolkit/internal';\nimport {\n SingleTabStopNavigationAPI,\n SingleTabStopNavigationProvider,\n} from '@cloudscape-design/component-toolkit/internal';\n\nimport { getAllFocusables } from '../../internal/components/focus-lock/utils';\nimport { KeyCode } from '../../internal/keycode';\nimport handleKey, { isEventLike } from '../../internal/utils/handle-key';\nimport { nodeBelongs } from '../../internal/utils/node-belongs';\nimport {\n findTreeItemByIndex,\n findTreeItemContentById,\n getClosestTreeItem,\n getToggleButtonOfTreeItem,\n isElementDisabled,\n isTreeItemToggle,\n} from './utils';\n\nimport treeItemStyles from '../tree-item/styles.css.js';\n\nexport function KeyboardNavigationProvider({\n getTreeView,\n children,\n}: {\n getTreeView: () => null | HTMLUListElement;\n children: React.ReactNode;\n}) {\n const navigationAPI = useRef<SingleTabStopNavigationAPI>(null);\n\n const keyboardNavigation = useMemo(() => new KeyboardNavigationProcessor(navigationAPI), []);\n\n const getTreeViewStable = useStableCallback(getTreeView);\n\n // Initialize the processor with the treeView container assuming it is mounted synchronously and only once.\n useEffect(() => {\n const treeView = getTreeViewStable();\n if (treeView) {\n keyboardNavigation.init(treeView);\n return keyboardNavigation.cleanup;\n }\n }, [keyboardNavigation, getTreeViewStable]);\n\n // Notify the processor of the new render.\n useEffect(() => {\n keyboardNavigation.refresh();\n });\n\n return (\n <SingleTabStopNavigationProvider\n ref={navigationAPI}\n getNextFocusTarget={keyboardNavigation.getNextFocusTarget}\n onUnregisterActive={keyboardNavigation.onUnregisterActive}\n navigationActive={true}\n >\n {children}\n </SingleTabStopNavigationProvider>\n );\n}\n\ninterface FocusedTreeItem {\n treeItemId: string;\n treeItemIndex: number;\n element: HTMLElement;\n elementIndex: number;\n}\n\nexport class KeyboardNavigationProcessor {\n // Props\n private _treeView: null | HTMLUListElement = null;\n private _navigationAPI: { current: null | SingleTabStopNavigationAPI };\n\n // State\n private focusedTreeItem: null | FocusedTreeItem = null;\n\n constructor(navigationAPI: { current: null | SingleTabStopNavigationAPI }) {\n this._navigationAPI = navigationAPI;\n }\n\n public init(treeView: HTMLUListElement) {\n this._treeView = treeView;\n const controller = new AbortController();\n\n treeView.addEventListener('focusin', event => this.onFocusin(treeView, event), { signal: controller.signal });\n treeView.addEventListener('keydown', event => this.onKeydown(treeView, event), { signal: controller.signal });\n\n this.cleanup = () => {\n controller.abort();\n };\n }\n\n public cleanup = () => {\n // Do nothing before initialized.\n };\n\n public refresh() {\n // Timeout ensures the newly rendered content elements are registered.\n setTimeout(() => {\n if (this.treeView) {\n // Update focused tree-item in case tree-items change.\n this.updateFocusedTreeItem(this.treeView, this.focusedTreeItem?.element);\n this._navigationAPI.current?.updateFocusTarget();\n }\n }, 0);\n }\n\n public onUnregisterActive = () => {\n // If the focused tree-item or tree-item focusable appears to be no longer attached to the tree-view we need to re-apply\n // focus to a tree-item focusable with the same position or to the tree-item toggle.\n // istanbul ignore next - tested via integration tests\n if (this.treeView && this.focusedTreeItem && !nodeBelongs(this.treeView, this.focusedTreeItem.element)) {\n const nextFocusableElement = this.getNextFocusableTreeItemContent(this.treeView, this.focusedTreeItem, 0);\n if (nextFocusableElement) {\n nextFocusableElement?.focus();\n } else {\n this.moveFocusBetweenTreeItems(this.treeView, this.focusedTreeItem, 0);\n }\n }\n };\n\n public getNextFocusTarget = () => {\n if (!this.treeView) {\n return null;\n }\n\n const treeItem = this.focusedTreeItem;\n const firstTreeItemToggle = this.treeView.querySelector(\n `.${treeItemStyles['tree-item-focus-target']}`\n ) as null | HTMLButtonElement;\n\n let focusTarget: null | HTMLElement = firstTreeItemToggle;\n\n // Focus on the element that was focused before.\n if (treeItem) {\n focusTarget = this.getNextFocusableTreeItem(this.treeView, treeItem, 0);\n }\n\n return focusTarget;\n };\n\n private get treeView(): null | HTMLUListElement {\n return this._treeView;\n }\n\n private getFocusablesFrom(target: HTMLElement) {\n const isElementRegistered = (element: Element) => this._navigationAPI.current?.isRegistered(element);\n return getAllFocusables(target).filter(el => isElementRegistered(el) && !isElementDisabled(el));\n }\n\n private isRegistered(element: null | Element): boolean {\n return !element || (this._navigationAPI.current?.isRegistered(element) ?? false);\n }\n\n private updateFocusedTreeItem(treeView: HTMLUListElement, focusedElement?: HTMLElement): void {\n if (!focusedElement) {\n return;\n }\n\n const treeItem = getClosestTreeItem(focusedElement);\n if (!treeItem) {\n return;\n }\n\n const treeItemContent = findTreeItemContentById(treeView, treeItem.id);\n\n this.focusedTreeItem = {\n treeItemId: treeItem.id,\n treeItemIndex: parseInt(treeItem.getAttribute('data-awsui-tree-item-index') ?? ''),\n element: focusedElement,\n elementIndex: treeItemContent ? this.getFocusablesFrom(treeItemContent).indexOf(focusedElement) : 0,\n };\n }\n\n private onFocusin = (treeView: HTMLUListElement, event: FocusEvent) => {\n if (!(event.target instanceof HTMLElement)) {\n return;\n }\n\n this.updateFocusedTreeItem(treeView, event.target);\n if (!this.focusedTreeItem) {\n return;\n }\n\n this._navigationAPI.current?.updateFocusTarget();\n };\n\n private onKeydown = (treeView: HTMLUListElement, event: KeyboardEvent) => {\n const keys = [\n KeyCode.up,\n KeyCode.down,\n KeyCode.left,\n KeyCode.right,\n KeyCode.pageUp,\n KeyCode.pageDown,\n KeyCode.home,\n KeyCode.end,\n ];\n\n if (!this.focusedTreeItem || !this.isRegistered(document.activeElement) || keys.indexOf(event.keyCode) === -1) {\n return;\n }\n\n const from = this.focusedTreeItem;\n\n if (isEventLike(event)) {\n handleKey(event, {\n onBlockStart: () => this.moveFocusBetweenTreeItems(treeView, from, -1, event),\n onBlockEnd: () => this.moveFocusBetweenTreeItems(treeView, from, 1, event),\n onInlineEnd: () => {\n // If focus is on the toggle, move focus to the first element inside the tree-item\n if (isTreeItemToggle(from.element)) {\n return this.moveFocusInsideTreeItem(treeView, from, 0, event);\n }\n return this.moveFocusInsideTreeItem(treeView, from, 1, event);\n },\n onInlineStart: () => {\n // If focus is on the toggle, move focus to the last element inside the tree-item\n if (isTreeItemToggle(from.element)) {\n return this.moveFocusToTheLastElementInsideTreeItem(treeView, from, event);\n }\n return this.moveFocusInsideTreeItem(treeView, from, -1, event);\n },\n onPageUp: () => this.moveFocusBetweenTreeItems(treeView, from, -10, event),\n onPageDown: () => this.moveFocusBetweenTreeItems(treeView, from, 10, event),\n onHome: () => this.moveFocusBetweenTreeItems(treeView, from, -Infinity, event),\n onEnd: () => this.moveFocusBetweenTreeItems(treeView, from, Infinity, event),\n });\n }\n };\n\n private getNextFocusableTreeItem(treeView: HTMLUListElement, from: FocusedTreeItem, by: number) {\n const targetTreeItemIndex = from.treeItemIndex + by;\n const targetTreeItem = findTreeItemByIndex(treeView, targetTreeItemIndex, by);\n\n // Return the toggle of the tree-item\n return getToggleButtonOfTreeItem(targetTreeItem);\n }\n\n private moveFocusInsideTreeItem(treeView: HTMLUListElement, from: FocusedTreeItem, by: number, event?: Event) {\n const nextFocusableElement = this.getNextFocusableTreeItemContent(treeView, from, by);\n\n if (nextFocusableElement) {\n // Prevent default only if there are focusables inside\n event?.preventDefault();\n nextFocusableElement?.focus();\n }\n }\n\n private moveFocusBetweenTreeItems(treeView: HTMLUListElement, from: FocusedTreeItem, by: number, event?: Event) {\n event?.preventDefault();\n const isToggleFocused = isTreeItemToggle(from.element);\n\n // If toggle is not focused (focus is inside the tree-item),\n // pressing up or down arrow keys should move focus to the toggle\n const nextFocusableTreeItem = this.getNextFocusableTreeItem(treeView, from, isToggleFocused ? by : 0);\n nextFocusableTreeItem?.focus();\n }\n\n private moveFocusToTheLastElementInsideTreeItem(treeView: HTMLUListElement, from: FocusedTreeItem, event?: Event) {\n const treeItem = findTreeItemContentById(treeView, from.treeItemId);\n if (!treeItem) {\n return null;\n }\n\n const treeItemFocusables = this.getFocusablesFrom(treeItem);\n\n const focusableElement = treeItemFocusables[treeItemFocusables.length - 1];\n\n if (focusableElement) {\n // Prevent default only if there are focusables inside\n event?.preventDefault();\n focusableElement?.focus();\n }\n }\n\n private getNextFocusableTreeItemContent(treeView: HTMLUListElement, from: FocusedTreeItem, by: number) {\n const treeItem = findTreeItemContentById(treeView, from.treeItemId);\n if (!treeItem) {\n return null;\n }\n\n const treeItemFocusables = this.getFocusablesFrom(treeItem);\n\n const targetElementIndex = isTreeItemToggle(from.element) ? by : from.elementIndex + by;\n\n // Move focus to the tree-item toggle if\n // left arrow key is pressed while focused on the first element inside the tree-item, or\n // right arrow key is pressed while focused on the last element inside the tree-item\n const isTargetToggle =\n (from.elementIndex === 0 && by < 0) || (targetElementIndex === treeItemFocusables.length && by > 0);\n if (isTargetToggle) {\n return this.getNextFocusableTreeItem(treeView, from, 0);\n }\n\n const isValidIndex = targetElementIndex < treeItemFocusables.length;\n if (isValidIndex) {\n return treeItemFocusables[targetElementIndex];\n }\n\n return null;\n }\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function getClosestTreeItem(element: Element): HTMLLIElement | null;
|
|
2
|
+
export declare function getToggleButtonOfTreeItem(treeItem: null | HTMLLIElement): HTMLElement | null;
|
|
3
|
+
export declare function isElementDisabled(element: HTMLElement): boolean;
|
|
4
|
+
export declare function findTreeItemByIndex(treeView: HTMLUListElement, targetTreeItemIndex: number, delta: number): HTMLLIElement | null;
|
|
5
|
+
export declare function findTreeItemContentById(treeView: HTMLUListElement, treeItemId: string): HTMLLIElement | null;
|
|
6
|
+
export declare function isTreeItemToggle(element: Element): boolean;
|
|
7
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/tree-view/keyboard-navigation/utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,wBAElD;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,IAAI,GAAG,aAAa,sBAGvE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,WAKrD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,wBAiBzG;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,wBAKrF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,WAEhD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import treeItemStyles from '../tree-item/styles.css.js';
|
|
4
|
+
export function getClosestTreeItem(element) {
|
|
5
|
+
return element.closest('li[data-awsui-tree-item-index]');
|
|
6
|
+
}
|
|
7
|
+
export function getToggleButtonOfTreeItem(treeItem) {
|
|
8
|
+
const toggleElement = treeItem === null || treeItem === void 0 ? void 0 : treeItem.querySelector(`.${treeItemStyles['tree-item-focus-target']}`);
|
|
9
|
+
return toggleElement;
|
|
10
|
+
}
|
|
11
|
+
export function isElementDisabled(element) {
|
|
12
|
+
if (element instanceof HTMLButtonElement) {
|
|
13
|
+
return element.disabled;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
export function findTreeItemByIndex(treeView, targetTreeItemIndex, delta) {
|
|
18
|
+
var _a;
|
|
19
|
+
let targetTreeItem = null;
|
|
20
|
+
const treeItemElements = Array.from(treeView.querySelectorAll('li[data-awsui-tree-item-index]'));
|
|
21
|
+
if (delta < 0) {
|
|
22
|
+
treeItemElements.reverse();
|
|
23
|
+
}
|
|
24
|
+
for (const element of treeItemElements) {
|
|
25
|
+
const elementIndex = parseInt((_a = element.getAttribute('data-awsui-tree-item-index')) !== null && _a !== void 0 ? _a : '');
|
|
26
|
+
targetTreeItem = element;
|
|
27
|
+
if (elementIndex === targetTreeItemIndex) {
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return targetTreeItem;
|
|
32
|
+
}
|
|
33
|
+
export function findTreeItemContentById(treeView, treeItemId) {
|
|
34
|
+
const treeItemContent = treeView.querySelector(`li[data-awsui-tree-item-index][id="${treeItemId}"] .${treeItemStyles['tree-item-structured-item']}`);
|
|
35
|
+
return treeItemContent;
|
|
36
|
+
}
|
|
37
|
+
export function isTreeItemToggle(element) {
|
|
38
|
+
return element.classList.contains(treeItemStyles['tree-item-focus-target']);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/tree-view/keyboard-navigation/utils.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AACtC,OAAO,cAAc,MAAM,4BAA4B,CAAC;AAExD,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,OAAO,OAAO,CAAC,OAAO,CAAC,gCAAgC,CAAyB,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAA8B;IACtE,MAAM,aAAa,GAAG,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,aAAa,CAAC,IAAI,cAAc,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC;IAC9F,OAAO,aAAmC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAoB;IACpD,IAAI,OAAO,YAAY,iBAAiB,EAAE;QACxC,OAAO,OAAO,CAAC,QAAQ,CAAC;KACzB;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAA0B,EAAE,mBAA2B,EAAE,KAAa;;IACxG,IAAI,cAAc,GAAyB,IAAI,CAAC;IAChD,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,gCAAgC,CAAC,CAAC,CAAC;IAEjG,IAAI,KAAK,GAAG,CAAC,EAAE;QACb,gBAAgB,CAAC,OAAO,EAAE,CAAC;KAC5B;IAED,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE;QACtC,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAA,OAAO,CAAC,YAAY,CAAC,4BAA4B,CAAC,mCAAI,EAAE,CAAC,CAAC;QACxF,cAAc,GAAG,OAAwB,CAAC;QAE1C,IAAI,YAAY,KAAK,mBAAmB,EAAE;YACxC,MAAM;SACP;KACF;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAA0B,EAAE,UAAkB;IACpF,MAAM,eAAe,GAAG,QAAQ,CAAC,aAAa,CAC5C,sCAAsC,UAAU,OAAO,cAAc,CAAC,2BAA2B,CAAC,EAAE,CACrG,CAAC;IACF,OAAO,eAAuC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,OAAO,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC,CAAC;AAC9E,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport treeItemStyles from '../tree-item/styles.css.js';\n\nexport function getClosestTreeItem(element: Element) {\n return element.closest('li[data-awsui-tree-item-index]') as null | HTMLLIElement;\n}\n\nexport function getToggleButtonOfTreeItem(treeItem: null | HTMLLIElement) {\n const toggleElement = treeItem?.querySelector(`.${treeItemStyles['tree-item-focus-target']}`);\n return toggleElement as null | HTMLElement;\n}\n\nexport function isElementDisabled(element: HTMLElement) {\n if (element instanceof HTMLButtonElement) {\n return element.disabled;\n }\n return false;\n}\n\nexport function findTreeItemByIndex(treeView: HTMLUListElement, targetTreeItemIndex: number, delta: number) {\n let targetTreeItem: null | HTMLLIElement = null;\n const treeItemElements = Array.from(treeView.querySelectorAll('li[data-awsui-tree-item-index]'));\n\n if (delta < 0) {\n treeItemElements.reverse();\n }\n\n for (const element of treeItemElements) {\n const elementIndex = parseInt(element.getAttribute('data-awsui-tree-item-index') ?? '');\n targetTreeItem = element as HTMLLIElement;\n\n if (elementIndex === targetTreeItemIndex) {\n break;\n }\n }\n return targetTreeItem;\n}\n\nexport function findTreeItemContentById(treeView: HTMLUListElement, treeItemId: string) {\n const treeItemContent = treeView.querySelector(\n `li[data-awsui-tree-item-index][id=\"${treeItemId}\"] .${treeItemStyles['tree-item-structured-item']}`\n );\n return treeItemContent as null | HTMLLIElement;\n}\n\nexport function isTreeItemToggle(element: Element) {\n return element.classList.contains(treeItemStyles['tree-item-focus-target']);\n}\n"]}
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
*/
|
|
179
179
|
/* Style used for links in slots/components that are text heavy, to help links stand out among
|
|
180
180
|
surrounding text. (WCAG F73) https://www.w3.org/WAI/WCAG21/Techniques/failures/F73#description */
|
|
181
|
-
.
|
|
181
|
+
.awsui_root_18gnm_1d03e_181:not(#\9) {
|
|
182
182
|
border-collapse: separate;
|
|
183
183
|
border-spacing: 0;
|
|
184
184
|
box-sizing: border-box;
|
|
@@ -215,7 +215,8 @@ surrounding text. (WCAG F73) https://www.w3.org/WAI/WCAG21/Techniques/failures/F
|
|
|
215
215
|
padding-inline: var(--space-scaled-xxs-jatbiv, 4px);
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
.
|
|
218
|
+
.awsui_tree_18gnm_1d03e_218:not(#\9) {
|
|
219
|
+
list-style: none;
|
|
219
220
|
margin-block: 0;
|
|
220
221
|
margin-inline: 0;
|
|
221
222
|
padding-block: 0;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// es-module interop with Babel and Typescript
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
module.exports.default = {
|
|
5
|
-
"root": "
|
|
6
|
-
"tree": "
|
|
5
|
+
"root": "awsui_root_18gnm_1d03e_181",
|
|
6
|
+
"tree": "awsui_tree_18gnm_1d03e_218"
|
|
7
7
|
};
|
|
8
8
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus-target.d.ts","sourceRoot":"","sources":["../../../../src/tree-view/tree-item/focus-target.tsx"],"names":[],"mappings":";AAQA,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,eAexE"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import React, { useRef } from 'react';
|
|
4
|
+
import { useSingleTabStopNavigation } from '@cloudscape-design/component-toolkit/internal';
|
|
5
|
+
import styles from './styles.css.js';
|
|
6
|
+
export default function FocusTarget({ ariaLabel }) {
|
|
7
|
+
const divRef = useRef(null);
|
|
8
|
+
const { tabIndex } = useSingleTabStopNavigation(divRef);
|
|
9
|
+
return (React.createElement("div", { role: "group", ref: divRef, tabIndex: tabIndex, "aria-label": ariaLabel, className: styles['tree-item-focus-target'] }, null));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=focus-target.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus-target.js","sourceRoot":"","sources":["../../../../src/tree-view/tree-item/focus-target.tsx"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AACtC,OAAO,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEtC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+CAA+C,CAAC;AAE3F,OAAO,MAAM,MAAM,iBAAiB,CAAC;AAErC,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,SAAS,EAA0B;IACvE,MAAM,MAAM,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAE,QAAQ,EAAE,GAAG,0BAA0B,CAAC,MAAM,CAAC,CAAC;IAExD,OAAO,CACL,6BACE,IAAI,EAAC,OAAO,EACZ,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,gBACN,SAAS,EACrB,SAAS,EAAE,MAAM,CAAC,wBAAwB,CAAC,IAE1C,IAAI,CACD,CACP,CAAC;AACJ,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport React, { useRef } from 'react';\n\nimport { useSingleTabStopNavigation } from '@cloudscape-design/component-toolkit/internal';\n\nimport styles from './styles.css.js';\n\nexport default function FocusTarget({ ariaLabel }: { ariaLabel?: string }) {\n const divRef = useRef<HTMLDivElement>(null);\n const { tabIndex } = useSingleTabStopNavigation(divRef);\n\n return (\n <div\n role=\"group\"\n ref={divRef}\n tabIndex={tabIndex}\n aria-label={ariaLabel}\n className={styles['tree-item-focus-target']}\n >\n {null}\n </div>\n );\n}\n"]}
|
|
@@ -5,7 +5,10 @@ interface InternalTreeItemProps<T> extends Pick<TreeViewProps, 'expandedItems' |
|
|
|
5
5
|
index: number;
|
|
6
6
|
level: number;
|
|
7
7
|
onItemToggle: (detail: TreeViewProps.ItemToggleDetail<T>) => void;
|
|
8
|
+
allVisibleItemsIndices: {
|
|
9
|
+
[key: string]: number;
|
|
10
|
+
};
|
|
8
11
|
}
|
|
9
|
-
declare const InternalTreeItem: <T>({ item, index, level, i18nStrings, expandedItems, renderItemToggleIcon, renderItem, getItemId, getItemChildren, onItemToggle, }: InternalTreeItemProps<T>) => JSX.Element;
|
|
12
|
+
declare const InternalTreeItem: <T>({ item, index, level, i18nStrings, expandedItems, renderItemToggleIcon, renderItem, getItemId, getItemChildren, onItemToggle, allVisibleItemsIndices, }: InternalTreeItemProps<T>) => JSX.Element;
|
|
10
13
|
export default InternalTreeItem;
|
|
11
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tree-view/tree-item/index.tsx"],"names":[],"mappings":";AASA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tree-view/tree-item/index.tsx"],"names":[],"mappings":";AASA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAM9C,UAAU,qBAAqB,CAAC,CAAC,CAC/B,SAAQ,IAAI,CACV,aAAa,EACb,eAAe,GAAG,YAAY,GAAG,WAAW,GAAG,iBAAiB,GAAG,sBAAsB,GAAG,aAAa,CAC1G;IACD,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAClE,sBAAsB,EAAE;QACtB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,CAAC;CACH;AAED,QAAA,MAAM,gBAAgB,uMA+GrB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -6,9 +6,10 @@ import { useInternalI18n } from '../../i18n/context';
|
|
|
6
6
|
import { ExpandToggleButton } from '../../internal/components/expand-toggle-button';
|
|
7
7
|
import InternalStructuredItem from '../../internal/components/structured-item';
|
|
8
8
|
import { joinStrings } from '../../internal/utils/strings';
|
|
9
|
+
import FocusTarget from './focus-target';
|
|
9
10
|
import testUtilStyles from '../test-classes/styles.css.js';
|
|
10
11
|
import styles from './styles.css.js';
|
|
11
|
-
const InternalTreeItem = ({ item, index, level, i18nStrings, expandedItems = [], renderItemToggleIcon, renderItem, getItemId, getItemChildren, onItemToggle, }) => {
|
|
12
|
+
const InternalTreeItem = ({ item, index, level, i18nStrings, expandedItems = [], renderItemToggleIcon, renderItem, getItemId, getItemChildren, onItemToggle, allVisibleItemsIndices, }) => {
|
|
12
13
|
var _a, _b;
|
|
13
14
|
const i18n = useInternalI18n('tree-view');
|
|
14
15
|
const { icon, content, secondaryContent, actions, announcementLabel } = renderItem(item, index);
|
|
@@ -26,14 +27,15 @@ const InternalTreeItem = ({ item, index, level, i18nStrings, expandedItems = [],
|
|
|
26
27
|
: typeof content === 'string'
|
|
27
28
|
? content
|
|
28
29
|
: '';
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
isExpanded && children.length && (React.createElement("ul", { className: styles['treeitem-group'] }, children.map((child, index) => {
|
|
36
|
-
|
|
30
|
+
return (React.createElement("li", { role: "treeitem", id: id, className: clsx(styles.treeitem, testUtilStyles.treeitem, level > 1 && styles.offset, isExpandable && [testUtilStyles.expandable], isExpanded && [testUtilStyles.expanded]), "aria-expanded": isExpandable ? isExpanded : undefined, "aria-level": level, "data-testid": `awsui-treeitem-${id}`, "data-awsui-tree-item-index": allVisibleItemsIndices[id] },
|
|
31
|
+
React.createElement("div", { className: styles['treeitem-content-wrapper'] },
|
|
32
|
+
React.createElement("div", { className: styles['expand-toggle-wrapper'] },
|
|
33
|
+
React.createElement("div", { className: styles.toggle }, isExpandable ? (React.createElement(ExpandToggleButton, { isExpanded: isExpanded, customIcon: customIcon, expandButtonLabel: joinStrings(i18n('i18nStrings.expandButtonLabel', (_a = i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.expandButtonLabel) === null || _a === void 0 ? void 0 : _a.call(i18nStrings, item)), itemLabelToAnnounce), collapseButtonLabel: joinStrings(i18n('i18nStrings.collapseButtonLabel', (_b = i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.collapseButtonLabel) === null || _b === void 0 ? void 0 : _b.call(i18nStrings, item)), itemLabelToAnnounce), onExpandableItemToggle: () => onItemToggle({ id, item, expanded: !isExpanded }), className: styles['tree-item-focus-target'], disableFocusHighlight: true })) : (React.createElement(FocusTarget, { ariaLabel: itemLabelToAnnounce })))),
|
|
34
|
+
React.createElement("div", { className: styles['structured-item-wrapper'] },
|
|
35
|
+
React.createElement(InternalStructuredItem, { icon: icon, content: content, secondaryContent: secondaryContent, actions: actions, wrapActions: false, className: styles['tree-item-structured-item'] }))),
|
|
36
|
+
isExpanded && children.length && (React.createElement("ul", { role: "group", className: styles['treeitem-group'] }, children.map((child, index) => {
|
|
37
|
+
const itemId = getItemId(child, index);
|
|
38
|
+
return (React.createElement(InternalTreeItem, { item: child, index: index, key: itemId, level: nextLevel, expandedItems: expandedItems, i18nStrings: i18nStrings, onItemToggle: onItemToggle, renderItem: renderItem, getItemId: getItemId, getItemChildren: getItemChildren, renderItemToggleIcon: renderItemToggleIcon, allVisibleItemsIndices: allVisibleItemsIndices }));
|
|
37
39
|
})))));
|
|
38
40
|
};
|
|
39
41
|
export default InternalTreeItem;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/tree-view/tree-item/index.tsx"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AACtC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AACpF,OAAO,sBAAsB,MAAM,2CAA2C,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/tree-view/tree-item/index.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport React from 'react';\nimport clsx from 'clsx';\n\nimport { useInternalI18n } from '../../i18n/context';\nimport { ExpandToggleButton } from '../../internal/components/expand-toggle-button';\nimport InternalStructuredItem from '../../internal/components/structured-item';\nimport { joinStrings } from '../../internal/utils/strings';\nimport { TreeViewProps } from '../interfaces';\nimport FocusTarget from './focus-target';\n\nimport testUtilStyles from '../test-classes/styles.css.js';\nimport styles from './styles.css.js';\n\ninterface InternalTreeItemProps<T>\n extends Pick<\n TreeViewProps,\n 'expandedItems' | 'renderItem' | 'getItemId' | 'getItemChildren' | 'renderItemToggleIcon' | 'i18nStrings'\n > {\n item: T;\n index: number;\n level: number;\n onItemToggle: (detail: TreeViewProps.ItemToggleDetail<T>) => void;\n allVisibleItemsIndices: {\n [key: string]: number;\n };\n}\n\nconst InternalTreeItem = <T,>({\n item,\n index,\n level,\n i18nStrings,\n expandedItems = [],\n renderItemToggleIcon,\n renderItem,\n getItemId,\n getItemChildren,\n onItemToggle,\n allVisibleItemsIndices,\n}: InternalTreeItemProps<T>) => {\n const i18n = useInternalI18n('tree-view');\n\n const { icon, content, secondaryContent, actions, announcementLabel } = renderItem(item, index);\n const id = getItemId(item, index);\n const children = getItemChildren(item, index) || [];\n const isExpandable = children.length > 0;\n const isExpanded = isExpandable && expandedItems.includes(id);\n const nextLevel = level + 1;\n\n let customIcon: React.ReactNode | undefined = undefined;\n if (isExpandable && renderItemToggleIcon) {\n customIcon = renderItemToggleIcon({ expanded: isExpanded });\n }\n\n const itemLabelToAnnounce = announcementLabel\n ? announcementLabel\n : typeof content === 'string'\n ? (content as string)\n : '';\n\n return (\n <li\n role=\"treeitem\"\n id={id}\n className={clsx(\n styles.treeitem,\n testUtilStyles.treeitem,\n level > 1 && styles.offset,\n isExpandable && [testUtilStyles.expandable],\n isExpanded && [testUtilStyles.expanded]\n )}\n aria-expanded={isExpandable ? isExpanded : undefined}\n aria-level={level}\n data-testid={`awsui-treeitem-${id}`}\n data-awsui-tree-item-index={allVisibleItemsIndices[id]}\n >\n <div className={styles['treeitem-content-wrapper']}>\n <div className={styles['expand-toggle-wrapper']}>\n <div className={styles.toggle}>\n {isExpandable ? (\n <ExpandToggleButton\n isExpanded={isExpanded}\n customIcon={customIcon}\n expandButtonLabel={joinStrings(\n i18n('i18nStrings.expandButtonLabel', i18nStrings?.expandButtonLabel?.(item)),\n itemLabelToAnnounce\n )}\n collapseButtonLabel={joinStrings(\n i18n('i18nStrings.collapseButtonLabel', i18nStrings?.collapseButtonLabel?.(item)),\n itemLabelToAnnounce\n )}\n onExpandableItemToggle={() => onItemToggle({ id, item, expanded: !isExpanded })}\n className={styles['tree-item-focus-target']}\n disableFocusHighlight={true}\n />\n ) : (\n <FocusTarget ariaLabel={itemLabelToAnnounce} />\n )}\n </div>\n </div>\n\n <div className={styles['structured-item-wrapper']}>\n <InternalStructuredItem\n icon={icon}\n content={content}\n secondaryContent={secondaryContent}\n actions={actions}\n wrapActions={false}\n className={styles['tree-item-structured-item']}\n />\n </div>\n </div>\n\n {isExpanded && children.length && (\n <ul role=\"group\" className={styles['treeitem-group']}>\n {children.map((child, index) => {\n const itemId = getItemId(child, index);\n return (\n <InternalTreeItem<T>\n item={child}\n index={index}\n key={itemId}\n level={nextLevel}\n expandedItems={expandedItems}\n i18nStrings={i18nStrings}\n onItemToggle={onItemToggle}\n renderItem={renderItem}\n getItemId={getItemId}\n getItemChildren={getItemChildren}\n renderItemToggleIcon={renderItemToggleIcon}\n allVisibleItemsIndices={allVisibleItemsIndices}\n />\n );\n })}\n </ul>\n )}\n </li>\n );\n};\n\nexport default InternalTreeItem;\n"]}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
import './styles.scoped.css';
|
|
3
3
|
export default {
|
|
4
|
-
"treeitem-group": "awsui_treeitem-
|
|
5
|
-
"treeitem": "
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
4
|
+
"treeitem-group": "awsui_treeitem-group_1agpu_1hpjs_185",
|
|
5
|
+
"treeitem": "awsui_treeitem_1agpu_1hpjs_185",
|
|
6
|
+
"offset": "awsui_offset_1agpu_1hpjs_202",
|
|
7
|
+
"treeitem-content-wrapper": "awsui_treeitem-content-wrapper_1agpu_1hpjs_205",
|
|
8
|
+
"tree-item-focus-target": "awsui_tree-item-focus-target_1agpu_1hpjs_210",
|
|
9
|
+
"expand-toggle-wrapper": "awsui_expand-toggle-wrapper_1agpu_1hpjs_231",
|
|
10
|
+
"toggle": "awsui_toggle_1agpu_1hpjs_236",
|
|
11
|
+
"structured-item-wrapper": "awsui_structured-item-wrapper_1agpu_1hpjs_241",
|
|
12
|
+
"tree-item-structured-item": "awsui_tree-item-structured-item_1agpu_1hpjs_248"
|
|
9
13
|
};
|
|
10
14
|
|
|
@@ -178,39 +178,74 @@
|
|
|
178
178
|
*/
|
|
179
179
|
/* Style used for links in slots/components that are text heavy, to help links stand out among
|
|
180
180
|
surrounding text. (WCAG F73) https://www.w3.org/WAI/WCAG21/Techniques/failures/F73#description */
|
|
181
|
-
|
|
181
|
+
/*
|
|
182
|
+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
183
|
+
SPDX-License-Identifier: Apache-2.0
|
|
184
|
+
*/
|
|
185
|
+
.awsui_treeitem-group_1agpu_1hpjs_185:not(#\9) {
|
|
186
|
+
list-style: none;
|
|
182
187
|
margin-block: 0;
|
|
183
188
|
margin-inline: 0;
|
|
184
189
|
padding-block: 0;
|
|
185
190
|
padding-inline: 0;
|
|
191
|
+
position: relative;
|
|
186
192
|
}
|
|
187
193
|
|
|
188
|
-
.
|
|
194
|
+
.awsui_treeitem_1agpu_1hpjs_185:not(#\9) {
|
|
195
|
+
list-style: none;
|
|
189
196
|
margin-block: 0;
|
|
190
197
|
margin-inline: 0;
|
|
191
198
|
padding-block: 0;
|
|
192
199
|
padding-inline: 0;
|
|
193
|
-
|
|
200
|
+
position: relative;
|
|
201
|
+
}
|
|
202
|
+
.awsui_treeitem_1agpu_1hpjs_185.awsui_offset_1agpu_1hpjs_202:not(#\9) {
|
|
203
|
+
margin-inline-start: 28px;
|
|
204
|
+
}
|
|
205
|
+
.awsui_treeitem_1agpu_1hpjs_185 > .awsui_treeitem-content-wrapper_1agpu_1hpjs_205:not(#\9) {
|
|
194
206
|
display: grid;
|
|
195
207
|
grid-template-columns: 28px 1fr;
|
|
196
|
-
|
|
208
|
+
align-items: baseline;
|
|
209
|
+
}
|
|
210
|
+
body[data-awsui-focus-visible=true] .awsui_treeitem_1agpu_1hpjs_185 > .awsui_treeitem-content-wrapper_1agpu_1hpjs_205:not(#\9):has(.awsui_tree-item-focus-target_1agpu_1hpjs_210:focus) {
|
|
211
|
+
position: relative;
|
|
212
|
+
}
|
|
213
|
+
body[data-awsui-focus-visible=true] .awsui_treeitem_1agpu_1hpjs_185 > .awsui_treeitem-content-wrapper_1agpu_1hpjs_205:not(#\9):has(.awsui_tree-item-focus-target_1agpu_1hpjs_210:focus) {
|
|
214
|
+
outline: 2px dotted transparent;
|
|
215
|
+
outline-offset: calc(0px - 1px);
|
|
197
216
|
}
|
|
198
|
-
.
|
|
217
|
+
body[data-awsui-focus-visible=true] .awsui_treeitem_1agpu_1hpjs_185 > .awsui_treeitem-content-wrapper_1agpu_1hpjs_205:not(#\9):has(.awsui_tree-item-focus-target_1agpu_1hpjs_210:focus)::before {
|
|
218
|
+
content: " ";
|
|
219
|
+
display: block;
|
|
220
|
+
position: absolute;
|
|
221
|
+
inset-inline-start: calc(-1 * 0px);
|
|
222
|
+
inset-block-start: calc(-1 * 0px);
|
|
223
|
+
inline-size: calc(100% + 0px + 0px);
|
|
224
|
+
block-size: calc(100% + 0px + 0px);
|
|
225
|
+
border-start-start-radius: var(--border-radius-control-default-focus-ring-9xsko1, 2px);
|
|
226
|
+
border-start-end-radius: var(--border-radius-control-default-focus-ring-9xsko1, 2px);
|
|
227
|
+
border-end-start-radius: var(--border-radius-control-default-focus-ring-9xsko1, 2px);
|
|
228
|
+
border-end-end-radius: var(--border-radius-control-default-focus-ring-9xsko1, 2px);
|
|
229
|
+
box-shadow: 0 0 0 2px var(--color-border-item-focused-r5f6xl, #0073bb);
|
|
230
|
+
}
|
|
231
|
+
.awsui_treeitem_1agpu_1hpjs_185 > .awsui_treeitem-content-wrapper_1agpu_1hpjs_205 > .awsui_expand-toggle-wrapper_1agpu_1hpjs_231:not(#\9) {
|
|
199
232
|
grid-column: 1;
|
|
200
233
|
grid-row: 1;
|
|
201
|
-
|
|
234
|
+
padding-inline-end: var(--space-scaled-xxs-jatbiv, 4px);
|
|
202
235
|
}
|
|
203
|
-
.
|
|
236
|
+
.awsui_treeitem_1agpu_1hpjs_185 > .awsui_treeitem-content-wrapper_1agpu_1hpjs_205 > .awsui_expand-toggle-wrapper_1agpu_1hpjs_231 > .awsui_toggle_1agpu_1hpjs_236:not(#\9) {
|
|
204
237
|
justify-self: center;
|
|
205
238
|
position: relative;
|
|
206
239
|
inset-block-start: 2px;
|
|
207
240
|
}
|
|
208
|
-
.
|
|
241
|
+
.awsui_treeitem_1agpu_1hpjs_185 > .awsui_treeitem-content-wrapper_1agpu_1hpjs_205 > .awsui_structured-item-wrapper_1agpu_1hpjs_241:not(#\9) {
|
|
209
242
|
grid-column: 2;
|
|
210
243
|
grid-row: 1/span 2;
|
|
211
244
|
padding-block: var(--space-scaled-xxs-jatbiv, 4px);
|
|
245
|
+
position: relative;
|
|
212
246
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
247
|
+
|
|
248
|
+
.awsui_tree-item-structured-item_1agpu_1hpjs_248:not(#\9),
|
|
249
|
+
.awsui_tree-item-focus-target_1agpu_1hpjs_210:not(#\9) {
|
|
250
|
+
/* used in keyboard navigation */
|
|
216
251
|
}
|