Skip to content

Commit 90546a9

Browse files
committed
Adds virtualized tree with keyboard nav support
- Replaces tree with lit-labs/virtualizer for better perf - Implements keyboard nav (arrow keys, Home/End, Enter/Space, Tab) - Adds type-ahead search functionality for quick item location - Improves action button focus handling and Tab navigation
1 parent 868eccf commit 90546a9

File tree

8 files changed

+888
-114
lines changed

8 files changed

+888
-114
lines changed

ThirdPartyNotices.txt

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,37 @@ This project incorporates components from the projects listed below.
55

66
1. @gk-nzaytsev/fast-string-truncated-width version 1.1.0 (https://github.com/nzaytsev/fast-string-truncated-width)
77
2. @lit-labs/signals version 0.1.3 (https://github.com/lit/lit)
8-
3. @lit/context version 1.1.6 (https://github.com/lit/lit)
9-
4. @lit/react version 1.0.8 (https://github.com/lit/lit)
10-
5. @lit/task version 1.0.3 (https://github.com/lit/lit)
11-
6. @octokit/graphql version 9.0.1 (https://github.com/octokit/graphql.js)
12-
7. @octokit/request-error version 7.0.0 (https://github.com/octokit/request-error.js)
13-
8. @octokit/request version 10.0.3 (https://github.com/octokit/request.js)
14-
9. @octokit/types version 14.1.0 (https://github.com/octokit/types.ts)
15-
10. @opentelemetry/api version 1.9.0 (https://github.com/open-telemetry/opentelemetry-js)
16-
11. @opentelemetry/exporter-trace-otlp-http version 0.205.0 (https://github.com/open-telemetry/opentelemetry-js)
17-
12. @opentelemetry/resources version 2.1.0 (https://github.com/open-telemetry/opentelemetry-js)
18-
13. @opentelemetry/sdk-trace-base version 2.1.0 (https://github.com/open-telemetry/opentelemetry-js)
19-
14. @opentelemetry/semantic-conventions version 1.37.0 (https://github.com/open-telemetry/opentelemetry-js)
20-
15. @shoelace-style/shoelace version 2.20.1 (https://github.com/shoelace-style/shoelace)
21-
16. @vscode/codicons version 0.0.40 (https://github.com/microsoft/vscode-codicons)
22-
17. billboard.js version 3.17.0 (https://github.com/naver/billboard.js)
23-
18. diff2html version 3.4.52 (https://github.com/rtfpessoa/diff2html)
24-
19. driver.js version 1.3.6 (https://github.com/kamranahmedse/driver.js)
25-
20. https-proxy-agent version 5.0.1 (https://github.com/TooTallNate/node-https-proxy-agent)
26-
21. iconv-lite version 0.6.3 (https://github.com/ashtuchkin/iconv-lite)
27-
22. lit version 3.3.1 (https://github.com/lit/lit)
28-
23. marked version 16.3.0 (https://github.com/markedjs/marked)
29-
24. microsoft/vscode (https://github.com/microsoft/vscode)
30-
25. node-fetch version 2.7.0 (https://github.com/bitinn/node-fetch)
31-
26. os-browserify version 0.3.0 (https://github.com/CoderPuppy/os-browserify)
32-
27. path-browserify version 1.0.1 (https://github.com/browserify/path-browserify)
33-
28. react-dom version 19.0.0 (https://github.com/facebook/react)
34-
29. react version 19.0.0 (https://github.com/facebook/react)
35-
30. signal-utils version 0.21.1 (https://github.com/proposal-signals/signal-utils)
36-
31. slug version 11.0.0 (https://github.com/Trott/slug)
37-
32. sortablejs version 1.15.6 (https://github.com/SortableJS/Sortable)
8+
3. @lit-labs/virtualizer version 2.1.1 (https://github.com/lit/lit)
9+
4. @lit/context version 1.1.6 (https://github.com/lit/lit)
10+
5. @lit/react version 1.0.8 (https://github.com/lit/lit)
11+
6. @lit/task version 1.0.3 (https://github.com/lit/lit)
12+
7. @octokit/graphql version 9.0.1 (https://github.com/octokit/graphql.js)
13+
8. @octokit/request-error version 7.0.0 (https://github.com/octokit/request-error.js)
14+
9. @octokit/request version 10.0.3 (https://github.com/octokit/request.js)
15+
10. @octokit/types version 14.1.0 (https://github.com/octokit/types.ts)
16+
11. @opentelemetry/api version 1.9.0 (https://github.com/open-telemetry/opentelemetry-js)
17+
12. @opentelemetry/exporter-trace-otlp-http version 0.205.0 (https://github.com/open-telemetry/opentelemetry-js)
18+
13. @opentelemetry/resources version 2.1.0 (https://github.com/open-telemetry/opentelemetry-js)
19+
14. @opentelemetry/sdk-trace-base version 2.1.0 (https://github.com/open-telemetry/opentelemetry-js)
20+
15. @opentelemetry/semantic-conventions version 1.37.0 (https://github.com/open-telemetry/opentelemetry-js)
21+
16. @shoelace-style/shoelace version 2.20.1 (https://github.com/shoelace-style/shoelace)
22+
17. @vscode/codicons version 0.0.40 (https://github.com/microsoft/vscode-codicons)
23+
18. billboard.js version 3.17.0 (https://github.com/naver/billboard.js)
24+
19. diff2html version 3.4.52 (https://github.com/rtfpessoa/diff2html)
25+
20. driver.js version 1.3.6 (https://github.com/kamranahmedse/driver.js)
26+
21. https-proxy-agent version 5.0.1 (https://github.com/TooTallNate/node-https-proxy-agent)
27+
22. iconv-lite version 0.6.3 (https://github.com/ashtuchkin/iconv-lite)
28+
23. lit version 3.3.1 (https://github.com/lit/lit)
29+
24. marked version 16.3.0 (https://github.com/markedjs/marked)
30+
25. microsoft/vscode (https://github.com/microsoft/vscode)
31+
26. node-fetch version 2.7.0 (https://github.com/bitinn/node-fetch)
32+
27. os-browserify version 0.3.0 (https://github.com/CoderPuppy/os-browserify)
33+
28. path-browserify version 1.0.1 (https://github.com/browserify/path-browserify)
34+
29. react-dom version 19.0.0 (https://github.com/facebook/react)
35+
30. react version 19.0.0 (https://github.com/facebook/react)
36+
31. signal-utils version 0.21.1 (https://github.com/proposal-signals/signal-utils)
37+
32. slug version 11.0.0 (https://github.com/Trott/slug)
38+
33. sortablejs version 1.15.6 (https://github.com/SortableJS/Sortable)
3839

3940
%% @gk-nzaytsev/fast-string-truncated-width NOTICES AND INFORMATION BEGIN HERE
4041
=========================================
@@ -97,6 +98,40 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9798
=========================================
9899
END OF @lit-labs/signals NOTICES AND INFORMATION
99100

101+
%% @lit-labs/virtualizer NOTICES AND INFORMATION BEGIN HERE
102+
=========================================
103+
BSD 3-Clause License
104+
105+
Copyright (c) 2017, Google LLC. All rights reserved.
106+
107+
Redistribution and use in source and binary forms, with or without
108+
modification, are permitted provided that the following conditions are met:
109+
110+
* Redistributions of source code must retain the above copyright notice, this
111+
list of conditions and the following disclaimer.
112+
113+
* Redistributions in binary form must reproduce the above copyright notice,
114+
this list of conditions and the following disclaimer in the documentation
115+
and/or other materials provided with the distribution.
116+
117+
* Neither the name of the copyright holder nor the names of its
118+
contributors may be used to endorse or promote products derived from
119+
this software without specific prior written permission.
120+
121+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
122+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
123+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
124+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
125+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
126+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
127+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
128+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
129+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
130+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
131+
132+
=========================================
133+
END OF @lit-labs/virtualizer NOTICES AND INFORMATION
134+
100135
%% @lit/context NOTICES AND INFORMATION BEGIN HERE
101136
=========================================
102137
BSD 3-Clause License

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25051,6 +25051,7 @@
2505125051
"@gitkraken/shared-web-components": "0.1.1-rc.15",
2505225052
"@gk-nzaytsev/fast-string-truncated-width": "1.1.0",
2505325053
"@lit-labs/signals": "0.1.3",
25054+
"@lit-labs/virtualizer": "2.1.1",
2505425055
"@lit/context": "1.1.6",
2505525056
"@lit/react": "1.0.8",
2505625057
"@lit/task": "1.0.3",

pnpm-lock.yaml

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/webviews/apps/shared/components/actions/action-item.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class ActionItem extends LitElement {
2121
width: 2rem;
2222
height: 2rem;
2323
border-radius: 0.5rem;
24-
color: inherit;
24+
color: var(--vscode-icon-foreground);
2525
padding: 0.2rem;
2626
vertical-align: text-bottom;
2727
text-decoration: none;
@@ -32,7 +32,8 @@ export class ActionItem extends LitElement {
3232
${focusOutline}
3333
}
3434
35-
:host(:hover) {
35+
:host(:hover),
36+
:host(:focus-within) {
3637
background-color: var(--vscode-toolbar-hoverBackground);
3738
}
3839
@@ -47,6 +48,11 @@ export class ActionItem extends LitElement {
4748
4849
a {
4950
color: inherit;
51+
display: flex;
52+
align-items: center;
53+
justify-content: center;
54+
width: 100%;
55+
height: 100%;
5056
}
5157
a:focus {
5258
outline: none;
@@ -147,13 +153,24 @@ export class ActionItem extends LitElement {
147153
aria-label="${this.effectiveLabel ?? nothing}"
148154
?disabled=${this.disabled}
149155
href=${this.effectiveHref ?? nothing}
156+
tabindex="0"
157+
@keydown=${this.handleLinkKeydown}
150158
>
151159
<code-icon icon="${this.effectiveIcon}"></code-icon>
152160
</a>
153161
</gl-tooltip>
154162
`;
155163
}
156164

165+
private handleLinkKeydown = (e: KeyboardEvent) => {
166+
// Handle Space and Enter for button-role links without href
167+
if (!this.effectiveHref && (e.key === ' ' || e.key === 'Enter')) {
168+
e.preventDefault();
169+
// Trigger a click event
170+
(e.target as HTMLElement).click();
171+
}
172+
};
173+
157174
override focus(options?: FocusOptions): void {
158175
this.defaultFocusEl.focus(options);
159176
}

src/webviews/apps/shared/components/actions/action-nav.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,17 @@ export class ActionNav extends LitElement {
3333
private handleSlotChange(_e: Event) {
3434
this._slotSubscriptionsDisposer?.();
3535

36-
if (this.actionNodes.length < 2) return;
36+
if (this.actionNodes.length < 1) return;
3737

3838
const handleKeydown = this.handleKeydown.bind(this);
3939
const size = `${this.actionNodes.length}`;
4040
const subs = this.actionNodes.map((element, i) => {
4141
element.setAttribute('aria-posinset', `${i + 1}`);
4242
element.setAttribute('aria-setsize', size);
4343
element.setAttribute('tabindex', i === 0 ? '0' : '-1');
44-
element.addEventListener('keydown', handleKeydown, false);
44+
if (this.actionNodes.length >= 2) {
45+
element.addEventListener('keydown', handleKeydown, false);
46+
}
4547
return {
4648
dispose: () => {
4749
element?.removeEventListener('keydown', handleKeydown, false);
@@ -55,10 +57,18 @@ export class ActionNav extends LitElement {
5557
}
5658

5759
private handleKeydown(e: KeyboardEvent) {
58-
if (!e.target || this.actionNodes == null || this.actionNodes.length < 2) return;
60+
if (!e.target || this.actionNodes == null) return;
5961
const target = e.target as HTMLElement;
6062
const posinset = parseInt(target.getAttribute('aria-posinset') ?? '0', 10);
6163

64+
// Only handle arrow keys, not Tab
65+
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') {
66+
return;
67+
}
68+
69+
// Handle arrow key navigation between action buttons
70+
if (this.actionNodes.length < 2) return;
71+
6272
let $next: HTMLElement | null = null;
6373
if (e.key === 'ArrowLeft') {
6474
const next = posinset === 1 ? this.actionNodes.length - 1 : posinset - 2;
@@ -70,6 +80,8 @@ export class ActionNav extends LitElement {
7080
if ($next == null || $next === target) {
7181
return;
7282
}
83+
e.preventDefault();
84+
e.stopPropagation();
7385
target.setAttribute('tabindex', '-1');
7486
$next.setAttribute('tabindex', '0');
7587
$next.focus();

0 commit comments

Comments
 (0)