Skip to content

Commit 08230d3

Browse files
committed
Version 1.1.2
1 parent aad4ae0 commit 08230d3

16 files changed

Lines changed: 382 additions & 57 deletions

File tree

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The **Active Page** tab in Remix Development Tools allows you to gain insights i
1717
- **URL Parameters**: Easily view and analyze the URL parameters associated with the current page.
1818
- **Server Responses**: Inspect and review the server responses received by the application for the current page.
1919
- **Loader Data**: Monitor and track the loader data used by the application during page rendering.
20+
- **Outlet boundaries** Activate the **Show Route Boundaries** option to see each Outlet and route boundaries by coloring the background.
2021

2122
### Routes Tab
2223

@@ -86,16 +87,20 @@ The `RemixDevTools` component accepts the following props:
8687

8788
- `port`: The port number to use for the Remix Development Tools connection to Remix Forge. If you want to change the port and connect to your Remix Forge VS code extension you need to change the port in VS Code too. Defaults to `3003`.
8889
- `defaultOpen`: Whether to open the Remix Development Tools by default. Defaults to `false`.
90+
- `position`: The position of the Remix Development Tools trigger. Defaults to `bottom-right`.
91+
- `requireUrlFlag`: Requires rdt=true to be present in the URL search to open the Remix Development Tools. Defaults to `false`.
92+
- `showRouteBoundaries`: Allows you to see each Outlet and route boundaries by coloring the background. Defaults to `false`.
8993

9094
## Contributing
9195

9296
Contributions to Remix Development Tools are welcome! To contribute, please follow these guidelines:
9397

9498
1. Fork the repository and clone it locally.
9599
2. Create a new branch for your feature or bug fix.
96-
3. Run `npm install` to get your development environment set up.
100+
3. Run `npm run setup` to get your development environment set up.
97101
4. Run `npm run dev` to start the development server.
98102
5. Implement your changes, adhering to the existing code style and best practices.
103+
5. Please add tests for any new features or bug fixes.
99104
6. Commit and push your changes to your forked repository.
100105
7. Open a pull request, providing a clear description of your changes and their purpose.
101106

@@ -114,3 +119,5 @@ Remix Development Tools was inspired by the Remix framework and aims to enhance
114119
---
115120

116121
Feel free to explore Remix Development Tools, and we hope it significantly improves your Remix development process. If you encounter any issues or have suggestions for enhancements, please don't hesitate to open an issue on our GitHub repository. Happy Remixing!
122+
123+

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "remix-development-tools",
33
"description": "Remix development tools.",
44
"author": "Alem Tuzlak",
5-
"version": "1.1.0",
5+
"version": "1.1.2",
66
"license": "MIT",
77
"keywords": [
88
"remix",

src/RemixDevTools/RemixDevTools.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import clsx from "clsx";
22
import { Logo } from "./components/Logo";
3-
import { useEffect, useState } from "react";
3+
import React, { useEffect, useState } from "react";
44
import { RDTContextProvider } from "./context/RDTContext";
55
import { tabs } from "./tabs";
66
import { useTimelineHandler } from "./hooks/useTimelineHandler";
@@ -10,16 +10,11 @@ import { useGetSocket } from "./hooks/useGetSocket";
1010
import { Radio } from "lucide-react";
1111
import { useResize } from "./hooks/useResize";
1212
import { useLocation } from "@remix-run/react";
13+
import { useOutletAugment } from "./hooks/useOutletAugment";
1314

14-
interface Props {
15-
position:
16-
| "bottom-right"
17-
| "bottom-left"
18-
| "top-right"
19-
| "top-left"
20-
| "middle-right"
21-
| "middle-left";
15+
interface Props extends RemixDevToolsProps {
2216
defaultOpen: boolean;
17+
position: Exclude<RemixDevToolsProps["position"], undefined>;
2318
}
2419

2520
const RemixDevTools = ({ defaultOpen, position }: Props) => {
@@ -157,23 +152,33 @@ interface RemixDevToolsProps {
157152
// Whether the dev tools require a url flag to be shown
158153
requireUrlFlag?: boolean;
159154
// Set the position of the trigger button
160-
position?: Props["position"];
155+
position?:
156+
| "bottom-right"
157+
| "bottom-left"
158+
| "top-right"
159+
| "top-left"
160+
| "middle-right"
161+
| "middle-left";
162+
// Show route boundaries when you hover over a route in active page tab
163+
showRouteBoundaries?: boolean;
161164
}
162165

163166
const RDTWithContext = ({
164167
port = 3003,
165168
defaultOpen = false,
166169
requireUrlFlag,
170+
showRouteBoundaries = false,
167171
position = "bottom-right",
168172
}: RemixDevToolsProps) => {
169173
const hydrated = useHydrated();
170174
const isDevelopment = isDev();
171175
const url = useLocation().search;
176+
useOutletAugment(showRouteBoundaries);
172177

173178
if (!hydrated || !isDevelopment) return null;
174179
if (requireUrlFlag && !url.includes("rdt=true")) return null;
175180
return (
176-
<RDTContextProvider port={port}>
181+
<RDTContextProvider showRouteBoundaries={showRouteBoundaries} port={port}>
177182
<RemixDevTools position={position} defaultOpen={defaultOpen} />
178183
</RDTContextProvider>
179184
);

src/RemixDevTools/context/RDTContext.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,23 @@ RDTContext.displayName = "RDTContext";
1717
interface ContextProps {
1818
children: React.ReactNode;
1919
port: number;
20+
showRouteBoundaries?: boolean;
2021
}
2122

2223
export const REMIX_DEV_TOOLS = "remixDevTools";
2324

24-
export const RDTContextProvider = ({ children, port }: ContextProps) => {
25+
export const RDTContextProvider = ({
26+
children,
27+
port,
28+
showRouteBoundaries,
29+
}: ContextProps) => {
2530
const existingState = sessionStorage.getItem(REMIX_DEV_TOOLS);
2631
const settings = localStorage.getItem(REMIX_DEV_TOOLS);
2732

2833
const [state, dispatch] = useReducer(rdtReducer, {
2934
...initialState,
3035
...(existingState ? JSON.parse(existingState) : {}),
36+
showRouteBoundaries,
3137
settings: settings
3238
? { ...initialState.settings, ...JSON.parse(settings), port }
3339
: { ...initialState.settings, port },

src/RemixDevTools/context/rdtReducer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export type RouteWildcards = Record<string, Record<string, string> | undefined>;
55

66
export type RemixDevToolsState = {
77
timeline: TimelineEvent[];
8+
showRouteBoundaries?: boolean;
89
settings: {
910
routeWildcards: RouteWildcards;
1011
activeTab: Tabs;
@@ -16,6 +17,7 @@ export type RemixDevToolsState = {
1617

1718
export const initialState: RemixDevToolsState = {
1819
timeline: [],
20+
showRouteBoundaries: false,
1921
settings: {
2022
routeWildcards: {},
2123
activeTab: "timeline",

src/RemixDevTools/context/useRDTContext.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const useRDTContext = () => {
1010
throw new Error("useRDTContext must be used within a RDTContextProvider");
1111
}
1212
const { state, dispatch } = context;
13-
const { timeline, settings } = state;
13+
const { timeline, settings, showRouteBoundaries } = state;
1414
const { activeTab, shouldConnectWithForge, routeWildcards, port, height } =
1515
settings;
1616

@@ -76,6 +76,7 @@ const useRDTContext = () => {
7676
routeWildcards,
7777
port,
7878
height,
79+
showRouteBoundaries,
7980
setHeight,
8081
setRouteWildcards,
8182
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { useSubmit, useLocation } from "@remix-run/react";
2+
import clsx from "clsx";
3+
import { useEffect } from "react";
4+
5+
const isHooked = Symbol("isHooked");
6+
export function useOutletAugment(shouldAugment: boolean) {
7+
const submit = useSubmit();
8+
const location = useLocation();
9+
useEffect(() => {
10+
if (!shouldAugment) return;
11+
if (window.__remixRouteModules[isHooked as any]) return;
12+
13+
window.__remixRouteModules = new Proxy(window.__remixRouteModules, {
14+
get: function (target, property) {
15+
if (property === isHooked) return target[property as any];
16+
if (property === "root") return target[property];
17+
const value = target[property as any];
18+
19+
if (value?.default && value.default.name !== "hooked") {
20+
return {
21+
...value,
22+
default: function hooked() {
23+
return (
24+
<>
25+
<div
26+
className={clsx(
27+
"rdt-invisible rdt-absolute rdt-hidden rdt-h-0 rdt-w-0",
28+
property as string
29+
)}
30+
/>
31+
<value.default />
32+
</>
33+
);
34+
},
35+
};
36+
}
37+
38+
return value;
39+
},
40+
});
41+
42+
submit(null, { method: "get", action: location.pathname });
43+
// We only want to run this once regardless of the dependencies and we want it to run after the first render
44+
// eslint-disable-next-line react-hooks/exhaustive-deps
45+
}, []);
46+
}

src/RemixDevTools/tabs/PageTab.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { useGetSocket } from "../hooks/useGetSocket";
66
import { Tag } from "../components/Tag";
77
import { VsCodeButton } from "../components/VScodeButton";
88
import { useMemo } from "react";
9-
import { isLayoutRoute } from "../utils/misc";
9+
import { isLayoutRoute } from "../utils/routing";
10+
import { useRDTContext } from "../context/useRDTContext";
1011

1112
export const ROUTE_COLORS: Record<string, string> = {
1213
ROUTE: "rdt-bg-green-500 rdt-text-white",
@@ -45,7 +46,26 @@ const PageTab = () => {
4546
const reversed = useMemo(() => routes.reverse(), [routes]);
4647
const { revalidate, state } = useRevalidator();
4748
const { isConnected, sendJsonMessage } = useGetSocket();
49+
const { showRouteBoundaries } = useRDTContext();
50+
const onHover = (path: string, type: "enter" | "leave") => {
51+
if (!showRouteBoundaries) return;
52+
const classes =
53+
"rdt-bg-green-100 rdt-transition-all rdt-rounded rdt-apply-tw rdt-bg-gradient-to-r rdt-from-cyan-500/50 rdt-to-blue-500/50";
54+
const isRoot = path === "root";
55+
const elements = isRoot
56+
? document.getElementsByTagName("body")
57+
: document.getElementsByClassName(path);
4858

59+
const element = elements.item(elements.length - 1);
60+
61+
if (element) {
62+
// Root has no outlet so we need to use the body, otherwise we get the outlet that is the next sibling of the element
63+
const outlet = isRoot ? element : (element.nextSibling as HTMLElement);
64+
for (const c of classes.split(" ")) {
65+
outlet.classList[type === "enter" ? "add" : "remove"](c);
66+
}
67+
}
68+
};
4969
return (
5070
<div className="rdt-relative rdt-flex rdt-h-full rdt-flex-col rdt-overflow-y-auto rdt-p-6 rdt-px-6">
5171
<button
@@ -73,7 +93,12 @@ const PageTab = () => {
7393
const isLayout = isLayoutRoute(entryRoute);
7494

7595
return (
76-
<li key={route.id} className="rdt-mb-8 rdt-ml-8">
96+
<li
97+
onMouseEnter={() => onHover(route.id, "enter")}
98+
onMouseLeave={() => onHover(route.id, "leave")}
99+
key={route.id}
100+
className="rdt-mb-8 rdt-ml-8"
101+
>
77102
<span className="rdt-absolute -rdt-left-3 rdt-mt-2 rdt-flex rdt-h-6 rdt-w-6 rdt-items-center rdt-justify-center rdt-rounded-full rdt-bg-blue-900 rdt-ring-4 rdt-ring-blue-900 ">
78103
<CornerDownRight />
79104
</span>

src/RemixDevTools/tabs/RoutesTab.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { useRDTContext } from "../context/useRDTContext";
1313
import { Input } from "../components/Input";
1414
import { NewRouteForm } from "../components/NewRouteForm";
1515
import { useGetSocket } from "../hooks/useGetSocket";
16-
import { isLeafRoute } from "../utils/misc";
16+
import { isLeafRoute } from "../utils/routing";
1717

1818
const RoutesTab = () => {
1919
const { routeWildcards, setRouteWildcards } = useRDTContext();

src/RemixDevTools/utils/misc.ts

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)