nextjs-ide-helper 1.3.3 → 1.4.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 +141 -5
- package/lib/loader.js +91 -35
- package/lib/plugin.js +0 -3
- package/lib/withIdeButton.js +9 -10
- package/lib/withIdeButton.tsx +10 -13
- package/package.json +7 -4
- package/src/__tests__/loader.test.js +338 -2
- package/src/loader.js +91 -30
- package/src/withIdeButton.tsx +10 -13
- package/lib/__tests__/loader.test.js +0 -480
package/README.md
CHANGED
|
@@ -119,7 +119,40 @@ export default withIdeButton(MyComponent, 'src/components/MyComponent.tsx', {
|
|
|
119
119
|
|
|
120
120
|
The plugin automatically detects and wraps all types of React component export patterns:
|
|
121
121
|
|
|
122
|
-
### Named Components
|
|
122
|
+
### Named Export Components
|
|
123
|
+
```tsx
|
|
124
|
+
// Named arrow function exports
|
|
125
|
+
export const Button = () => <button>Click me</button>;
|
|
126
|
+
export const Modal = () => <div>Modal content</div>;
|
|
127
|
+
|
|
128
|
+
// Named function exports
|
|
129
|
+
export function MyButton() {
|
|
130
|
+
return <button>Function Button</button>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function MyModal() {
|
|
134
|
+
return <div>Function Modal</div>;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Mixed named and default exports
|
|
138
|
+
export const HeaderButton = () => <button>Header</button>;
|
|
139
|
+
|
|
140
|
+
const MainComponent = () => <div>Main</div>;
|
|
141
|
+
export default MainComponent;
|
|
142
|
+
|
|
143
|
+
// TypeScript named exports
|
|
144
|
+
interface ButtonProps {
|
|
145
|
+
onClick: () => void;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export const TypedButton = ({ onClick }: ButtonProps) => (
|
|
149
|
+
<button onClick={onClick}>Typed Button</button>
|
|
150
|
+
);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Default Export Components
|
|
154
|
+
|
|
155
|
+
#### Named Components
|
|
123
156
|
```tsx
|
|
124
157
|
// Standard pattern
|
|
125
158
|
const MyComponent = () => <div>Hello</div>;
|
|
@@ -132,7 +165,7 @@ const MyComponent = function() {
|
|
|
132
165
|
export default MyComponent;
|
|
133
166
|
```
|
|
134
167
|
|
|
135
|
-
|
|
168
|
+
#### Direct Export Function Components
|
|
136
169
|
```tsx
|
|
137
170
|
// Named function
|
|
138
171
|
export default function MyComponent() {
|
|
@@ -145,7 +178,7 @@ export default function() {
|
|
|
145
178
|
}
|
|
146
179
|
```
|
|
147
180
|
|
|
148
|
-
|
|
181
|
+
#### Arrow Function Components
|
|
149
182
|
```tsx
|
|
150
183
|
// Anonymous arrow function
|
|
151
184
|
export default () => {
|
|
@@ -158,7 +191,7 @@ export default (props) => {
|
|
|
158
191
|
};
|
|
159
192
|
```
|
|
160
193
|
|
|
161
|
-
|
|
194
|
+
#### Class Components
|
|
162
195
|
```tsx
|
|
163
196
|
// Named class
|
|
164
197
|
export default class MyComponent extends React.Component {
|
|
@@ -175,7 +208,7 @@ export default class MyComponent extends Component<Props> {
|
|
|
175
208
|
}
|
|
176
209
|
```
|
|
177
210
|
|
|
178
|
-
|
|
211
|
+
#### TypeScript Components
|
|
179
212
|
```tsx
|
|
180
213
|
// Function with TypeScript
|
|
181
214
|
interface Props {
|
|
@@ -240,6 +273,102 @@ export default withIdeButton(Button, 'src/components/Button.tsx', {
|
|
|
240
273
|
});
|
|
241
274
|
```
|
|
242
275
|
|
|
276
|
+
### Named Export Pattern
|
|
277
|
+
Before (your original named exports):
|
|
278
|
+
```tsx
|
|
279
|
+
// src/components/Buttons.tsx
|
|
280
|
+
export const PrimaryButton = ({ children, onClick }) => {
|
|
281
|
+
return (
|
|
282
|
+
<button className="primary" onClick={onClick}>
|
|
283
|
+
{children}
|
|
284
|
+
</button>
|
|
285
|
+
);
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export const SecondaryButton = ({ children, onClick }) => {
|
|
289
|
+
return (
|
|
290
|
+
<button className="secondary" onClick={onClick}>
|
|
291
|
+
{children}
|
|
292
|
+
</button>
|
|
293
|
+
);
|
|
294
|
+
};
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
After (automatically transformed):
|
|
298
|
+
```tsx
|
|
299
|
+
// src/components/Buttons.tsx (transformed by the plugin)
|
|
300
|
+
import { withIdeButton } from 'nextjs-ide-plugin/withIdeButton';
|
|
301
|
+
|
|
302
|
+
export const PrimaryButton = withIdeButton(({ children, onClick }) => {
|
|
303
|
+
return (
|
|
304
|
+
<button className="primary" onClick={onClick}>
|
|
305
|
+
{children}
|
|
306
|
+
</button>
|
|
307
|
+
);
|
|
308
|
+
}, 'src/components/Buttons.tsx', {
|
|
309
|
+
projectRoot: '/path/to/project',
|
|
310
|
+
ideType: 'cursor'
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
export const SecondaryButton = withIdeButton(({ children, onClick }) => {
|
|
314
|
+
return (
|
|
315
|
+
<button className="secondary" onClick={onClick}>
|
|
316
|
+
{children}
|
|
317
|
+
</button>
|
|
318
|
+
);
|
|
319
|
+
}, 'src/components/Buttons.tsx', {
|
|
320
|
+
projectRoot: '/path/to/project',
|
|
321
|
+
ideType: 'cursor'
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Mixed Named and Default Exports
|
|
326
|
+
Before (mixed exports):
|
|
327
|
+
```tsx
|
|
328
|
+
// src/components/Layout.tsx
|
|
329
|
+
export const Header = () => <header>My App Header</header>;
|
|
330
|
+
export const Footer = () => <footer>© 2025 My App</footer>;
|
|
331
|
+
|
|
332
|
+
const Layout = ({ children }) => (
|
|
333
|
+
<div>
|
|
334
|
+
<Header />
|
|
335
|
+
<main>{children}</main>
|
|
336
|
+
<Footer />
|
|
337
|
+
</div>
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
export default Layout;
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
After (automatically transformed):
|
|
344
|
+
```tsx
|
|
345
|
+
// src/components/Layout.tsx (transformed by the plugin)
|
|
346
|
+
import { withIdeButton } from 'nextjs-ide-plugin/withIdeButton';
|
|
347
|
+
|
|
348
|
+
export const Header = withIdeButton(() => <header>My App Header</header>, 'src/components/Layout.tsx', {
|
|
349
|
+
projectRoot: '/path/to/project',
|
|
350
|
+
ideType: 'cursor'
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
export const Footer = withIdeButton(() => <footer>© 2025 My App</footer>, 'src/components/Layout.tsx', {
|
|
354
|
+
projectRoot: '/path/to/project',
|
|
355
|
+
ideType: 'cursor'
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
const Layout = ({ children }) => (
|
|
359
|
+
<div>
|
|
360
|
+
<Header />
|
|
361
|
+
<main>{children}</main>
|
|
362
|
+
<Footer />
|
|
363
|
+
</div>
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
export default withIdeButton(Layout, 'src/components/Layout.tsx', {
|
|
367
|
+
projectRoot: '/path/to/project',
|
|
368
|
+
ideType: 'cursor'
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
243
372
|
### Direct Export Function Component
|
|
244
373
|
Before:
|
|
245
374
|
```tsx
|
|
@@ -327,6 +456,13 @@ See [CHANGELOG.md](./CHANGELOG.md) for detailed release notes.
|
|
|
327
456
|
|
|
328
457
|
### Recent Releases
|
|
329
458
|
|
|
459
|
+
### 1.4.0 - Named Export Support
|
|
460
|
+
- Added comprehensive support for ES6 named exports in React components
|
|
461
|
+
- Support for `export const Component = () => {}` and `export function Component() {}` patterns
|
|
462
|
+
- Mixed export support - files with both named and default exports
|
|
463
|
+
- Enhanced component detection to distinguish React components from utility exports
|
|
464
|
+
- Expanded test suite with 8 new comprehensive test cases
|
|
465
|
+
|
|
330
466
|
### 1.3.0 - Glob Pattern Support
|
|
331
467
|
- Added support for glob patterns in `componentPaths` configuration
|
|
332
468
|
- Support for nested directory matching with `**` patterns
|
package/lib/loader.js
CHANGED
|
@@ -5,11 +5,6 @@ const generate = require('@babel/generator').default;
|
|
|
5
5
|
const t = require('@babel/types');
|
|
6
6
|
const { minimatch } = require('minimatch');
|
|
7
7
|
|
|
8
|
-
console.log('.................................')
|
|
9
|
-
console.log('🔧 minimatch version:', require('minimatch/package.json').version);
|
|
10
|
-
console.log('minimatch is', require('minimatch'));
|
|
11
|
-
console.log('.................................')
|
|
12
|
-
|
|
13
8
|
/**
|
|
14
9
|
* Webpack loader that automatically wraps React components with cursor buttons
|
|
15
10
|
* @param {string} source - The source code of the file
|
|
@@ -19,8 +14,6 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
19
14
|
const filename = this.resourcePath;
|
|
20
15
|
const options = this.getOptions() || {};
|
|
21
16
|
|
|
22
|
-
console.log('🔧 Loader called for file:', filename);
|
|
23
|
-
|
|
24
17
|
const {
|
|
25
18
|
componentPaths = ['src/components'],
|
|
26
19
|
projectRoot = process.cwd(),
|
|
@@ -30,44 +23,34 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
30
23
|
|
|
31
24
|
// Only process if enabled
|
|
32
25
|
if (!enabled) {
|
|
33
|
-
console.log('🔧 Loader disabled, returning original source');
|
|
34
26
|
return source;
|
|
35
27
|
}
|
|
36
28
|
|
|
37
29
|
// Only process files in specified component directories
|
|
38
30
|
const relativePath = path.relative(projectRoot, filename);
|
|
39
|
-
console.log('🔧 Processing file:', relativePath, 'against paths:', componentPaths);
|
|
40
31
|
|
|
41
32
|
const shouldProcess = componentPaths.some(componentPath => {
|
|
42
|
-
console.log('🔧 Checking path:', componentPath);
|
|
43
33
|
// Check if componentPath contains glob patterns
|
|
44
34
|
if (componentPath.includes('*')) {
|
|
45
35
|
const matches = minimatch(relativePath, componentPath);
|
|
46
|
-
console.log('🔧 Glob match result:', matches, 'for pattern:', componentPath);
|
|
47
36
|
return matches;
|
|
48
37
|
} else {
|
|
49
38
|
// Fallback to the original behavior for non-glob patterns
|
|
50
39
|
const matches = filename.includes(path.resolve(projectRoot, componentPath));
|
|
51
|
-
console.log('🔧 Direct path match result:', matches);
|
|
52
40
|
return matches;
|
|
53
41
|
}
|
|
54
42
|
});
|
|
55
43
|
|
|
56
|
-
console.log('🔧 Should process:', shouldProcess);
|
|
57
44
|
|
|
58
45
|
if (!shouldProcess || (!filename.endsWith('.tsx') && !filename.endsWith('.jsx'))) {
|
|
59
|
-
console.log('🔧 File does not match criteria, skipping');
|
|
60
46
|
return source;
|
|
61
47
|
}
|
|
62
48
|
|
|
63
49
|
// Check if it's already wrapped using simple string check for performance
|
|
64
50
|
if (source.includes('withIdeButton')) {
|
|
65
|
-
console.log('🔧 File already contains withIdeButton, skipping');
|
|
66
51
|
return source;
|
|
67
52
|
}
|
|
68
53
|
|
|
69
|
-
console.log('🔧 Proceeding to transform file:', relativePath);
|
|
70
|
-
|
|
71
54
|
let ast;
|
|
72
55
|
try {
|
|
73
56
|
// Parse the source code into an AST
|
|
@@ -99,6 +82,7 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
99
82
|
let hasWithIdeButtonImport = false;
|
|
100
83
|
let lastImportPath = null;
|
|
101
84
|
let defaultExportPath = null;
|
|
85
|
+
let namedExports = []; // Track named component exports
|
|
102
86
|
|
|
103
87
|
// Traverse the AST to analyze the code
|
|
104
88
|
traverse(ast, {
|
|
@@ -107,7 +91,7 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
107
91
|
|
|
108
92
|
// Check if withIdeButton is already imported
|
|
109
93
|
if (path.node.source.value === importPath) {
|
|
110
|
-
path.node.specifiers.forEach(spec => {
|
|
94
|
+
path.node.specifiers.forEach((spec) => {
|
|
111
95
|
if (t.isImportSpecifier(spec) && spec.imported.name === 'withIdeButton') {
|
|
112
96
|
hasWithIdeButtonImport = true;
|
|
113
97
|
}
|
|
@@ -146,17 +130,46 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
146
130
|
|
|
147
131
|
// Stop traversal once we find the default export
|
|
148
132
|
path.stop();
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
ExportNamedDeclaration(path) {
|
|
136
|
+
// Handle named exports like: export const Button = () => {}
|
|
137
|
+
if (path.node.declaration && t.isVariableDeclaration(path.node.declaration)) {
|
|
138
|
+
path.node.declaration.declarations.forEach((declarator) => {
|
|
139
|
+
if (t.isIdentifier(declarator.id) &&
|
|
140
|
+
declarator.id.name[0] === declarator.id.name[0].toUpperCase() &&
|
|
141
|
+
(t.isArrowFunctionExpression(declarator.init) ||
|
|
142
|
+
t.isFunctionExpression(declarator.init))) {
|
|
143
|
+
namedExports.push({
|
|
144
|
+
name: declarator.id.name,
|
|
145
|
+
path: path,
|
|
146
|
+
declarator: declarator
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// Handle named function exports like: export function Button() {}
|
|
152
|
+
else if (path.node.declaration && t.isFunctionDeclaration(path.node.declaration)) {
|
|
153
|
+
const funcName = path.node.declaration.id.name;
|
|
154
|
+
if (funcName[0] === funcName[0].toUpperCase()) {
|
|
155
|
+
namedExports.push({
|
|
156
|
+
name: funcName,
|
|
157
|
+
path: path,
|
|
158
|
+
declaration: path.node.declaration
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
149
162
|
}
|
|
150
163
|
});
|
|
151
164
|
|
|
152
165
|
// Check if we should process this file
|
|
153
|
-
if (!hasDefaultExport || (!defaultExportName && !isAnonymousComponent)) {
|
|
166
|
+
if ((!hasDefaultExport || (!defaultExportName && !isAnonymousComponent)) && namedExports.length === 0) {
|
|
154
167
|
return source;
|
|
155
168
|
}
|
|
156
169
|
|
|
157
170
|
// Check if component name starts with uppercase (React component convention)
|
|
158
|
-
// Skip this check for anonymous components
|
|
159
|
-
if (defaultExportName && defaultExportName[0] !== defaultExportName[0].toUpperCase()) {
|
|
171
|
+
// Skip this check for anonymous components and if we have named exports
|
|
172
|
+
if (defaultExportName && defaultExportName[0] !== defaultExportName[0].toUpperCase() && namedExports.length === 0) {
|
|
160
173
|
return source;
|
|
161
174
|
}
|
|
162
175
|
|
|
@@ -170,26 +183,69 @@ module.exports = function cursorButtonLoader(source) {
|
|
|
170
183
|
// Transform the AST
|
|
171
184
|
let modified = false;
|
|
172
185
|
|
|
173
|
-
// Add the withIdeButton import
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
186
|
+
// Add the withIdeButton import if we have exports to process
|
|
187
|
+
if ((hasDefaultExport && (defaultExportName || isAnonymousComponent)) || namedExports.length > 0) {
|
|
188
|
+
const withIdeButtonImport = t.importDeclaration(
|
|
189
|
+
[t.importSpecifier(t.identifier('withIdeButton'), t.identifier('withIdeButton'))],
|
|
190
|
+
t.stringLiteral(importPath)
|
|
191
|
+
);
|
|
178
192
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
modified = true;
|
|
183
|
-
} else {
|
|
184
|
-
// No imports found, add at the beginning
|
|
185
|
-
if (ast.program && ast.program.body && Array.isArray(ast.program.body)) {
|
|
186
|
-
ast.program.body.unshift(withIdeButtonImport);
|
|
193
|
+
// Insert import after last existing import or at the beginning
|
|
194
|
+
if (lastImportPath) {
|
|
195
|
+
lastImportPath.insertAfter(withIdeButtonImport);
|
|
187
196
|
modified = true;
|
|
197
|
+
} else {
|
|
198
|
+
// No imports found, add at the beginning
|
|
199
|
+
if (ast.program && ast.program.body && Array.isArray(ast.program.body)) {
|
|
200
|
+
ast.program.body.unshift(withIdeButtonImport);
|
|
201
|
+
modified = true;
|
|
202
|
+
}
|
|
188
203
|
}
|
|
189
204
|
}
|
|
190
205
|
|
|
206
|
+
// Process named exports
|
|
207
|
+
namedExports.forEach(namedExport => {
|
|
208
|
+
if (namedExport.declarator) {
|
|
209
|
+
// Handle export const Component = () => {}
|
|
210
|
+
const wrappedCall = t.callExpression(
|
|
211
|
+
t.identifier('withIdeButton'),
|
|
212
|
+
[
|
|
213
|
+
namedExport.declarator.init,
|
|
214
|
+
t.stringLiteral(relativePath),
|
|
215
|
+
t.objectExpression([
|
|
216
|
+
t.objectProperty(t.identifier('projectRoot'), t.stringLiteral(projectRoot))
|
|
217
|
+
])
|
|
218
|
+
]
|
|
219
|
+
);
|
|
220
|
+
namedExport.declarator.init = wrappedCall;
|
|
221
|
+
modified = true;
|
|
222
|
+
} else if (namedExport.declaration) {
|
|
223
|
+
// Handle export function Component() {}
|
|
224
|
+
const funcDeclaration = namedExport.declaration;
|
|
225
|
+
const wrappedCall = t.callExpression(
|
|
226
|
+
t.identifier('withIdeButton'),
|
|
227
|
+
[
|
|
228
|
+
t.identifier(namedExport.name),
|
|
229
|
+
t.stringLiteral(relativePath),
|
|
230
|
+
t.objectExpression([
|
|
231
|
+
t.objectProperty(t.identifier('projectRoot'), t.stringLiteral(projectRoot))
|
|
232
|
+
])
|
|
233
|
+
]
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
// Insert the function declaration before the export
|
|
237
|
+
namedExport.path.insertBefore(funcDeclaration);
|
|
238
|
+
|
|
239
|
+
// Replace the export with wrapped call
|
|
240
|
+
namedExport.path.node.declaration = t.variableDeclaration('const', [
|
|
241
|
+
t.variableDeclarator(t.identifier(namedExport.name), wrappedCall)
|
|
242
|
+
]);
|
|
243
|
+
modified = true;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
191
247
|
// Replace the default export with wrapped version
|
|
192
|
-
if (defaultExportPath &&
|
|
248
|
+
if (defaultExportPath && (hasDefaultExport && (defaultExportName || isAnonymousComponent))) {
|
|
193
249
|
let wrappedCall;
|
|
194
250
|
|
|
195
251
|
if (isAnonymousComponent) {
|
package/lib/plugin.js
CHANGED
|
@@ -42,8 +42,6 @@ function withCursorHelper(options = {}) {
|
|
|
42
42
|
webpack: (webpackConfig, context) => {
|
|
43
43
|
const { dev, isServer } = context;
|
|
44
44
|
|
|
45
|
-
console.log('🔧 Webpack config called:', { dev, isServer, enabled: config.enabled });
|
|
46
|
-
|
|
47
45
|
// Only apply in development and for client-side
|
|
48
46
|
if (config.enabled && dev && !isServer) {
|
|
49
47
|
// Extract base directories from glob patterns for webpack's include
|
|
@@ -51,7 +49,6 @@ function withCursorHelper(options = {}) {
|
|
|
51
49
|
config.componentPaths.map(p => extractBaseDirectory(p))
|
|
52
50
|
)].map(p => path.resolve(config.projectRoot, p));
|
|
53
51
|
|
|
54
|
-
console.log('🔧 Adding webpack rule with include directories:', includeDirectories);
|
|
55
52
|
|
|
56
53
|
const rule = {
|
|
57
54
|
test: /\.tsx?$/,
|
package/lib/withIdeButton.js
CHANGED
|
@@ -26,20 +26,19 @@ const IdeButton = ({ filePath, projectRoot, ideType = 'cursor' }) => {
|
|
|
26
26
|
};
|
|
27
27
|
return ((0, jsx_runtime_1.jsx)("button", { onClick: handleClick, style: {
|
|
28
28
|
position: 'absolute',
|
|
29
|
-
top: '
|
|
30
|
-
right: '
|
|
29
|
+
top: '4px',
|
|
30
|
+
right: '4px',
|
|
31
|
+
width: '10px',
|
|
32
|
+
height: '10px',
|
|
31
33
|
background: '#007acc',
|
|
32
|
-
color: 'white',
|
|
33
34
|
border: 'none',
|
|
34
|
-
borderRadius: '
|
|
35
|
-
padding:
|
|
36
|
-
fontSize: '12px',
|
|
35
|
+
borderRadius: '50%',
|
|
36
|
+
padding: 0,
|
|
37
37
|
cursor: 'pointer',
|
|
38
38
|
zIndex: 1000,
|
|
39
|
-
opacity: 0.
|
|
40
|
-
transition: 'opacity 0.2s'
|
|
41
|
-
|
|
42
|
-
}, onMouseEnter: (e) => (e.currentTarget.style.opacity = '1'), onMouseLeave: (e) => (e.currentTarget.style.opacity = '0.7'), title: `Open ${filePath} in ${ideType.toUpperCase()}`, children: "\uD83D\uDCDD" }));
|
|
39
|
+
opacity: 0.6,
|
|
40
|
+
transition: 'opacity 0.2s'
|
|
41
|
+
}, onMouseEnter: (e) => (e.currentTarget.style.opacity = '1'), onMouseLeave: (e) => (e.currentTarget.style.opacity = '0.6'), title: `Open ${filePath} in ${ideType.toUpperCase()}` }));
|
|
43
42
|
};
|
|
44
43
|
function withIdeButton(WrappedComponent, filePath, options = {}) {
|
|
45
44
|
const { projectRoot, enabled = process.env.NODE_ENV === 'development', ideType = 'cursor' } = options;
|
package/lib/withIdeButton.tsx
CHANGED
|
@@ -35,26 +35,23 @@ const IdeButton: React.FC<IdeButtonProps> = ({ filePath, projectRoot, ideType =
|
|
|
35
35
|
onClick={handleClick}
|
|
36
36
|
style={{
|
|
37
37
|
position: 'absolute',
|
|
38
|
-
top: '
|
|
39
|
-
right: '
|
|
38
|
+
top: '4px',
|
|
39
|
+
right: '4px',
|
|
40
|
+
width: '10px',
|
|
41
|
+
height: '10px',
|
|
40
42
|
background: '#007acc',
|
|
41
|
-
color: 'white',
|
|
42
43
|
border: 'none',
|
|
43
|
-
borderRadius: '
|
|
44
|
-
padding:
|
|
45
|
-
fontSize: '12px',
|
|
44
|
+
borderRadius: '50%',
|
|
45
|
+
padding: 0,
|
|
46
46
|
cursor: 'pointer',
|
|
47
47
|
zIndex: 1000,
|
|
48
|
-
opacity: 0.
|
|
49
|
-
transition: 'opacity 0.2s'
|
|
50
|
-
fontFamily: 'monospace'
|
|
48
|
+
opacity: 0.6,
|
|
49
|
+
transition: 'opacity 0.2s'
|
|
51
50
|
}}
|
|
52
51
|
onMouseEnter={(e) => (e.currentTarget.style.opacity = '1')}
|
|
53
|
-
onMouseLeave={(e) => (e.currentTarget.style.opacity = '0.
|
|
52
|
+
onMouseLeave={(e) => (e.currentTarget.style.opacity = '0.6')}
|
|
54
53
|
title={`Open ${filePath} in ${ideType.toUpperCase()}`}
|
|
55
|
-
|
|
56
|
-
📝
|
|
57
|
-
</button>
|
|
54
|
+
/>
|
|
58
55
|
);
|
|
59
56
|
};
|
|
60
57
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nextjs-ide-helper",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "A Next.js plugin that automatically adds IDE buttons to React components for seamless IDE integration. Supports Cursor, VS Code, WebStorm, and Atom.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"src"
|
|
10
10
|
],
|
|
11
11
|
"scripts": {
|
|
12
|
-
"build": "tsc",
|
|
12
|
+
"build": "tsc && cp src/loader.js lib/loader.js",
|
|
13
13
|
"prepare": "npm run build",
|
|
14
14
|
"test": "jest"
|
|
15
15
|
},
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"next": ">=13.0.0",
|
|
33
33
|
"react": ">=18.0.0"
|
|
34
34
|
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"minimatch": "^10.0.3"
|
|
37
|
+
},
|
|
38
|
+
|
|
35
39
|
"devDependencies": {
|
|
36
40
|
"@babel/generator": "^7.28.0",
|
|
37
41
|
"@babel/parser": "^7.28.0",
|
|
@@ -40,8 +44,7 @@
|
|
|
40
44
|
"@types/jest": "^30.0.0",
|
|
41
45
|
"@types/node": "^20.19.9",
|
|
42
46
|
"@types/react": "^18.3.23",
|
|
43
|
-
"jest": "^30.0.5",
|
|
44
|
-
"minimatch": "^10.0.3",
|
|
47
|
+
"jest": "^30.0.5",
|
|
45
48
|
"typescript": "^5.8.3"
|
|
46
49
|
},
|
|
47
50
|
"repository": {
|