Skip to content
This repository was archived by the owner on Jul 31, 2026. It is now read-only.

Commit af81995

Browse files
alx-xoclaude
andcommitted
fix: address tabnabbing, stale closure, null coalescing, a11y, and color index bugs
- ExternalPill: add rel="noopener noreferrer" when target="_blank" - useAppLayoutKeys: functional updater for setCollapsed to prevent stale closure on rapid keypresses - Tabs: ?? over || for tab fallback so empty-string IDs are handled correctly - KeyHint: replace dismiss div with button for keyboard/a11y; add React.Fragment keys to mapped modifier/key arrays - UserAvatar: Math.abs() on color index to handle non-letter initials Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b19dfa3 commit af81995

5 files changed

Lines changed: 15 additions & 12 deletions

File tree

src/components/AppLayout/useAppLayoutKeys.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ export function useAppLayoutKeys() {
1111
event.key.toLowerCase() === keybinds.toggle.key.toLowerCase()
1212
) {
1313
event.preventDefault();
14-
setCollapsed(!collapsed);
14+
setCollapsed((prev) => !prev);
1515
}
1616
},
17-
[keybinds, collapsed, setCollapsed],
17+
[keybinds, setCollapsed],
1818
);
1919

2020
useEffect(() => {

src/components/ExternalPill/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export function ExternalPill({
4545
<a
4646
href={href}
4747
target={target}
48+
rel={target === "_blank" ? "noopener noreferrer" : undefined}
4849
title={title}
4950
className={cn(
5051
"inline-flex flex-row items-center gap-1.5 rounded-xl border px-3.5 py-2 text-zinc-700 transition-colors duration-500 hover:border-zinc-300 hover:bg-zinc-50 hover:text-black dark:text-zinc-300 dark:hover:border-zinc-700 dark:hover:bg-zinc-900 hover:dark:text-white",

src/components/KeyHint/index.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { cn } from "@/lib/utils";
22
import { Icon } from "@/components/Icon";
3+
import React from "react";
34

45
type Modifier = "shift" | "ctrlorcommand" | "alt" | "meta" | "esc";
56

@@ -46,21 +47,21 @@ function KeyHintKeys({ modifiers, keys }: KeyHintItemProps) {
4647
return (
4748
<div className="flex flex-row items-center gap-1">
4849
{modifiers.map((modifier, index) => (
49-
<>
50+
<React.Fragment key={modifier}>
5051
<Key value={modifierMap[modifier]} />
5152
{index < modifiers.length - 1 && (
5253
<span className="text-sm text-body-muted">+</span>
5354
)}
54-
</>
55+
</React.Fragment>
5556
))}
5657
{keys.length > 0 && <span className="text-sm text-body-muted">+</span>}
5758
{keys.map((key, index) => (
58-
<>
59+
<React.Fragment key={key}>
5960
<Key value={key.toUpperCase()} />
6061
{index < keys.length - 1 && (
6162
<span className="text-sm text-body-muted">+</span>
6263
)}
63-
</>
64+
</React.Fragment>
6465
))}
6566
</div>
6667
);
@@ -96,13 +97,14 @@ export function KeyHint({
9697
<div className="flex w-full flex-row items-center self-start border-b px-2.5 py-0.5 text-[10px] font-semibold tracking-wide text-body-muted uppercase select-none dark:text-body-muted/80">
9798
<div>{titleText}</div>
9899
{dismissable && (
99-
<div
100+
<button
101+
type="button"
100102
className="ml-auto cursor-pointer hover:text-foreground"
101103
onClick={onDismiss}
102-
title="Close"
104+
aria-label="Dismiss"
103105
>
104106
<Icon name="x" className="h-3.5 w-3.5" />
105-
</div>
107+
</button>
106108
)}
107109
</div>
108110
<div className="flex flex-row items-center gap-1 px-4 py-3.5">

src/components/Tabs/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ export function Tabs<I extends string>({
4848
className,
4949
}: TabsProps<I>) {
5050
const [activeTab, setActiveTab] = useState<I>(
51-
selectedTab || children[0].props.id,
51+
selectedTab ?? children[0].props.id,
5252
);
5353

5454
useEffect(() => {
55-
setActiveTab(selectedTab || children[0].props.id);
55+
setActiveTab(selectedTab ?? children[0].props.id);
5656
}, [selectedTab]);
5757

5858
const validChildren = React.Children.toArray(children).filter(

src/components/UserAvatar/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function getFallbackColor(name: string | undefined) {
2929
const firstLetter = name[0].toLowerCase();
3030

3131
const index = firstLetter.charCodeAt(0) - "a".charCodeAt(0);
32-
return fallbackColors[index % fallbackColors.length];
32+
return fallbackColors[Math.abs(index) % fallbackColors.length];
3333
}
3434

3535
export function UserAvatar({

0 commit comments

Comments
 (0)