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

Commit 4df2753

Browse files
committed
fix(ui): use state-driven isExtension flag instead of runtime isBrowser check
The isBrowser + window.__QWIK_DEVTOOLS_DATA_PROVIDER__ check inside component$ was unreliable in Qwik's rendering model, leaving Vite-only tabs visible in extension mode. Replaced with an isExtension flag set at state creation time so it is available from the very first render. Also removed the unused disabled prop from Tab.
1 parent 97fafcc commit 4df2753

6 files changed

Lines changed: 18 additions & 21 deletions

File tree

packages/ui/src/components/Tab/Tab.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,24 @@ interface TabProps {
55
state: State;
66
id: TabName;
77
title: string;
8-
disabled?: boolean;
98
}
109

11-
export const Tab = component$<TabProps>(({ state, id, title, disabled }) => {
10+
export const Tab = component$<TabProps>(({ state, id, title }) => {
1211
const isActive = state.activeTab === id;
1312

1413
return (
1514
<button
1615
onClick$={() => {
17-
if (!disabled) state.activeTab = id;
16+
state.activeTab = id;
1817
}}
19-
title={disabled ? `${title} (overlay only)` : title}
18+
title={title}
2019
class={[
2120
'relative flex h-11 w-11 items-center justify-center rounded-xl transition-all duration-300 ease-out select-none',
22-
disabled
23-
? 'text-muted-foreground/30 cursor-not-allowed'
24-
: isActive
25-
? 'bg-primary/15 text-primary cursor-pointer'
26-
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground cursor-pointer',
21+
isActive
22+
? 'bg-primary/15 text-primary cursor-pointer'
23+
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground cursor-pointer',
2724
]}
28-
style={isActive && !disabled ? { boxShadow: 'inset 3px 0 0 0 var(--color-primary)' } : {}}
25+
style={isActive ? { boxShadow: 'inset 3px 0 0 0 var(--color-primary)' } : {}}
2926
>
3027
<Slot />
3128
</button>

packages/ui/src/devtools/DevtoolsContent.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { component$, isBrowser } from '@qwik.dev/core';
1+
import { component$ } from '@qwik.dev/core';
22
import type { AssetInfo } from '@devtools/kit';
33
import { IconMonitor } from '../components/Icons/Icons';
44
import { TabContent } from '../components/TabContent/TabContent';
@@ -50,8 +50,7 @@ const ViteOnlyPlaceholder = component$<{ feature: string }>(({ feature }) => {
5050
});
5151

5252
export const DevtoolsContent = component$<DevtoolsContentProps>(({ state }) => {
53-
const isExtensionMode =
54-
isBrowser && !!window.__QWIK_DEVTOOLS_DATA_PROVIDER__;
53+
const isExtensionMode = state.isExtension;
5554
const assetSummary = formatAssetSummary(state.assets);
5655

5756
switch (state.activeTab) {

packages/ui/src/devtools/DevtoolsSidebar.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { component$, isBrowser } from '@qwik.dev/core';
1+
import { component$ } from '@qwik.dev/core';
22
import { Tab } from '../components/Tab/Tab';
33
import { QwikThemeToggle } from '../components/ThemeToggle/QwikThemeToggle';
44
import type { DevtoolsState } from './state';
@@ -9,12 +9,10 @@ interface DevtoolsSidebarProps {
99
}
1010

1111
export const DevtoolsSidebar = component$<DevtoolsSidebarProps>(({ state }) => {
12-
const isExtension = isBrowser && !!window.__QWIK_DEVTOOLS_DATA_PROVIDER__;
13-
1412
return (
1513
<div class="glass-bg border-r border-glass-border shadow-r flex h-full w-16 flex-col items-center justify-start gap-3 p-3 md:w-20">
1614
{devtoolsTabs
17-
.filter((tab) => !(isExtension && tab.viteOnly))
15+
.filter((tab) => !(state.isExtension && tab.viteOnly))
1816
.map((tab) => (
1917
<Tab
2018
key={tab.id}

packages/ui/src/devtools/QwikDevtoolsExtension.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { DevtoolsSidebar } from './DevtoolsSidebar';
1717
* It must be a separate element so descendant selectors match.
1818
*/
1919
export const QwikDevtoolsExtension = component$(() => {
20-
const state = useStore<DevtoolsState>(createDevtoolsState());
20+
const state = useStore<DevtoolsState>(createDevtoolsState({ isExtension: true }));
2121

2222
useVisibleTask$(async () => {
2323
await loadDevtoolsData(state);

packages/ui/src/devtools/state.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ export interface DevtoolsState {
3434
lastPanelBounds: DevtoolsPanelBounds | null;
3535
/** Whether the Vite devtools plugin overlay is also active on the page. */
3636
vitePluginDetected?: boolean;
37+
/** True when running inside the browser extension panel (no Vite server). */
38+
isExtension: boolean;
3739
}
3840

39-
export function createDevtoolsState(): DevtoolsState {
41+
export function createDevtoolsState(opts?: { isExtension?: boolean }): DevtoolsState {
4042
return {
4143
isOpen: false,
4244
isPanelFullscreen: false,
@@ -54,5 +56,6 @@ export function createDevtoolsState(): DevtoolsState {
5456
height: 0,
5557
},
5658
lastPanelBounds: null,
59+
isExtension: opts?.isExtension ?? false,
5760
};
5861
}

packages/ui/src/features/Overview/Overview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { $, component$, isBrowser, sync$ } from '@qwik.dev/core';
1+
import { $, component$, sync$ } from '@qwik.dev/core';
22
import {
33
IconCubeOutline,
44
IconFolderTree,
@@ -12,7 +12,7 @@ interface OverviewProps {
1212
}
1313

1414
export const Overview = component$(({ state }: OverviewProps) => {
15-
const isExtension = isBrowser && !!window.__QWIK_DEVTOOLS_DATA_PROVIDER__;
15+
const isExtension = state.isExtension;
1616
const pageJump = $((pageName: TabName) => {
1717
state.activeTab = pageName;
1818
});

0 commit comments

Comments
 (0)