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
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# @dev-plugins/react-navigation
# @bam.tech/react-navigation-visualizer-dev-plugin

A React Navigation DevTool that can run in an Expo App
A Visualization Tool based on Expo DevTools Plugin for React Navigation.

## Installation

### Add the package to your project

```bash
npx expo install @dev-plugins/react-navigation
npx expo install@bam.tech/react-navigation-visualizer-dev-plugin
```

## Usage
Expand All @@ -18,7 +18,7 @@ npx expo install @dev-plugins/react-navigation

```jsx
import { useNavigationContainerRef } from '@react-navigation/native';
import { useReactNavigationDevTools } from '@dev-plugins/react-navigation';
import { useReactNavigationDevTools } from '@bam.tech/react-navigation-visualizer-dev-plugin';

export default function App() {
const navigationRef = useNavigationContainerRef();
Expand All @@ -34,13 +34,13 @@ When using `expo-router`, integrate the DevTool in your main `_layout.tsx` file.

```tsx
import { useNavigationContainerRef } from 'expo-router';
import { useReactNavigationDevTools } from '@dev-plugins/react-navigation';
import { useReactNavigationDevTools } from '@bam.tech/react-navigation-visualizer-dev-plugin';

export default function RootLayout() {
const navigationRef = useNavigationContainerRef();
useReactNavigationDevTools(navigationRef);

return <Stack />
return <Stack />;
}
```

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@dev-plugins/react-navigation",
"version": "0.1.0",
"description": "Expo DevTools Plugin for React Navigation",
"name": "@bam.tech/react-navigation-visualizer-dev-plugin",
"version": "0.1.4",
"description": "Visualization Tool based on Expo DevTools Plugin for React Navigation",
"main": "build/index.js",
"types": "build/index.d.ts",
"sideEffects": false,
Expand All @@ -10,20 +10,20 @@
"clean": "expo-module clean",
"lint": "expo-module lint",
"test": "expo-module test",
"prepare": "expo-module prepare && node ../../scripts/build-webui.js react-navigation",
"prepare": "expo-module prepare && node ../../scripts/build-webui.js react-navigation-visualizer",
"prepublishOnly": "expo-module prepublishOnly",
"expo-module": "expo-module"
},
"homepage": "https://docs.expo.dev/versions/latest/sdk/image/",
"repository": {
"type": "git",
"url": "git+https://github.com/expo/dev-plugins.git",
"directory": "packages/react-navigation"
"url": "git+https://github.com/thomasrebam/dev-plugins.git",
"directory": "packages/react-navigation-visualizer"
},
"keywords": [
"expo",
"devtools",
"react-navigation"
"react-navigation-visualizer"
],
"files": [
"build",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"bundler": "metro"
},
"experiments": {
"baseUrl": "/_expo/plugins/@dev-plugins/react-navigation"
"baseUrl": "/_expo/plugins/@bam.tech/react-navigation-visualizer-dev-plugin"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dev-plugins/react-navigation-webui",
"description": "The frontend webui for @dev-plugins/react-navigation",
"name": "@bam.tech/react-navigation-visualizer-dev-plugin-webui",
"description": "The frontend webui for @bam.tech/react-navigation-visualizer-dev-plugin",
"private": true,
"version": "0.1.0",
"main": "index.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Layout, Tabs, theme as antTheme, ThemeConfig } from 'antd';
import { ThemeProvider } from '@emotion/react';
import styled from '@emotion/styled';
import { theme as antTheme, Layout, Tabs, ThemeConfig } from 'antd';
import * as React from 'react';

import { theme } from './theme';

import { LinkingTester } from './LinkingTester';
import { Logs } from './Logs';
import { NavigationTree } from './NavigationTree';
import { theme } from './theme';
import { usePluginStore } from './usePluginStore';

declare module '@emotion/react' {
Expand All @@ -31,6 +31,9 @@ export default function App() {
<TabsContent tab={<TabLabel>Linking</TabLabel>} key="linking">
<LinkingTester active={activeKey === 'linking'} {...store} />
</TabsContent>
<TabsContent tab={<TabLabel>Stack Visualization</TabLabel>} key="navigationTree">
<NavigationTree {...store} />
</TabsContent>
</Tabs>
</Container>
</ThemeProvider>
Expand Down
145 changes: 145 additions & 0 deletions packages/react-navigation-visualizer/webui/src/NavigationTree.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import styled from '@emotion/styled';
import { Layout, Typography } from 'antd';
import * as React from 'react';

import { Sidebar } from './Sidebar';
import type { NavigationState, StoreType } from './types';

type Props = StoreType;

export function NavigationTree({ logs }: Props) {
const currentNavigationItem = logs[logs.length - 1];
const previousNavigationItem = logs[logs.length - 2];

const currentNavigationItemState = currentNavigationItem?.state;
const previousNavigationItemState = previousNavigationItem?.state;

const hasCurrentItem = !!currentNavigationItem && currentNavigationItemState;
const hasPreviousItem = !!previousNavigationItem && previousNavigationItemState;

return (
<Layout>
<Layout.Content style={{ height: '100vh', overflow: 'auto', paddingBottom: '80px' }}>
<Container>
<HalfContainer>
<Typography>Previous state</Typography>
<HalfContent>
{hasPreviousItem && <Node name="root" state={previousNavigationItemState} />}
</HalfContent>
</HalfContainer>
<HalfContainer>
<Typography>Current state</Typography>
<HalfContent>
{hasCurrentItem && <Node name="root" state={currentNavigationItemState} />}
</HalfContent>
</HalfContainer>
</Container>
</Layout.Content>
{hasCurrentItem ? (
<Sidebar
action={currentNavigationItem.action}
state={currentNavigationItem.state}
stack={currentNavigationItem.stack}
/>
) : null}
</Layout>
);
}

const Container = styled.div({
display: 'flex',
overflow: 'auto',
flexDirection: 'row',
flex: 1,
});

const HalfContainer = styled.div({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
overflow: 'auto',
justifyContent: 'space-between',
height: '100%',
flex: 1,
});

const HalfContent = styled.div({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
overflow: 'auto',
justifyContent: 'flex-end',
height: '100%',
flex: 1,
});

const Spacer = styled.div({
height: 4,
});

const LeafContainer = styled.div(({ theme: antdTheme }) => ({
display: 'flex',
backgroundColor: antdTheme.token?.colorPrimary,
borderRadius: 4,
alignItems: 'center',
justifyContent: 'center',
padding: 8,
}));

const LeafTitle = styled(Typography.Text)({
color: 'white',
});

const Leaf = ({ title, isSelectedTab }: { title: string; isSelectedTab?: boolean }) => {
return (
<LeafContainer>
<LeafTitle style={{ textDecoration: isSelectedTab ? 'underline' : 'none' }}>
{title}
</LeafTitle>
</LeafContainer>
);
};

const NodeContainer = styled.div(({ theme: antdTheme }) => ({
display: 'flex',
flexDirection: 'column',
borderRadius: 4,
borderWidth: 1,
border: 'solid',
borderColor: antdTheme.token?.colorPrimary,
padding: 8,
}));

const NodeTitle = styled(Typography)(({ theme }) => ({
color: theme.token?.colorPrimary,
alignSelf: 'flex-start',
}));

const Node = ({ name, state }: { name: string; state: NavigationState }) => {
const routes = state.routes;
if (!routes || !routes.length) {
return <Leaf title={name} />;
}

return (
<NodeContainer>
{routes.toReversed().map((route, index) => (
<React.Fragment key={index}>
{route.state?.routes && route.state.routes.length ? (
<Node name={route.name} state={route.state} />
) : (
<Leaf
title={route.name}
isSelectedTab={
state.type === 'tab' && state.index === state.routes.length - 1 - index
}
/>
)}
<Spacer />
</React.Fragment>
))}
<Spacer />
<NodeTitle>{name}</NodeTitle>
</NodeContainer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type NavigationState = {
key: string;
index: number;
routes: NavigationRoute[];
type: string;
};

export type NavigationAction = {
Expand Down