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
1 change: 0 additions & 1 deletion docs/app/components/ui/Sparkles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ export const SparklesCore = (props: ParticlesProps) => {

const particlesLoaded = async (container?: Container) => {
if (container) {
console.log(container)
controls.start({
opacity: 1,
transition: {
Expand Down
56 changes: 43 additions & 13 deletions package-lock.json

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

12 changes: 6 additions & 6 deletions 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": "1.1.10",
"version": "5.0.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this change intentional?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes,it was a mistake to start over from v1 on react-router-devtools as most of the v2-v4 version range was taken by remix-development-tools on this repo so I moved it to 5 to allow for easier releases

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @AlemTuzlak!

Thank you for confirming this information. We're in the process of upgrading to the latest version and noticed this represents a significant version jump. I was interested in understanding the rationale behind this major bump from 1.x to 5.x.

Is this transition documented somewhere? It would be valuable to share this context with customers and users who are planning similar upgrades to ensure a smooth transition.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fkoner sorry I missed this comment, the reason behind it is that this repo used to be remix-development-tools which has a lot of existing releases in the 2-4 range so I decided to skip to 5 so I don't break releases due to duplicate versions. I should've started from the beginning with v5

"license": "MIT",
"keywords": [
"react-router",
Expand All @@ -19,7 +19,6 @@
],
"private": false,
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
Expand Down Expand Up @@ -105,6 +104,8 @@
"peerDependencies": {
"react": ">=17",
"react-dom": ">=17",
"@types/react": ">=17",
"@types/react-dom": ">=17",
"react-router": ">=7.0.0",
"vite": ">=5.0.0 || >=6.0.0"
},
Expand All @@ -118,8 +119,6 @@
"@types/babel__core": "^7.20.5",
"@types/beautify": "^0.0.3",
"@types/node": "^22.12.0",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"@vitest/coverage-v8": "^3.0.4",
"@vitest/ui": "^3.0.4",
"autoprefixer": "^10.4.20",
Expand All @@ -132,13 +131,13 @@
"npm-run-all": "^4.1.5",
"postcss": "^8.5.1",
"prompt": "^1.3.0",
"tailwind-merge": "^3.0.1",
"tailwindcss": "^3.4.0",
"tailwindcss-animate": "^1.0.7",
"tsup": "^8.3.6",
"tsx": "^4.19.2",
"typescript": "^5.7.3",
"vite": "^6.0.11",
"vite-node": "^3.1.2",
"vitest": "^3.0.4"
},
"dependencies": {
Expand All @@ -158,7 +157,8 @@
"react-d3-tree": "^3.6.4",
"react-diff-viewer-continued": "^4.0.5",
"react-hotkeys-hook": "^4.6.1",
"react-tooltip": "^5.28.0"
"react-tooltip": "^5.28.0",
"tailwind-merge": "^3.0.1"
},
"optionalDependencies": {
"@biomejs/cli-darwin-arm64": "^1.9.4",
Expand Down
35 changes: 22 additions & 13 deletions src/client/components/RouteInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { MouseEvent } from "react"
import { Link } from "react-router"
import { useSettingsContext } from "../context/useRDTContext.js"
import { type ExtendedRoute, constructRoutePath } from "../utils/routing.js"
import { findParentErrorBoundary } from "../utils/sanitize.js"
import { Input } from "./Input.js"
import { Tag } from "./Tag.js"
import { Icon } from "./icon/Icon.js"
Expand All @@ -14,39 +15,49 @@ interface RouteInfoProps {
onClose?: () => void
}

export const RouteInfo = ({ route, className, openNewRoute, onClose }: RouteInfoProps) => {
export const RouteInfo = ({ route: routeToUse, className, openNewRoute, onClose }: RouteInfoProps) => {
const route = window.__reactRouterManifest?.routes[routeToUse.id] || routeToUse
const { settings, setSettings } = useSettingsContext()
const { routeWildcards, routeViewMode } = settings
const { hasWildcard, path, pathToOpen } = constructRoutePath(route, routeWildcards)
const { hasWildcard, path, pathToOpen } = constructRoutePath(routeToUse, routeWildcards)
const isTreeView = routeViewMode === "tree"
const hasParentErrorBoundary = route.errorBoundary.errorBoundaryId && route.errorBoundary.errorBoundaryId !== route.id
const hasErrorBoundary = route.errorBoundary.hasErrorBoundary
const { hasErrorBoundary, errorBoundaryId } = findParentErrorBoundary(route)
const hasParentErrorBoundary = errorBoundaryId && errorBoundaryId !== route.id

return (
<div className={clsx(className, "relative")}>
{isTreeView && (
<>
<Icon onClick={onClose} className="absolute right-2 top-2 cursor-pointer text-red-600" name="X" />

<h1 className="text-xl font-semibold">{route.url}</h1>
<h1 className="text-xl text-white font-semibold">{routeToUse.url}</h1>
<hr className="mb-4 mt-1" />
<h3>
<span className="text-gray-500">Path:</span> {path}
<span className="text-gray-500">Path:</span>
<span className="text-white"> {path}</span>
</h3>
<h3>
<span className="text-gray-500">Url:</span> {pathToOpen}
<span className="text-gray-500">Url:</span> <span className="text-white">{pathToOpen}</span>
</h3>
</>
)}
<div className="flex gap-2">
<span className="whitespace-nowrap text-gray-500">Route file:</span>
{route.id}
{route.module ?? routeToUse.file}
</div>

<div className="mb-4 mt-4 flex flex-col gap-2">
<span className="text-gray-500">Components contained in the route:</span>
<div className="flex gap-2">
<div className="flex flex-wrap gap-2">
<Tag className="h-max" color={route.hasLoader ? "GREEN" : "RED"}>
Loader
</Tag>
<Tag className="h-max" color={route.hasClientLoader ? "GREEN" : "RED"}>
Client Loader
</Tag>
<Tag className="h-max" color={route.hasClientAction ? "GREEN" : "RED"}>
Client Action
</Tag>
<Tag className="h-max" color={route.hasAction ? "GREEN" : "RED"}>
Action
</Tag>
Expand All @@ -60,17 +71,15 @@ export const RouteInfo = ({ route, className, openNewRoute, onClose }: RouteInfo
</div>
{hasErrorBoundary ? (
<div className="mr-2">
{hasParentErrorBoundary
? `Covered by parent ErrorBoundary located in: ${route.errorBoundary.errorBoundaryId}`
: ""}
{hasParentErrorBoundary ? `Covered by parent ErrorBoundary located in: ${errorBoundaryId}` : ""}
</div>
) : null}
</div>
{hasWildcard && (
<>
<p className="mb-2 text-gray-500">Wildcard parameters:</p>
<div className={clsx("mb-4 grid w-full grid-cols-2 gap-2", isTreeView && "grid-cols-1")}>
{route.url
{routeToUse.url
.split("/")
.filter((p) => p.startsWith(":"))
.map((param) => (
Expand Down
30 changes: 27 additions & 3 deletions src/client/tabs/RoutesTab.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type MouseEvent, useState } from "react"
import { type MouseEvent, useEffect, useState } from "react"
import { useMatches, useNavigate } from "react-router"
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../components/Accordion.js"
import { NewRouteForm } from "../components/NewRouteForm.js"
Expand All @@ -22,7 +22,7 @@ const RoutesTab = () => {
const { detachedWindow } = useDetachedWindowControls()
const [activeRoute, setActiveRoute] = useState<ExtendedRoute | null>(null)
const [routes] = useState<ExtendedRoute[]>(createExtendedRoutes() as ExtendedRoute[])
const [treeRoutes] = useState(createRouteTree(window.__reactRouterManifest?.routes))
const [treeRoutes, setTreeRoutes] = useState(createRouteTree(window.__reactRouterManifest?.routes))
const isTreeView = routeViewMode === "tree"
const openNewRoute = (path: string) => (e?: MouseEvent<HTMLDivElement | HTMLButtonElement>) => {
e?.preventDefault()
Expand All @@ -32,6 +32,26 @@ const RoutesTab = () => {
}
}

useEffect(function fetchAllRoutesOnMount() {
import.meta.hot?.send("routes-info")
const cb = (event: any) => {
const parsed = JSON.parse(event)
const data = parsed.data as Record<string, any>[]

const routeObject: Record<string, any> = {}
for (const route of data) {
routeObject[route.id] = route
}

routeObject.root = window.__reactRouterManifest?.routes?.root

setTreeRoutes(createRouteTree(routeObject))
}
import.meta.hot?.on("routes-info", cb)
return () => {
import.meta.hot?.off("routes-info", cb)
}
}, [])
return (
<div className={clsx("relative h-full w-full ", !isTreeView && "pt-8")}>
<RouteToggle />
Expand All @@ -40,7 +60,11 @@ const RoutesTab = () => {
<Tree
translate={{ x: window.innerWidth / 2 - (isTreeView && activeRoute ? 0 : 0), y: 30 }}
pathClassFunc={(link) =>
activeRoutes.includes((link.target.data.attributes as any).id) ? "stroke-yellow-500" : "stroke-gray-400"
activeRoutes.includes((link.target.data.attributes as any).id)
? "stroke-yellow-500"
: window.__reactRouterManifest?.routes?.[link.target.data.attributes.id]
? "stroke-gray-400"
: "stroke-gray-400/20"
}
renderCustomNodeElement={(props) =>
RouteNode({
Expand Down
22 changes: 16 additions & 6 deletions src/client/utils/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,29 @@ const ROUTE_FILLS = {
PURPLE: "fill-purple-500 text-white",
} as const

const UNDISCOVERED_ROUTE_FILLS = {
GREEN: "fill-green-500/20 text-white",
BLUE: "fill-blue-500/20 text-white",
PURPLE: "fill-purple-500/20 text-white",
}

export function getRouteColor(route: Route) {
const isDiscovered = !!window.__reactRouterManifest?.routes[route.id]
const FILL = isDiscovered ? ROUTE_FILLS : UNDISCOVERED_ROUTE_FILLS
switch (getRouteType(route)) {
case "ROOT":
return ROUTE_FILLS.PURPLE
case "LAYOUT":
return ROUTE_FILLS.BLUE
return FILL.PURPLE

case "ROUTE":
return ROUTE_FILLS.GREEN
return FILL.GREEN

case "LAYOUT":
return FILL.BLUE
}
}
export type ExtendedRoute = EntryRoute & {
url: string
file?: string
errorBoundary: { hasErrorBoundary: boolean; errorBoundaryId: string | null }
}

Expand Down Expand Up @@ -89,8 +100,7 @@ export const createExtendedRoutes = () => {
...route,
// biome-ignore lint/style/noNonNullAssertion: <explanation>
url: convertReactRouterPathToUrl(window.__reactRouterManifest!.routes, route),
// biome-ignore lint/style/noNonNullAssertion: <explanation>
errorBoundary: findParentErrorBoundary(window.__reactRouterManifest!.routes, route),
errorBoundary: findParentErrorBoundary(route),
}
})
.filter((route) => isLeafRoute(route as any))
Expand Down
Loading
Loading