@react-trace-enhancer/plugin-open-editor 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # @react-trace-enhancer/plugin-open-editor
2
+
3
+ Open the currently selected component source in a local editor from the Trace action panel.
4
+
5
+ This plugin adds:
6
+
7
+ - an `Open in Editor` action for the selected source
8
+ - a settings control for choosing the default editor inside the widget
9
+
10
+ ## Installation
11
+
12
+ Install the plugin alongside its peer dependencies:
13
+
14
+ ```bash
15
+ pnpm add --dev @react-trace-enhancer/core @react-trace-enhancer/ui-components @react-trace-enhancer/plugin-open-editor
16
+ ```
17
+
18
+ If you are already using `@react-trace-enhancer/kit`, this plugin is included there by default.
19
+
20
+ ## Usage
21
+
22
+ ```tsx
23
+ import { Trace } from '@react-trace-enhancer/core'
24
+ import { OpenEditorPlugin } from '@react-trace-enhancer/plugin-open-editor'
25
+
26
+ import App from './App'
27
+
28
+ export function AppWithTrace() {
29
+ return (
30
+ <>
31
+ <App />
32
+ <Trace
33
+ root={import.meta.env.VITE_ROOT}
34
+ plugins={[OpenEditorPlugin({ editor: 'vscode' })]}
35
+ />
36
+ </>
37
+ )
38
+ }
39
+ ```
40
+
41
+ `root` should be the absolute project root passed to Trace so the plugin can resolve relative file paths for comments.
42
+
43
+ ## `editor` option
44
+
45
+ `OpenEditorPlugin` accepts a single option:
46
+
47
+ ```ts
48
+ interface OpenEditorPluginOptions {
49
+ editor?: EditorPreset
50
+ }
51
+ ```
52
+
53
+ - Default: `vscode`
54
+ - If the user changes the editor in the widget settings, that's what's used instead.
55
+
56
+ The package also exports the `EditorPreset` type.
57
+
58
+ ## Supported editor presets
59
+
60
+ These are the currently implemented presets:
61
+
62
+ - `vscode`
63
+ - `cursor`
64
+ - `windsurf`
65
+ - `zed`
66
+ - `webstorm`
67
+ - `intellij`
68
+
69
+ ## Behavior
70
+
71
+ When a source location is selected, the plugin resolves the file path relative to the Trace `root` and opens the generated editor URL with `window.open(...)`.
@@ -0,0 +1,19 @@
1
+ import { TracePlugin } from "@react-trace-enhancer/core";
2
+
3
+ //#region src/types.d.ts
4
+ type EditorPreset = 'vscode' | 'cursor' | 'windsurf' | 'webstorm' | 'intellij' | 'zed';
5
+ //#endregion
6
+ //#region src/index.d.ts
7
+ interface OpenEditorPluginOptions {
8
+ /**
9
+ * The editor to open files in.
10
+ * @default 'vscode'
11
+ */
12
+ editor?: EditorPreset;
13
+ }
14
+ declare function OpenEditorPlugin({
15
+ editor
16
+ }?: OpenEditorPluginOptions): TracePlugin;
17
+ //#endregion
18
+ export { OpenEditorPluginOptions as n, EditorPreset as r, OpenEditorPlugin as t };
19
+ //# sourceMappingURL=index-Boboj3a-.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-Boboj3a-.d.ts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;KAAY,YAAA;;;UCmBK,uBAAA;EDnBO;;;;ECwBtB,MAAA,GAAS,YAAA;AAAA;AAAA,iBA6CK,gBAAA,CAAA;EACd;AAAA,IACC,uBAAA,GAA+B,WAAA"}
@@ -0,0 +1,19 @@
1
+ import { TracePlugin } from "@react-trace-enhancer/core";
2
+
3
+ //#region src/types.d.ts
4
+ type EditorPreset = 'vscode' | 'cursor' | 'windsurf' | 'webstorm' | 'intellij' | 'zed';
5
+ //#endregion
6
+ //#region src/index.d.ts
7
+ interface OpenEditorPluginOptions {
8
+ /**
9
+ * The editor to open files in.
10
+ * @default 'vscode'
11
+ */
12
+ editor?: EditorPreset;
13
+ }
14
+ declare function OpenEditorPlugin({
15
+ editor
16
+ }?: OpenEditorPluginOptions): TracePlugin;
17
+ //#endregion
18
+ export { OpenEditorPluginOptions as n, EditorPreset as r, OpenEditorPlugin as t };
19
+ //# sourceMappingURL=index-CXpzVMLC.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-CXpzVMLC.d.cts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;KAAY,YAAA;;;UCmBK,uBAAA;EDnBO;;;;ECwBtB,MAAA,GAAS,YAAA;AAAA;AAAA,iBA6CK,gBAAA,CAAA;EACd;AAAA,IACC,uBAAA,GAA+B,WAAA"}
package/dist/index.cjs ADDED
@@ -0,0 +1,119 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let _react_trace_enhancer_core = require("@react-trace-enhancer/core");
3
+ let _react_trace_enhancer_ui_components = require("@react-trace-enhancer/ui-components");
4
+ let jotai = require("jotai");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+
7
+ //#region src/store.ts
8
+ const openEditorSettingsAtom = (0, _react_trace_enhancer_core.settingsPluginAtom)("openEditor");
9
+
10
+ //#endregion
11
+ //#region src/index.tsx
12
+ const EDITOR_LABELS = {
13
+ vscode: "VS Code",
14
+ cursor: "Cursor",
15
+ windsurf: "Windsurf",
16
+ zed: "Zed",
17
+ webstorm: "WebStorm",
18
+ intellij: "IntelliJ"
19
+ };
20
+ const editors = Object.entries(EDITOR_LABELS).map(([value, label]) => ({
21
+ value,
22
+ label
23
+ }));
24
+ const LABEL_STYLE = {
25
+ fontSize: 12,
26
+ color: "#d4d4d8",
27
+ fontFamily: "system-ui, sans-serif"
28
+ };
29
+ /**
30
+ * Builds the editor-specific URL to open a file at a given line/column.
31
+ *
32
+ * VS Code family uses: {editor}://file/{path}:{line}:{col}
33
+ * JetBrains uses: {editor}://open?file={path}&line={line}
34
+ */
35
+ function buildEditorUrl(editor, path, line, col) {
36
+ if (editor === "webstorm") return `webstorm://open?file=${encodeURIComponent(path)}&line=${line}`;
37
+ if (editor === "intellij") return `idea://open?file=${encodeURIComponent(path)}&line=${line}`;
38
+ return `${editor}://file/${path}:${line}:${col}`;
39
+ }
40
+ function OpenEditorPlugin({ editor = "vscode" } = {}) {
41
+ function OpenEditorActionPanel() {
42
+ const selectedSource = (0, _react_trace_enhancer_core.useSelectedSource)();
43
+ const clearSelectedContext = (0, _react_trace_enhancer_core.useClearSelectedContext)();
44
+ const currentEditor = (0, jotai.useAtomValue)(openEditorSettingsAtom)?.editor ?? editor;
45
+ if (!selectedSource) return null;
46
+ const handleOpenEditor = () => {
47
+ clearSelectedContext();
48
+ const url = buildEditorUrl(currentEditor, selectedSource.absolutePath, selectedSource.lineNumber, selectedSource.columnNumber);
49
+ window.open(url);
50
+ };
51
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_react_trace_enhancer_ui_components.DropdownMenu.Item, {
52
+ onClick: handleOpenEditor,
53
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
54
+ style: {
55
+ display: "flex",
56
+ alignItems: "center"
57
+ },
58
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_trace_enhancer_ui_components.OpenInEditorIcon, {})
59
+ }), `Open in ${EDITOR_LABELS[currentEditor]}`]
60
+ });
61
+ }
62
+ function OpenEditorSettings() {
63
+ const portalContainer = (0, _react_trace_enhancer_core.useWidgetPortalContainer)();
64
+ const [editorSettings = { editor }, setEditorSettings] = (0, jotai.useAtom)(openEditorSettingsAtom);
65
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
66
+ style: {
67
+ display: "flex",
68
+ flexDirection: "column",
69
+ gap: 12
70
+ },
71
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
72
+ style: {
73
+ display: "flex",
74
+ flexDirection: "column",
75
+ gap: 6
76
+ },
77
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
78
+ style: LABEL_STYLE,
79
+ children: "Default editor"
80
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_react_trace_enhancer_ui_components.Select.Root, {
81
+ value: editorSettings.editor,
82
+ items: editors,
83
+ onValueChange: (value) => {
84
+ if (value) setEditorSettings({
85
+ ...editorSettings,
86
+ editor: value
87
+ });
88
+ },
89
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_trace_enhancer_ui_components.Select.Trigger, {
90
+ onClick: (e) => e.stopPropagation(),
91
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_trace_enhancer_ui_components.Select.Value, {})
92
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_trace_enhancer_ui_components.Select.Portal, {
93
+ container: portalContainer,
94
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_trace_enhancer_ui_components.Select.Positioner, {
95
+ style: {
96
+ zIndex: 1e8,
97
+ pointerEvents: "auto"
98
+ },
99
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_trace_enhancer_ui_components.Select.Popup, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_trace_enhancer_ui_components.Select.List, { children: editors.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_trace_enhancer_ui_components.Select.Item, {
100
+ value: option.value,
101
+ onClick: (e) => e.stopPropagation(),
102
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_react_trace_enhancer_ui_components.Select.ItemText, { children: option.label })
103
+ }, option.value)) }) })
104
+ })
105
+ })]
106
+ })]
107
+ })
108
+ });
109
+ }
110
+ return {
111
+ name: "open-editor",
112
+ actionPanel: OpenEditorActionPanel,
113
+ settings: OpenEditorSettings
114
+ };
115
+ }
116
+
117
+ //#endregion
118
+ exports.OpenEditorPlugin = OpenEditorPlugin;
119
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["DropdownMenu","OpenInEditorIcon","Select"],"sources":["../src/store.ts","../src/index.tsx"],"sourcesContent":["import type { TraceSettings } from '@react-trace-enhancer/core'\nimport { settingsPluginAtom } from '@react-trace-enhancer/core'\nimport type { WritableAtom } from 'jotai'\n\nimport type { EditorPreset } from './types'\n\ndeclare module '@react-trace-enhancer/core' {\n interface TraceSettings {\n openEditor?: {\n editor: EditorPreset\n }\n }\n}\n\nexport const openEditorSettingsAtom = settingsPluginAtom(\n 'openEditor',\n) as WritableAtom<\n TraceSettings['openEditor'],\n [TraceSettings['openEditor']],\n void\n>\n","import type { TracePlugin } from '@react-trace-enhancer/core'\nimport {\n useClearSelectedContext,\n useSelectedSource,\n useWidgetPortalContainer,\n} from '@react-trace-enhancer/core'\nimport {\n DropdownMenu,\n OpenInEditorIcon,\n Select,\n} from '@react-trace-enhancer/ui-components'\nimport { useAtom, useAtomValue } from 'jotai'\nimport type { CSSProperties } from 'react'\n\nimport { openEditorSettingsAtom } from './store'\nimport type { EditorPreset } from './types'\n\nexport type { EditorPreset }\n\nexport interface OpenEditorPluginOptions {\n /**\n * The editor to open files in.\n * @default 'vscode'\n */\n editor?: EditorPreset\n}\n\nconst EDITOR_LABELS: Record<EditorPreset, string> = {\n vscode: 'VS Code',\n cursor: 'Cursor',\n windsurf: 'Windsurf',\n zed: 'Zed',\n webstorm: 'WebStorm',\n intellij: 'IntelliJ',\n}\n\nconst editors = Object.entries(EDITOR_LABELS).map(([value, label]) => ({\n value: value as EditorPreset,\n label,\n}))\n\nconst LABEL_STYLE: CSSProperties = {\n fontSize: 12,\n color: '#d4d4d8',\n fontFamily: 'system-ui, sans-serif',\n}\n\n/**\n * Builds the editor-specific URL to open a file at a given line/column.\n *\n * VS Code family uses: {editor}://file/{path}:{line}:{col}\n * JetBrains uses: {editor}://open?file={path}&line={line}\n */\nfunction buildEditorUrl(\n editor: EditorPreset,\n path: string,\n line: number,\n col: number,\n): string {\n if (editor === 'webstorm') {\n return `webstorm://open?file=${encodeURIComponent(path)}&line=${line}`\n }\n if (editor === 'intellij') {\n return `idea://open?file=${encodeURIComponent(path)}&line=${line}`\n }\n // VS Code family + Zed: vscode, cursor, windsurf, zed — identical format, different protocol\n return `${editor}://file/${path}:${line}:${col}`\n}\n\nexport function OpenEditorPlugin({\n editor = 'vscode',\n}: OpenEditorPluginOptions = {}): TracePlugin {\n function OpenEditorActionPanel() {\n const selectedSource = useSelectedSource()\n const clearSelectedContext = useClearSelectedContext()\n const editorSettings = useAtomValue(openEditorSettingsAtom)\n const currentEditor = editorSettings?.editor ?? editor\n\n if (!selectedSource) return null\n\n const handleOpenEditor = () => {\n clearSelectedContext()\n const url = buildEditorUrl(\n currentEditor,\n selectedSource.absolutePath,\n selectedSource.lineNumber,\n selectedSource.columnNumber,\n )\n window.open(url)\n }\n\n return (\n <DropdownMenu.Item onClick={handleOpenEditor}>\n <span style={{ display: 'flex', alignItems: 'center' }}>\n <OpenInEditorIcon />\n </span>\n {`Open in ${EDITOR_LABELS[currentEditor]}`}\n </DropdownMenu.Item>\n )\n }\n\n function OpenEditorSettings() {\n const portalContainer = useWidgetPortalContainer()\n\n const [editorSettings = { editor }, setEditorSettings] = useAtom(\n openEditorSettingsAtom,\n )\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>\n <label style={LABEL_STYLE}>Default editor</label>\n <Select.Root\n value={editorSettings.editor}\n items={editors}\n onValueChange={(value) => {\n if (value) {\n setEditorSettings({ ...editorSettings, editor: value })\n }\n }}\n >\n <Select.Trigger onClick={(e) => e.stopPropagation()}>\n <Select.Value />\n </Select.Trigger>\n\n <Select.Portal container={portalContainer}>\n <Select.Positioner\n style={{ zIndex: 100000000, pointerEvents: 'auto' }}\n >\n <Select.Popup>\n <Select.List>\n {editors.map((option) => (\n <Select.Item\n key={option.value}\n value={option.value}\n onClick={(e) => e.stopPropagation()}\n >\n <Select.ItemText>{option.label}</Select.ItemText>\n </Select.Item>\n ))}\n </Select.List>\n </Select.Popup>\n </Select.Positioner>\n </Select.Portal>\n </Select.Root>\n </div>\n </div>\n )\n }\n\n return {\n name: 'open-editor',\n actionPanel: OpenEditorActionPanel,\n settings: OpenEditorSettings,\n }\n}\n"],"mappings":";;;;;;;AAcA,MAAa,4EACX,aACD;;;;ACWD,MAAM,gBAA8C;CAClD,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,KAAK;CACL,UAAU;CACV,UAAU;CACX;AAED,MAAM,UAAU,OAAO,QAAQ,cAAc,CAAC,KAAK,CAAC,OAAO,YAAY;CAC9D;CACP;CACD,EAAE;AAEH,MAAM,cAA6B;CACjC,UAAU;CACV,OAAO;CACP,YAAY;CACb;;;;;;;AAQD,SAAS,eACP,QACA,MACA,MACA,KACQ;AACR,KAAI,WAAW,WACb,QAAO,wBAAwB,mBAAmB,KAAK,CAAC,QAAQ;AAElE,KAAI,WAAW,WACb,QAAO,oBAAoB,mBAAmB,KAAK,CAAC,QAAQ;AAG9D,QAAO,GAAG,OAAO,UAAU,KAAK,GAAG,KAAK,GAAG;;AAG7C,SAAgB,iBAAiB,EAC/B,SAAS,aACkB,EAAE,EAAe;CAC5C,SAAS,wBAAwB;EAC/B,MAAM,oEAAoC;EAC1C,MAAM,gFAAgD;EAEtD,MAAM,wCAD8B,uBAAuB,EACrB,UAAU;AAEhD,MAAI,CAAC,eAAgB,QAAO;EAE5B,MAAM,yBAAyB;AAC7B,yBAAsB;GACtB,MAAM,MAAM,eACV,eACA,eAAe,cACf,eAAe,YACf,eAAe,aAChB;AACD,UAAO,KAAK,IAAI;;AAGlB,SACE,4CAACA,iDAAa,MAAd;GAAmB,SAAS;aAA5B,CACE,2CAAC,QAAD;IAAM,OAAO;KAAE,SAAS;KAAQ,YAAY;KAAU;cACpD,2CAACC,sDAAD,EAAoB;IACf,GACN,WAAW,cAAc,iBACR;;;CAIxB,SAAS,qBAAqB;EAC5B,MAAM,4EAA4C;EAElD,MAAM,CAAC,iBAAiB,EAAE,QAAQ,EAAE,wCAClC,uBACD;AAED,SACE,2CAAC,OAAD;GAAK,OAAO;IAAE,SAAS;IAAQ,eAAe;IAAU,KAAK;IAAI;aAC/D,4CAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,eAAe;KAAU,KAAK;KAAG;cAAhE,CACE,2CAAC,SAAD;KAAO,OAAO;eAAa;KAAsB,GACjD,4CAACC,2CAAO,MAAR;KACE,OAAO,eAAe;KACtB,OAAO;KACP,gBAAgB,UAAU;AACxB,UAAI,MACF,mBAAkB;OAAE,GAAG;OAAgB,QAAQ;OAAO,CAAC;;eAL7D,CASE,2CAACA,2CAAO,SAAR;MAAgB,UAAU,MAAM,EAAE,iBAAiB;gBACjD,2CAACA,2CAAO,OAAR,EAAgB;MACD,GAEjB,2CAACA,2CAAO,QAAR;MAAe,WAAW;gBACxB,2CAACA,2CAAO,YAAR;OACE,OAAO;QAAE,QAAQ;QAAW,eAAe;QAAQ;iBAEnD,2CAACA,2CAAO,OAAR,YACE,2CAACA,2CAAO,MAAR,YACG,QAAQ,KAAK,WACZ,2CAACA,2CAAO,MAAR;QAEE,OAAO,OAAO;QACd,UAAU,MAAM,EAAE,iBAAiB;kBAEnC,2CAACA,2CAAO,UAAR,YAAkB,OAAO,OAAwB;QACrC,EALP,OAAO,MAKA,CACd,EACU,GACD;OACG;MACN,EACJ;OACV;;GACF;;AAIV,QAAO;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACX"}
@@ -0,0 +1,2 @@
1
+ import { n as OpenEditorPluginOptions, r as EditorPreset, t as OpenEditorPlugin } from "./index-CXpzVMLC.cjs";
2
+ export { EditorPreset, OpenEditorPlugin, OpenEditorPluginOptions };
@@ -0,0 +1,2 @@
1
+ import { n as OpenEditorPluginOptions, r as EditorPreset, t as OpenEditorPlugin } from "./index-Boboj3a-.js";
2
+ export { EditorPreset, OpenEditorPlugin, OpenEditorPluginOptions };
package/dist/index.js ADDED
@@ -0,0 +1,118 @@
1
+ import { settingsPluginAtom, useClearSelectedContext, useSelectedSource, useWidgetPortalContainer } from "@react-trace-enhancer/core";
2
+ import { DropdownMenu, OpenInEditorIcon, Select } from "@react-trace-enhancer/ui-components";
3
+ import { useAtom, useAtomValue } from "jotai";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+
6
+ //#region src/store.ts
7
+ const openEditorSettingsAtom = settingsPluginAtom("openEditor");
8
+
9
+ //#endregion
10
+ //#region src/index.tsx
11
+ const EDITOR_LABELS = {
12
+ vscode: "VS Code",
13
+ cursor: "Cursor",
14
+ windsurf: "Windsurf",
15
+ zed: "Zed",
16
+ webstorm: "WebStorm",
17
+ intellij: "IntelliJ"
18
+ };
19
+ const editors = Object.entries(EDITOR_LABELS).map(([value, label]) => ({
20
+ value,
21
+ label
22
+ }));
23
+ const LABEL_STYLE = {
24
+ fontSize: 12,
25
+ color: "#d4d4d8",
26
+ fontFamily: "system-ui, sans-serif"
27
+ };
28
+ /**
29
+ * Builds the editor-specific URL to open a file at a given line/column.
30
+ *
31
+ * VS Code family uses: {editor}://file/{path}:{line}:{col}
32
+ * JetBrains uses: {editor}://open?file={path}&line={line}
33
+ */
34
+ function buildEditorUrl(editor, path, line, col) {
35
+ if (editor === "webstorm") return `webstorm://open?file=${encodeURIComponent(path)}&line=${line}`;
36
+ if (editor === "intellij") return `idea://open?file=${encodeURIComponent(path)}&line=${line}`;
37
+ return `${editor}://file/${path}:${line}:${col}`;
38
+ }
39
+ function OpenEditorPlugin({ editor = "vscode" } = {}) {
40
+ function OpenEditorActionPanel() {
41
+ const selectedSource = useSelectedSource();
42
+ const clearSelectedContext = useClearSelectedContext();
43
+ const currentEditor = useAtomValue(openEditorSettingsAtom)?.editor ?? editor;
44
+ if (!selectedSource) return null;
45
+ const handleOpenEditor = () => {
46
+ clearSelectedContext();
47
+ const url = buildEditorUrl(currentEditor, selectedSource.absolutePath, selectedSource.lineNumber, selectedSource.columnNumber);
48
+ window.open(url);
49
+ };
50
+ return /* @__PURE__ */ jsxs(DropdownMenu.Item, {
51
+ onClick: handleOpenEditor,
52
+ children: [/* @__PURE__ */ jsx("span", {
53
+ style: {
54
+ display: "flex",
55
+ alignItems: "center"
56
+ },
57
+ children: /* @__PURE__ */ jsx(OpenInEditorIcon, {})
58
+ }), `Open in ${EDITOR_LABELS[currentEditor]}`]
59
+ });
60
+ }
61
+ function OpenEditorSettings() {
62
+ const portalContainer = useWidgetPortalContainer();
63
+ const [editorSettings = { editor }, setEditorSettings] = useAtom(openEditorSettingsAtom);
64
+ return /* @__PURE__ */ jsx("div", {
65
+ style: {
66
+ display: "flex",
67
+ flexDirection: "column",
68
+ gap: 12
69
+ },
70
+ children: /* @__PURE__ */ jsxs("div", {
71
+ style: {
72
+ display: "flex",
73
+ flexDirection: "column",
74
+ gap: 6
75
+ },
76
+ children: [/* @__PURE__ */ jsx("label", {
77
+ style: LABEL_STYLE,
78
+ children: "Default editor"
79
+ }), /* @__PURE__ */ jsxs(Select.Root, {
80
+ value: editorSettings.editor,
81
+ items: editors,
82
+ onValueChange: (value) => {
83
+ if (value) setEditorSettings({
84
+ ...editorSettings,
85
+ editor: value
86
+ });
87
+ },
88
+ children: [/* @__PURE__ */ jsx(Select.Trigger, {
89
+ onClick: (e) => e.stopPropagation(),
90
+ children: /* @__PURE__ */ jsx(Select.Value, {})
91
+ }), /* @__PURE__ */ jsx(Select.Portal, {
92
+ container: portalContainer,
93
+ children: /* @__PURE__ */ jsx(Select.Positioner, {
94
+ style: {
95
+ zIndex: 1e8,
96
+ pointerEvents: "auto"
97
+ },
98
+ children: /* @__PURE__ */ jsx(Select.Popup, { children: /* @__PURE__ */ jsx(Select.List, { children: editors.map((option) => /* @__PURE__ */ jsx(Select.Item, {
99
+ value: option.value,
100
+ onClick: (e) => e.stopPropagation(),
101
+ children: /* @__PURE__ */ jsx(Select.ItemText, { children: option.label })
102
+ }, option.value)) }) })
103
+ })
104
+ })]
105
+ })]
106
+ })
107
+ });
108
+ }
109
+ return {
110
+ name: "open-editor",
111
+ actionPanel: OpenEditorActionPanel,
112
+ settings: OpenEditorSettings
113
+ };
114
+ }
115
+
116
+ //#endregion
117
+ export { OpenEditorPlugin };
118
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/store.ts","../src/index.tsx"],"sourcesContent":["import type { TraceSettings } from '@react-trace-enhancer/core'\nimport { settingsPluginAtom } from '@react-trace-enhancer/core'\nimport type { WritableAtom } from 'jotai'\n\nimport type { EditorPreset } from './types'\n\ndeclare module '@react-trace-enhancer/core' {\n interface TraceSettings {\n openEditor?: {\n editor: EditorPreset\n }\n }\n}\n\nexport const openEditorSettingsAtom = settingsPluginAtom(\n 'openEditor',\n) as WritableAtom<\n TraceSettings['openEditor'],\n [TraceSettings['openEditor']],\n void\n>\n","import type { TracePlugin } from '@react-trace-enhancer/core'\nimport {\n useClearSelectedContext,\n useSelectedSource,\n useWidgetPortalContainer,\n} from '@react-trace-enhancer/core'\nimport {\n DropdownMenu,\n OpenInEditorIcon,\n Select,\n} from '@react-trace-enhancer/ui-components'\nimport { useAtom, useAtomValue } from 'jotai'\nimport type { CSSProperties } from 'react'\n\nimport { openEditorSettingsAtom } from './store'\nimport type { EditorPreset } from './types'\n\nexport type { EditorPreset }\n\nexport interface OpenEditorPluginOptions {\n /**\n * The editor to open files in.\n * @default 'vscode'\n */\n editor?: EditorPreset\n}\n\nconst EDITOR_LABELS: Record<EditorPreset, string> = {\n vscode: 'VS Code',\n cursor: 'Cursor',\n windsurf: 'Windsurf',\n zed: 'Zed',\n webstorm: 'WebStorm',\n intellij: 'IntelliJ',\n}\n\nconst editors = Object.entries(EDITOR_LABELS).map(([value, label]) => ({\n value: value as EditorPreset,\n label,\n}))\n\nconst LABEL_STYLE: CSSProperties = {\n fontSize: 12,\n color: '#d4d4d8',\n fontFamily: 'system-ui, sans-serif',\n}\n\n/**\n * Builds the editor-specific URL to open a file at a given line/column.\n *\n * VS Code family uses: {editor}://file/{path}:{line}:{col}\n * JetBrains uses: {editor}://open?file={path}&line={line}\n */\nfunction buildEditorUrl(\n editor: EditorPreset,\n path: string,\n line: number,\n col: number,\n): string {\n if (editor === 'webstorm') {\n return `webstorm://open?file=${encodeURIComponent(path)}&line=${line}`\n }\n if (editor === 'intellij') {\n return `idea://open?file=${encodeURIComponent(path)}&line=${line}`\n }\n // VS Code family + Zed: vscode, cursor, windsurf, zed — identical format, different protocol\n return `${editor}://file/${path}:${line}:${col}`\n}\n\nexport function OpenEditorPlugin({\n editor = 'vscode',\n}: OpenEditorPluginOptions = {}): TracePlugin {\n function OpenEditorActionPanel() {\n const selectedSource = useSelectedSource()\n const clearSelectedContext = useClearSelectedContext()\n const editorSettings = useAtomValue(openEditorSettingsAtom)\n const currentEditor = editorSettings?.editor ?? editor\n\n if (!selectedSource) return null\n\n const handleOpenEditor = () => {\n clearSelectedContext()\n const url = buildEditorUrl(\n currentEditor,\n selectedSource.absolutePath,\n selectedSource.lineNumber,\n selectedSource.columnNumber,\n )\n window.open(url)\n }\n\n return (\n <DropdownMenu.Item onClick={handleOpenEditor}>\n <span style={{ display: 'flex', alignItems: 'center' }}>\n <OpenInEditorIcon />\n </span>\n {`Open in ${EDITOR_LABELS[currentEditor]}`}\n </DropdownMenu.Item>\n )\n }\n\n function OpenEditorSettings() {\n const portalContainer = useWidgetPortalContainer()\n\n const [editorSettings = { editor }, setEditorSettings] = useAtom(\n openEditorSettingsAtom,\n )\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>\n <label style={LABEL_STYLE}>Default editor</label>\n <Select.Root\n value={editorSettings.editor}\n items={editors}\n onValueChange={(value) => {\n if (value) {\n setEditorSettings({ ...editorSettings, editor: value })\n }\n }}\n >\n <Select.Trigger onClick={(e) => e.stopPropagation()}>\n <Select.Value />\n </Select.Trigger>\n\n <Select.Portal container={portalContainer}>\n <Select.Positioner\n style={{ zIndex: 100000000, pointerEvents: 'auto' }}\n >\n <Select.Popup>\n <Select.List>\n {editors.map((option) => (\n <Select.Item\n key={option.value}\n value={option.value}\n onClick={(e) => e.stopPropagation()}\n >\n <Select.ItemText>{option.label}</Select.ItemText>\n </Select.Item>\n ))}\n </Select.List>\n </Select.Popup>\n </Select.Positioner>\n </Select.Portal>\n </Select.Root>\n </div>\n </div>\n )\n }\n\n return {\n name: 'open-editor',\n actionPanel: OpenEditorActionPanel,\n settings: OpenEditorSettings,\n }\n}\n"],"mappings":";;;;;;AAcA,MAAa,yBAAyB,mBACpC,aACD;;;;ACWD,MAAM,gBAA8C;CAClD,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,KAAK;CACL,UAAU;CACV,UAAU;CACX;AAED,MAAM,UAAU,OAAO,QAAQ,cAAc,CAAC,KAAK,CAAC,OAAO,YAAY;CAC9D;CACP;CACD,EAAE;AAEH,MAAM,cAA6B;CACjC,UAAU;CACV,OAAO;CACP,YAAY;CACb;;;;;;;AAQD,SAAS,eACP,QACA,MACA,MACA,KACQ;AACR,KAAI,WAAW,WACb,QAAO,wBAAwB,mBAAmB,KAAK,CAAC,QAAQ;AAElE,KAAI,WAAW,WACb,QAAO,oBAAoB,mBAAmB,KAAK,CAAC,QAAQ;AAG9D,QAAO,GAAG,OAAO,UAAU,KAAK,GAAG,KAAK,GAAG;;AAG7C,SAAgB,iBAAiB,EAC/B,SAAS,aACkB,EAAE,EAAe;CAC5C,SAAS,wBAAwB;EAC/B,MAAM,iBAAiB,mBAAmB;EAC1C,MAAM,uBAAuB,yBAAyB;EAEtD,MAAM,gBADiB,aAAa,uBAAuB,EACrB,UAAU;AAEhD,MAAI,CAAC,eAAgB,QAAO;EAE5B,MAAM,yBAAyB;AAC7B,yBAAsB;GACtB,MAAM,MAAM,eACV,eACA,eAAe,cACf,eAAe,YACf,eAAe,aAChB;AACD,UAAO,KAAK,IAAI;;AAGlB,SACE,qBAAC,aAAa,MAAd;GAAmB,SAAS;aAA5B,CACE,oBAAC,QAAD;IAAM,OAAO;KAAE,SAAS;KAAQ,YAAY;KAAU;cACpD,oBAAC,kBAAD,EAAoB;IACf,GACN,WAAW,cAAc,iBACR;;;CAIxB,SAAS,qBAAqB;EAC5B,MAAM,kBAAkB,0BAA0B;EAElD,MAAM,CAAC,iBAAiB,EAAE,QAAQ,EAAE,qBAAqB,QACvD,uBACD;AAED,SACE,oBAAC,OAAD;GAAK,OAAO;IAAE,SAAS;IAAQ,eAAe;IAAU,KAAK;IAAI;aAC/D,qBAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,eAAe;KAAU,KAAK;KAAG;cAAhE,CACE,oBAAC,SAAD;KAAO,OAAO;eAAa;KAAsB,GACjD,qBAAC,OAAO,MAAR;KACE,OAAO,eAAe;KACtB,OAAO;KACP,gBAAgB,UAAU;AACxB,UAAI,MACF,mBAAkB;OAAE,GAAG;OAAgB,QAAQ;OAAO,CAAC;;eAL7D,CASE,oBAAC,OAAO,SAAR;MAAgB,UAAU,MAAM,EAAE,iBAAiB;gBACjD,oBAAC,OAAO,OAAR,EAAgB;MACD,GAEjB,oBAAC,OAAO,QAAR;MAAe,WAAW;gBACxB,oBAAC,OAAO,YAAR;OACE,OAAO;QAAE,QAAQ;QAAW,eAAe;QAAQ;iBAEnD,oBAAC,OAAO,OAAR,YACE,oBAAC,OAAO,MAAR,YACG,QAAQ,KAAK,WACZ,oBAAC,OAAO,MAAR;QAEE,OAAO,OAAO;QACd,UAAU,MAAM,EAAE,iBAAiB;kBAEnC,oBAAC,OAAO,UAAR,YAAkB,OAAO,OAAwB;QACrC,EALP,OAAO,MAKA,CACd,EACU,GACD;OACG;MACN,EACJ;OACV;;GACF;;AAIV,QAAO;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACX"}
@@ -0,0 +1,11 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/index.prod.ts
4
+ /**
5
+ * Production stub for @react-trace-enhancer/plugin-open-editor.
6
+ */
7
+ const OpenEditorPlugin = () => ({ name: "open-editor" });
8
+
9
+ //#endregion
10
+ exports.OpenEditorPlugin = OpenEditorPlugin;
11
+ //# sourceMappingURL=index.prod.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.prod.cjs","names":[],"sources":["../src/index.prod.ts"],"sourcesContent":["/**\n * Production stub for @react-trace-enhancer/plugin-open-editor.\n */\nexport const OpenEditorPlugin = () => ({ name: 'open-editor' as const })\n\nexport type { OpenEditorPluginOptions } from './index'\n\nexport type { EditorPreset } from './types'\n"],"mappings":";;;;;;AAGA,MAAa,0BAA0B,EAAE,MAAM,eAAwB"}
@@ -0,0 +1,12 @@
1
+ import { n as OpenEditorPluginOptions, r as EditorPreset } from "./index-CXpzVMLC.cjs";
2
+
3
+ //#region src/index.prod.d.ts
4
+ /**
5
+ * Production stub for @react-trace-enhancer/plugin-open-editor.
6
+ */
7
+ declare const OpenEditorPlugin: () => {
8
+ name: "open-editor";
9
+ };
10
+ //#endregion
11
+ export { type EditorPreset, OpenEditorPlugin, type OpenEditorPluginOptions };
12
+ //# sourceMappingURL=index.prod.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.prod.d.cts","names":[],"sources":["../src/index.prod.ts"],"mappings":";;;;;;cAGa,gBAAA;EAA2D,IAAA;AAAA"}
@@ -0,0 +1,12 @@
1
+ import { n as OpenEditorPluginOptions, r as EditorPreset } from "./index-Boboj3a-.js";
2
+
3
+ //#region src/index.prod.d.ts
4
+ /**
5
+ * Production stub for @react-trace-enhancer/plugin-open-editor.
6
+ */
7
+ declare const OpenEditorPlugin: () => {
8
+ name: "open-editor";
9
+ };
10
+ //#endregion
11
+ export { type EditorPreset, OpenEditorPlugin, type OpenEditorPluginOptions };
12
+ //# sourceMappingURL=index.prod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.prod.d.ts","names":[],"sources":["../src/index.prod.ts"],"mappings":";;;;;;cAGa,gBAAA;EAA2D,IAAA;AAAA"}
@@ -0,0 +1,9 @@
1
+ //#region src/index.prod.ts
2
+ /**
3
+ * Production stub for @react-trace-enhancer/plugin-open-editor.
4
+ */
5
+ const OpenEditorPlugin = () => ({ name: "open-editor" });
6
+
7
+ //#endregion
8
+ export { OpenEditorPlugin };
9
+ //# sourceMappingURL=index.prod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.prod.js","names":[],"sources":["../src/index.prod.ts"],"sourcesContent":["/**\n * Production stub for @react-trace-enhancer/plugin-open-editor.\n */\nexport const OpenEditorPlugin = () => ({ name: 'open-editor' as const })\n\nexport type { OpenEditorPluginOptions } from './index'\n\nexport type { EditorPreset } from './types'\n"],"mappings":";;;;AAGA,MAAa,0BAA0B,EAAE,MAAM,eAAwB"}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@react-trace-enhancer/plugin-open-editor",
3
+ "version": "0.0.1",
4
+ "description": "react-trace plugin: open inspected component source in your code editor",
5
+ "keywords": [
6
+ "react-trace",
7
+ "react-trace-plugin"
8
+ ],
9
+ "license": "MIT",
10
+ "author": "Vitor Buzinaro",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/buzinas/react-trace",
14
+ "directory": "packages/plugin-open-editor"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "type": "module",
20
+ "main": "./dist/index.cjs",
21
+ "module": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "development": {
26
+ "import": {
27
+ "types": "./dist/index.d.ts",
28
+ "default": "./dist/index.js"
29
+ },
30
+ "require": {
31
+ "types": "./dist/index.d.cts",
32
+ "default": "./dist/index.cjs"
33
+ }
34
+ },
35
+ "production": {
36
+ "import": {
37
+ "types": "./dist/index.d.ts",
38
+ "default": "./dist/index.prod.js"
39
+ },
40
+ "require": {
41
+ "types": "./dist/index.d.cts",
42
+ "default": "./dist/index.prod.cjs"
43
+ }
44
+ },
45
+ "default": {
46
+ "import": {
47
+ "types": "./dist/index.d.ts",
48
+ "default": "./dist/index.js"
49
+ },
50
+ "require": {
51
+ "types": "./dist/index.d.cts",
52
+ "default": "./dist/index.cjs"
53
+ }
54
+ }
55
+ }
56
+ },
57
+ "publishConfig": {
58
+ "access": "public"
59
+ },
60
+ "scripts": {
61
+ "build": "tsdown",
62
+ "dev": "tsdown --watch --no-clean",
63
+ "typecheck": "tsc --noEmit",
64
+ "lint": "oxlint src",
65
+ "prepublishOnly": "pnpm build"
66
+ },
67
+ "devDependencies": {
68
+ "@types/react": "^19",
69
+ "oxlint": "latest",
70
+ "react": "^19",
71
+ "tsdown": "^0.21.0-beta.2",
72
+ "typescript": "^5"
73
+ },
74
+ "peerDependencies": {
75
+ "@react-trace-enhancer/core": "^0.0.1",
76
+ "@react-trace-enhancer/ui-components": "^0.0.1",
77
+ "jotai": "^2.18.0",
78
+ "react": ">=18"
79
+ }
80
+ }