Skip to content
Open
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
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
4 changes: 1 addition & 3 deletions examples/react/basic/src/setup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ 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