Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions .changeset/icy-states-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/devtools': minor
---

Adds copy path feature and config to devtools source inspector
19 changes: 19 additions & 0 deletions docs/source-inspector.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ export default {

Both `files` and `components` accept arrays of strings (exact match) or RegExp patterns.

## Click Action

By default, clicking an inspected element opens the file in your editor. You can change this to copy the source path to the clipboard instead using the `sourceAction` setting:

```ts
<TanStackDevtools
config={{
sourceAction: 'copy-path',
}}
/>
```

| Value | Behavior |
| --- | --- |
| `"ide-warp"` | Opens the file in your editor at the exact line (default) |
| `"copy-path"` | Copies the `filepath:line:column` string to the clipboard |

This is useful in environments where the Vite dev server cannot reach your editor, or when you want to paste the path elsewhere.

## Editor Configuration

Most popular editors work out of the box via the `launch-editor` package. Supported editors include VS Code, WebStorm, Sublime Text, Atom, and more ([full list](https://github.com/yyx990803/launch-editor?tab=readme-ov-file#supported-editors)).
Expand Down
2 changes: 2 additions & 0 deletions examples/react/basic/src/setup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,15 @@ const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
const router = createRouter({
routeTree,
})

export default function DevtoolsExample() {
return (
<>
<TanStackDevtools
eventBusConfig={{
connectToServerBus: true,
}}
config={{ sourceAction: 'copy-path' }}
plugins={[
{
name: 'TanStack Query',
Expand Down
26 changes: 26 additions & 0 deletions packages/devtools/src/components/source-inspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,32 @@ export const SourceInspector = () => {

const downList = useKeyDownList()

const [disabledAfterClick, setDisabledAfterClick] = createSignal(false)

const isHighlightingKeysHeld = createMemo(() => {
return isHotkeyCombinationPressed(downList(), settings().inspectHotkey)
})

createEffect(() => {
if (!isHighlightingKeysHeld()) {
setDisabledAfterClick(false)
}
})

const isActive = createMemo(
() => isHighlightingKeysHeld() && !disabledAfterClick(),
)

createEffect(() => {
if (isActive()) {
document.body.style.cursor = 'pointer'
} else {
document.body.style.cursor = ''
}
})

createEffect(() => {
if (!isActive()) {
resetHighlight()
return
}
Expand Down Expand Up @@ -78,6 +98,12 @@ export const SourceInspector = () => {
window.getSelection()?.removeAllRanges()
e.preventDefault()
e.stopPropagation()
setDisabledAfterClick(true)

if (settings().sourceAction === 'copy-path') {
navigator.clipboard.writeText(highlightState.dataSource).catch(() => {})
return
}

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const baseUrl = new URL(import.meta.env?.BASE_URL ?? '/', location.origin)
Expand Down
8 changes: 8 additions & 0 deletions packages/devtools/src/context/devtools-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ export type DevtoolsStore = {
*/
theme: TanStackDevtoolsTheme

/**
* The action to perform when clicking a source-inspected element
* - "ide-warp": open the file in the IDE via the Vite middleware
* - "copy-path": copy the file path to the clipboard
* @default "ide-warp"
*/
sourceAction: 'ide-warp' | 'copy-path'
/**
* Whether the trigger should be completely hidden or not (you can still open with the hotkey)
*/
Expand Down Expand Up @@ -110,6 +117,7 @@ export const initialState: DevtoolsStore = {
window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light',
sourceAction: 'ide-warp',
triggerHidden: false,
customTrigger: undefined,
},
Expand Down
Loading