Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/react-router-devtools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "react-router-devtools",
"description": "Devtools for React Router - debug, trace, find hydration errors, catch bugs and inspect server/client data with react-router-devtools",
"author": "Alem Tuzlak",
"version": "6.1.0",
"version": "6.2.0",
"license": "MIT",
"keywords": [
"react-router",
Expand Down Expand Up @@ -131,6 +131,7 @@
"@babel/traverse": "^7.28.5",
"@babel/types": "^7.28.5",
"@radix-ui/react-accordion": "^1.2.12",
"@tanstack/devtools-client": "^0.0.5",
"@tanstack/devtools-event-client": "^0.4.0",
"@tanstack/devtools-vite": "^0.4.1",
"@tanstack/react-devtools": "^0.9.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { memo } from "react"
import { useStyles } from "../styles/use-styles.js"

interface TabContentProps {
children: React.ReactNode
}

export const TabContent = ({ children }: TabContentProps) => {
export const TabContent = memo(({ children }: TabContentProps) => {
const { styles } = useStyles()
return <div className={styles.tabContent.container}>{children}</div>
}
})
6 changes: 3 additions & 3 deletions packages/react-router-devtools/src/client/components/Tag.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ReactNode } from "react"
import { type ReactNode, memo } from "react"
import { cx, useStyles } from "../styles/use-styles.js"

export const TAG_COLORS = {
Expand All @@ -16,7 +16,7 @@ interface TagProps {
size?: "small" | "default"
}

const Tag = ({ color, children, className, size = "default" }: TagProps) => {
const Tag = memo(({ color, children, className, size = "default" }: TagProps) => {
const { styles } = useStyles()
return (
<span
Expand All @@ -30,6 +30,6 @@ const Tag = ({ color, children, className, size = "default" }: TagProps) => {
{children}
</span>
)
}
})

export { Tag }
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SVGProps } from "react"
import { type SVGProps, memo } from "react"
import { cx } from "../../styles/use-styles.js"
import { useStyles } from "../../styles/use-styles.js"
import type { IconName } from "./icons/types.js"
Expand Down Expand Up @@ -30,7 +30,7 @@ const strokeIcon: Partial<IconName>[] = []
* Icon component wrapper for SVG icons.
* @returns SVG icon as a react component
*/
export const Icon = ({ name, title, testId, className, size = "sm", ...props }: IconProps) => {
export const Icon = memo(({ name, title, testId, className, size = "sm", ...props }: IconProps) => {
const { styles } = useStyles()
const iconSize = IconSize[size]
const isEmptyFill = emptyFill.includes(name)
Expand Down Expand Up @@ -316,4 +316,4 @@ export const Icon = ({ name, title, testId, className, size = "sm", ...props }:
<use href={`#${name}`} />
</svg>
)
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const isPromise = (value: any): value is Promise<any> => {
return value && typeof value.then === "function"
}

const JsonRendererComponent = ({ data, expansionLevel }: JsonRendererProps) => {
const JsonRendererComponent = memo(({ data, expansionLevel }: JsonRendererProps) => {
const { styles } = useStyles()
const { settings } = useSettingsContext()
const ref = useRef(true)
Expand Down Expand Up @@ -71,7 +71,7 @@ const JsonRendererComponent = ({ data, expansionLevel }: JsonRendererProps) => {
return (
<JsonView highlightUpdates style={customTheme} collapsed={expansionLevel ?? settings.expansionLevel} value={json} />
)
}
})

const JsonRenderer = memo(JsonRendererComponent)

Expand Down
25 changes: 17 additions & 8 deletions packages/react-router-devtools/src/client/embedded-dev-tools.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import clsx from "clsx"
import { useEffect, useState } from "react"
import { memo, useEffect, useState } from "react"
import { RDTContextProvider } from "./context/RDTContext.js"
import { useFindRouteOutlets } from "./hooks/useReactTreeListeners.js"
import { useSetRouteBoundaries } from "./hooks/useSetRouteBoundaries.js"
Expand All @@ -10,18 +10,25 @@ import { Tabs } from "./layout/Tabs.js"
import type { ReactRouterDevtoolsProps } from "./react-router-dev-tools.js"
// Import to ensure global reset styles are injected
import "./styles/use-styles.js"
import { devtoolsEventClient } from "@tanstack/devtools-client"
import { RequestProvider } from "./context/requests/request-context.js"
import { REACT_ROUTER_DEV_TOOLS } from "./utils/storage.js"

export interface EmbeddedDevToolsProps extends ReactRouterDevtoolsProps {
mainPanelClassName?: string
className?: string
}
const Embedded = ({ mainPanelClassName, className }: EmbeddedDevToolsProps) => {
const Embedded = memo(({ mainPanelClassName, className }: EmbeddedDevToolsProps) => {
useTimelineHandler()
useFindRouteOutlets()
useSetRouteBoundaries()

const [isOpen, setIsOpen] = useState(true)
useEffect(() => {
const cleanup = devtoolsEventClient.on("trigger-toggled", (e) => {
setIsOpen(e.payload.isOpen)
})
return cleanup
}, [])
return (
<div
id={REACT_ROUTER_DEV_TOOLS}
Expand All @@ -30,13 +37,15 @@ const Embedded = ({ mainPanelClassName, className }: EmbeddedDevToolsProps) => {
}}
className={clsx("react-router-dev-tools", "h-full flex-row w-full", className)}
>
<MainPanel className={mainPanelClassName} isEmbedded isOpen={true}>
<Tabs />
<ContentPanel />
</MainPanel>
{isOpen ? (
<MainPanel className={mainPanelClassName} isEmbedded isOpen={true}>
<Tabs />
<ContentPanel />
</MainPanel>
) : null}
</div>
)
}
})

let hydrating = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function useFindRouteOutlets() {
const styleNearestElement = useCallback((fiberNode: any) => {
if (!fiberNode) return

if (fiberNode.stateNode) {
if (typeof fiberNode?.stateNode?.classList?.add === "function") {
return fiberNode.stateNode.classList.add(ROUTE_CLASS)
}
styleNearestElement(fiberNode.child)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Fragment } from "react"
import { Fragment, memo } from "react"
import { useTabs } from "../hooks/useTabs.js"
import { cx } from "../styles/use-styles.js"
import { useStyles } from "../styles/use-styles.js"
import { TimelineTab } from "../tabs/TimelineTab.js"

const ContentPanel = () => {
const ContentPanel = memo(() => {
const { Component, hideTimeline, activeTab } = useTabs()
const { styles } = useStyles()

Expand All @@ -29,6 +29,6 @@ const ContentPanel = () => {
)}
</div>
)
}
})

export { ContentPanel }
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { memo } from "react"
import { cx } from "../styles/use-styles.js"
import { useStyles } from "../styles/use-styles.js"

Expand All @@ -8,7 +9,7 @@ interface MainPanelProps {
className?: string
}

const MainPanel = ({ children, isOpen, className }: MainPanelProps) => {
const MainPanel = memo(({ children, isOpen, className }: MainPanelProps) => {
const { styles } = useStyles()

return (
Expand All @@ -26,6 +27,6 @@ const MainPanel = ({ children, isOpen, className }: MainPanelProps) => {
{children}
</div>
)
}
})

export { MainPanel }
67 changes: 35 additions & 32 deletions packages/react-router-devtools/src/client/layout/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { memo } from "react"
import { useSettingsContext } from "../context/useRDTContext.js"
import { useHorizontalScroll } from "../hooks/useHorizontalScroll.js"
import { useTabs } from "../hooks/useTabs.js"
Expand All @@ -11,39 +12,41 @@ declare global {
}
}

const Tab = ({
tab,
activeTab,
className,
onClick,
}: {
tab: TabType
activeTab?: string
className?: string
onClick?: () => void
}) => {
const { setSettings } = useSettingsContext()
const { styles } = useStyles()
const Tab = memo(
({
tab,
activeTab,
className,
onClick,
}: {
tab: TabType
activeTab?: string
className?: string
onClick?: () => void
}) => {
const { setSettings } = useSettingsContext()
const { styles } = useStyles()

return (
<button
data-testid={tab.id}
onClick={() => (onClick ? onClick() : setSettings({ activeTab: tab.id as TabsType }))}
title={typeof tab.name === "string" ? tab.name : undefined}
type="button"
className={cx(
"group",
styles.layout.tabs.tab,
activeTab !== tab.id && styles.layout.tabs.tabInactive,
activeTab === tab.id && styles.layout.tabs.tabActive
)}
>
<div className={cx(className, styles.layout.tabs.tabIcon)}>{tab.icon}</div>
</button>
)
}
return (
<button
data-testid={tab.id}
onClick={() => (onClick ? onClick() : setSettings({ activeTab: tab.id as TabsType }))}
title={typeof tab.name === "string" ? tab.name : undefined}
type="button"
className={cx(
"group",
styles.layout.tabs.tab,
activeTab !== tab.id && styles.layout.tabs.tabInactive,
activeTab === tab.id && styles.layout.tabs.tabActive
)}
>
<div className={cx(className, styles.layout.tabs.tabIcon)}>{tab.icon}</div>
</button>
)
}
)

const Tabs = () => {
const Tabs = memo(() => {
const { settings } = useSettingsContext()
const { styles } = useStyles()
const { activeTab } = settings
Expand All @@ -59,6 +62,6 @@ const Tabs = () => {
</div>
</div>
)
}
})

export { Tabs }
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { useStyles } from "../styles/use-styles.js"
export const NetworkTab = () => {
const { styles } = useStyles()
const { requests, removeAllRequests, isLimitReached } = useRequestContext()

return (
<div className={styles.networkTab.wrapper}>
<TabHeader
Expand Down
2 changes: 1 addition & 1 deletion packages/react-router-devtools/src/client/tabs/PageTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const PageTab = () => {
const { revalidate, state } = useRevalidator()

// Memoize reversed routes to avoid creating new array on every render
const reversedRoutes = useMemo(() => routes.toReversed(), [routes])
const reversedRoutes = useMemo(() => [...routes.toReversed()], [routes])

return (
<>
Expand Down
6 changes: 2 additions & 4 deletions packages/react-router-devtools/src/client/tabs/RoutesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const RoutesTab = () => {
}

// Add root from manifest
routeObject.root = window.__reactRouterManifest?.routes?.root
routeObject.root = { ...window.__reactRouterManifest?.routes?.root }

// Update tree view routes with merged data
setTreeRoutes(createRouteTree(routeObject))
Expand All @@ -63,9 +63,7 @@ const RoutesTab = () => {
// Request routes info from the server AFTER listener is set up
eventClient.emit("routes-tab-mounted", {})

return () => {
unsubscribe()
}
return unsubscribe
}, [])
return (
<div className={styles.routesTab.wrapper}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { memo } from "react"
import { TabContent } from "../components/TabContent.js"
import { TabHeader } from "../components/TabHeader.js"
import { type TAG_COLORS, Tag } from "../components/Tag.js"
Expand All @@ -17,7 +18,7 @@ const Translations: Record<TimelineEvent["type"], string> = {
FETCHER_RESPONSE: "Fetcher action response",
}

const RedirectEventComponent = (event: RedirectEvent) => {
const RedirectEventComponent = memo((event: RedirectEvent) => {
const { styles } = useStyles()
return (
<div className={styles.timelineTab.eventContainer}>
Expand All @@ -31,9 +32,9 @@ const RedirectEventComponent = (event: RedirectEvent) => {
)}
</div>
)
}
})

const FormEventComponent = (event: FormEvent) => {
const FormEventComponent = memo((event: FormEvent) => {
const { styles } = useStyles()
const isRedirect = event.type === "ACTION_REDIRECT"
const responseData = event.responseData
Expand Down Expand Up @@ -73,7 +74,7 @@ const FormEventComponent = (event: FormEvent) => {
</div>
</div>
)
}
})

export const METHOD_COLORS: Record<string, keyof typeof TAG_COLORS> = {
GET: "GREEN",
Expand Down
6 changes: 3 additions & 3 deletions packages/react-router-devtools/src/client/tabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@ export const tabs = [
name: "Active page",
icon: <Icon size="md" name="Layers" />,
id: "page",
component: PageTab,
component: () => <PageTab />,
hideTimeline: false,
},
{
name: "Routes",
icon: <Icon size="md" name="GitMerge" />,
id: "routes",
component: RoutesTab,
component: () => <RoutesTab />,
hideTimeline: false,
},
{
name: "Network",
icon: <Icon size="md" name="Network" />,
id: "network",
component: NetworkTab,
component: () => <NetworkTab />,

hideTimeline: true,
},
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading