Skip to content

Commit a85da6e

Browse files
committed
fix: overlapping tabs
1 parent 9e5f5dc commit a85da6e

5 files changed

Lines changed: 16 additions & 9 deletions

File tree

app/address/[address]/layout.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,9 @@ function getNavigationTabs(pubkey: PublicKey, account: Account): AddressTab[] {
377377
tabs.push(...TABS_LOOKUP[`${programTypeKey}:metaplexNFT`]);
378378
}
379379

380-
// Compressed NFTs: show tabs immediately for accounts with no data
380+
// Compressed NFTs: show tabs immediately for accounts with no data.
381+
// TODO: duplicates with async CompressedNftTabs on desktop tablist — refactor
382+
// to a single source once NavigationTabLink supports static deduplication.
381383
if ((!account.data.raw || account.data.raw.length === 0) && !account.data.parsed) {
382384
tabs.push({ path: 'metadata', title: 'Metadata' });
383385
tabs.push({ path: 'attributes', title: 'Attributes' });

app/entities/navigation-tabs/model/navigation-tabs-context.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export type NavigationTabsContextValue = {
88
activeValue: string;
99
buildHref: (path: string) => string;
1010
registerTab: (tab: NavigationTab) => void;
11+
staticPaths: Set<string>;
1112
unregisterTab: (path: string) => void;
1213
};
1314

app/entities/navigation-tabs/ui/BaseNavigationTabs.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,17 @@ export function BaseNavigationTabs({
2727
}: BaseNavigationTabsProps) {
2828
const { registeredTabs, registerTab, unregisterTab } = useTabRegistration();
2929

30+
const staticPaths = React.useMemo(() => new Set(tabs.map(t => t.path)), [tabs]);
31+
3032
const contextValue = React.useMemo(
31-
() => ({ activeValue, buildHref, registerTab, unregisterTab }),
32-
[activeValue, buildHref, registerTab, unregisterTab]
33+
() => ({ activeValue, buildHref, registerTab, staticPaths, unregisterTab }),
34+
[activeValue, buildHref, registerTab, staticPaths, unregisterTab]
3335
);
3436

35-
const allTabs = React.useMemo(() => {
36-
const staticPaths = new Set(tabs.map(t => t.path));
37-
return [...tabs, ...registeredTabs.filter(t => !staticPaths.has(t.path))];
38-
}, [tabs, registeredTabs]);
37+
const allTabs = React.useMemo(
38+
() => [...tabs, ...registeredTabs.filter(t => !staticPaths.has(t.path))],
39+
[tabs, registeredTabs, staticPaths]
40+
);
3941

4042
return (
4143
<NavigationTabsContext.Provider value={contextValue}>

app/entities/navigation-tabs/ui/NavigationTabLink.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ export function NavigationTabLink({ path, title, className }: { path: string; ti
1616
// eslint-disable-next-line react-hooks/exhaustive-deps
1717
}, [path, title]);
1818

19+
if (ctx.staticPaths.has(path)) return null;
20+
1921
return <TabLink path={path} title={title} className={className} />;
2022
}

app/entities/navigation-tabs/ui/__stories__/navigation-tabs.stories.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ export const OverlappingAsyncTabs: Story = {
118118
const tablist = canvas.getByRole('tablist', { hidden: true });
119119
const tabs = within(tablist).getAllByRole('tab', { hidden: true });
120120

121-
// Desktop tablist: 4 static + 2 children rendered (both appear in DOM)
122-
expect(tabs).toHaveLength(6);
121+
// Desktop tablist: 4 static + 1 new (overlapping "rewards" is deduplicated)
122+
expect(tabs).toHaveLength(5);
123123

124124
// Mobile select: should deduplicate "rewards", so 4 static + 1 new = 5
125125
const select = canvasElement.querySelector('select') as HTMLSelectElement;

0 commit comments

Comments
 (0)