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.
@@ -188,8 +188,9 @@ export default Button;`;
188
188
  mockContext.getOptions.mockReturnValue({ enabled: true });
189
189
  });
190
190
 
191
- it('should not process files without default export', function() {
192
- const source = `export const Button = () => <button>Click</button>;`;
191
+ it('should not process files without any React component exports', function() {
192
+ const source = `export const API_URL = 'http://localhost:3000';
193
+ export const utils = { format: () => {} };`;
193
194
 
194
195
  const result = loader.call(mockContext, source);
195
196
 
@@ -197,6 +198,127 @@ export default Button;`;
197
198
  expect(result).not.toContain('withIdeButton');
198
199
  });
199
200
 
201
+ it('should process named exports and wrap them with withIdeButton', function() {
202
+ const source = `export const Button = () => <button>Click</button>;
203
+ export const Modal = () => <div>Modal</div>;`;
204
+
205
+ const result = loader.call(mockContext, source);
206
+
207
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
208
+ expect(result).toContain("export const Button = withIdeButton(() => <button>Click</button>,");
209
+ expect(result).toContain("export const Modal = withIdeButton(() => <div>Modal</div>,");
210
+ expect(result).toMatch(/projectRoot: ['"][^'"]*['"]/);
211
+
212
+ // Verify the complete structure
213
+ const lines = result.split('\n');
214
+ const importLine = lines.find(line => line.includes("import { withIdeButton }"));
215
+ const buttonLine = lines.find(line => line.includes("export const Button = withIdeButton"));
216
+ const modalLine = lines.find(line => line.includes("export const Modal = withIdeButton"));
217
+
218
+ expect(importLine).toBeDefined();
219
+ expect(buttonLine).toBeDefined();
220
+ expect(modalLine).toBeDefined();
221
+
222
+ // Verify each wrapped export contains the file path
223
+ expect(buttonLine).toContain("'src/components/Button.tsx'");
224
+ expect(modalLine).toContain("'src/components/Button.tsx'");
225
+ });
226
+
227
+ it('should process mixed named and default exports', function() {
228
+ const source = `export const Button = () => <button>Click</button>;
229
+
230
+ const MainComponent = () => <div>Main</div>;
231
+ export default MainComponent;`;
232
+
233
+ const result = loader.call(mockContext, source);
234
+
235
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
236
+ expect(result).toContain("export const Button = withIdeButton(() => <button>Click</button>,");
237
+ expect(result).toContain("export default withIdeButton(MainComponent,");
238
+
239
+ // Verify both exports are properly wrapped
240
+ const lines = result.split('\n');
241
+ const namedExportLine = lines.find(line => line.includes("export const Button = withIdeButton"));
242
+ const defaultExportLine = lines.find(line => line.includes("export default withIdeButton(MainComponent"));
243
+
244
+ expect(namedExportLine).toBeDefined();
245
+ expect(defaultExportLine).toBeDefined();
246
+
247
+ // Verify file paths are included
248
+ expect(namedExportLine).toContain("'src/components/Button.tsx'");
249
+ expect(defaultExportLine).toContain("'src/components/Button.tsx'");
250
+ });
251
+
252
+ it('should process named function exports', function() {
253
+ const source = `export function MyButton() {
254
+ return <button>Function Button</button>;
255
+ }
256
+
257
+ export function MyModal() {
258
+ return <div>Function Modal</div>;
259
+ }`;
260
+
261
+ const result = loader.call(mockContext, source);
262
+
263
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
264
+
265
+ // For function exports, the function should be declared first, then wrapped
266
+ expect(result).toContain("function MyButton()");
267
+ expect(result).toContain("function MyModal()");
268
+ expect(result).toContain("const MyButton = withIdeButton(MyButton,");
269
+ expect(result).toContain("const MyModal = withIdeButton(MyModal,");
270
+
271
+ // Verify file paths
272
+ expect(result).toContain("'src/components/Button.tsx'");
273
+ });
274
+
275
+ it('should not process lowercase named exports', function() {
276
+ const source = `export const button = () => <button>lowercase</button>;
277
+ export const modal = () => <div>lowercase modal</div>;`;
278
+
279
+ const result = loader.call(mockContext, source);
280
+
281
+ expect(result).toBe(source);
282
+ expect(result).not.toContain('withIdeButton');
283
+ });
284
+
285
+ it('should process complex mixed scenario with multiple export types', function() {
286
+ const source = `import React from 'react';
287
+
288
+ export const PrimaryButton = () => <button className="primary">Primary</button>;
289
+ export const SecondaryButton = () => <button className="secondary">Secondary</button>;
290
+
291
+ export function DialogModal() {
292
+ return <div>Dialog Content</div>;
293
+ }
294
+
295
+ const MainLayout = ({ children }) => <div className="layout">{children}</div>;
296
+ export default MainLayout;`;
297
+
298
+ const result = loader.call(mockContext, source);
299
+
300
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
301
+
302
+ // Named arrow function exports
303
+ expect(result).toContain("export const PrimaryButton = withIdeButton(() => <button className=\"primary\">Primary</button>,");
304
+ expect(result).toContain("export const SecondaryButton = withIdeButton(() => <button className=\"secondary\">Secondary</button>,");
305
+
306
+ // Named function export
307
+ expect(result).toContain("function DialogModal()");
308
+ expect(result).toContain("const DialogModal = withIdeButton(DialogModal,");
309
+
310
+ // Default export
311
+ expect(result).toContain("export default withIdeButton(MainLayout,");
312
+
313
+ // Verify React import is preserved and withIdeButton import is added after it
314
+ const lines = result.split('\n');
315
+ const reactImportIndex = lines.findIndex(line => line.includes("import React from 'react'"));
316
+ const withIdeButtonImportIndex = lines.findIndex(line => line.includes("import { withIdeButton }"));
317
+
318
+ expect(reactImportIndex).toBeGreaterThan(-1);
319
+ expect(withIdeButtonImportIndex).toBeGreaterThan(reactImportIndex);
320
+ });
321
+
200
322
  it('should not process files with lowercase default export', function() {
201
323
  const source = `const button = () => <button>Click</button>;
202
324
  export default button;`;
@@ -323,6 +445,218 @@ export default class TSClassComponent extends Component<Props> {
323
445
  expect(result).toContain("export default withIdeButton(TSClassComponent,");
324
446
  expect(result).toContain("class TSClassComponent extends Component<Props>");
325
447
  });
448
+
449
+ it('should process named exports with TypeScript types', function() {
450
+ const source = `interface ButtonProps {
451
+ onClick: () => void;
452
+ }
453
+
454
+ export const TypedButton = ({ onClick }: ButtonProps) => <button onClick={onClick}>Typed Button</button>;
455
+
456
+ type ModalProps = {
457
+ isOpen: boolean;
458
+ }
459
+
460
+ export const TypedModal = ({ isOpen }: ModalProps) => isOpen ? <div>Modal</div> : null;`;
461
+
462
+ const result = loader.call(mockContext, source);
463
+
464
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
465
+ expect(result).toContain("export const TypedButton = withIdeButton(({");
466
+ expect(result).toContain("onClick");
467
+ expect(result).toContain("}: ButtonProps) => <button onClick={onClick}>Typed Button</button>,");
468
+ expect(result).toContain("export const TypedModal = withIdeButton(({");
469
+ expect(result).toContain("isOpen");
470
+ expect(result).toContain("}: ModalProps) => isOpen ? <div>Modal</div> : null,");
471
+
472
+ // Verify interfaces and types are preserved
473
+ expect(result).toContain("interface ButtonProps");
474
+ expect(result).toContain("type ModalProps");
475
+ });
476
+
477
+ it('should handle mixed named exports with non-component exports', function() {
478
+ const source = `export const API_URL = 'https://api.example.com';
479
+ export const utils = { format: () => {} };
480
+
481
+ export const Button = () => <button>Click</button>;
482
+ export const Modal = () => <div>Modal</div>;
483
+
484
+ export const config = { theme: 'dark' };`;
485
+
486
+ const result = loader.call(mockContext, source);
487
+
488
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
489
+
490
+ // Component exports should be wrapped
491
+ expect(result).toContain("export const Button = withIdeButton(() => <button>Click</button>,");
492
+ expect(result).toContain("export const Modal = withIdeButton(() => <div>Modal</div>,");
493
+
494
+ // Non-component exports should remain unchanged (check for key parts since formatting may vary)
495
+ expect(result).toContain("export const API_URL = 'https://api.example.com';");
496
+ expect(result).toContain("export const utils = {");
497
+ expect(result).toContain("format: () => {}");
498
+ expect(result).toContain("export const config = {");
499
+ expect(result).toContain("theme: 'dark'");
500
+ });
501
+
502
+ it('should handle complex export patterns with existing imports', function() {
503
+ const source = `import React, { useState, useEffect } from 'react';
504
+ import { someUtil } from './utils';
505
+
506
+ export const InteractiveButton = () => {
507
+ const [count, setCount] = useState(0);
508
+ return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
509
+ };
510
+
511
+ export function StatefulModal() {
512
+ useEffect(() => {
513
+ console.log('Modal mounted');
514
+ }, []);
515
+ return <div>Stateful Modal</div>;
516
+ }
517
+
518
+ const ComplexComponent = () => {
519
+ return <div>Complex</div>;
520
+ };
521
+
522
+ export default ComplexComponent;`;
523
+
524
+ const result = loader.call(mockContext, source);
525
+
526
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
527
+
528
+ // Verify all imports are preserved
529
+ expect(result).toContain("import React, { useState, useEffect } from 'react';");
530
+ expect(result).toContain("import { someUtil } from './utils';");
531
+
532
+ // Verify withIdeButton import is added after existing imports
533
+ const lines = result.split('\n');
534
+ const reactImportIndex = lines.findIndex(line => line.includes("import React"));
535
+ const utilImportIndex = lines.findIndex(line => line.includes("import { someUtil }"));
536
+ const withIdeButtonImportIndex = lines.findIndex(line => line.includes("import { withIdeButton }"));
537
+
538
+ expect(withIdeButtonImportIndex).toBeGreaterThan(Math.max(reactImportIndex, utilImportIndex));
539
+
540
+ // Verify component transformations
541
+ expect(result).toContain("export const InteractiveButton = withIdeButton(() => {");
542
+ expect(result).toContain("function StatefulModal()");
543
+ expect(result).toContain("const StatefulModal = withIdeButton(StatefulModal,");
544
+ expect(result).toContain("export default withIdeButton(ComplexComponent,");
545
+ });
546
+
547
+ it('should handle files with only named exports (no default export)', function() {
548
+ const source = `export const HeaderButton = () => <button>Header</button>;
549
+ export const FooterButton = () => <button>Footer</button>;
550
+ export const SidebarButton = () => <button>Sidebar</button>;`;
551
+
552
+ const result = loader.call(mockContext, source);
553
+
554
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
555
+ expect(result).toContain("export const HeaderButton = withIdeButton(() => <button>Header</button>,");
556
+ expect(result).toContain("export const FooterButton = withIdeButton(() => <button>Footer</button>,");
557
+ expect(result).toContain("export const SidebarButton = withIdeButton(() => <button>Sidebar</button>,");
558
+
559
+ // Verify no default export processing
560
+ expect(result).not.toContain("export default");
561
+ });
562
+
563
+ it('should preserve comments and formatting in named exports', function() {
564
+ const source = `// Header comment
565
+ export const Button = () => <button>Click</button>; // Inline comment
566
+
567
+ /* Block comment */
568
+ export const Modal = () => <div>Modal</div>;`;
569
+
570
+ const result = loader.call(mockContext, source);
571
+
572
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
573
+ expect(result).toContain("export const Button = withIdeButton(() => <button>Click</button>,");
574
+ expect(result).toContain("export const Modal = withIdeButton(() => <div>Modal</div>,");
575
+ });
576
+
577
+ it('should not double-wrap components that are both named and default exports', function() {
578
+ const source = `const MyComponent = () => <div>Shared Component</div>;
579
+
580
+ export { MyComponent }; // named export
581
+ export default MyComponent; // default export`;
582
+
583
+ const result = loader.call(mockContext, source);
584
+
585
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
586
+
587
+ // Should only have one withIdeButton import
588
+ const importMatches = (result.match(/import.*withIdeButton/g) || []);
589
+ expect(importMatches).toHaveLength(1);
590
+
591
+ // Should only wrap once - either as named or default, not both
592
+ const withIdeButtonMatches = (result.match(/withIdeButton\(/g) || []);
593
+ expect(withIdeButtonMatches.length).toBeLessThanOrEqual(2); // At most one for named, one for default
594
+
595
+ // Verify the component isn't wrapped multiple times in the same export
596
+ expect(result).not.toContain("withIdeButton(withIdeButton(");
597
+ });
598
+
599
+ it('should handle component exported as both const and default', function() {
600
+ const source = `export const MyComponent = () => <div>Component</div>;
601
+ export default MyComponent;`;
602
+
603
+ const result = loader.call(mockContext, source);
604
+
605
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
606
+
607
+ // Should only have one withIdeButton import
608
+ const importMatches = (result.match(/import.*withIdeButton/g) || []);
609
+ expect(importMatches).toHaveLength(1);
610
+
611
+ // Should wrap both the named export and default export separately
612
+ expect(result).toContain("export const MyComponent = withIdeButton(() => <div>Component</div>,");
613
+ expect(result).toContain("export default withIdeButton(MyComponent,");
614
+
615
+ // But shouldn't double-wrap
616
+ expect(result).not.toContain("withIdeButton(withIdeButton(");
617
+ });
618
+
619
+ it('should handle TypeScript React.FC named exports', function() {
620
+ const source = `import React from 'react';
621
+
622
+ interface TestComponentProps {
623
+ message: string;
624
+ }
625
+
626
+ export const TestComponent: React.FC<TestComponentProps> = ({ message }) => {
627
+ return (
628
+ <div style={{
629
+ padding: '20px',
630
+ margin: '10px',
631
+ border: '2px solid #007acc',
632
+ borderRadius: '8px',
633
+ backgroundColor: '#f0f8ff'
634
+ }}>
635
+ <h2>Test Component</h2>
636
+ <p>{message}</p>
637
+ </div>
638
+ );
639
+ };`;
640
+
641
+ const result = loader.call(mockContext, source);
642
+
643
+ expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
644
+ expect(result).toContain("export const TestComponent: React.FC<TestComponentProps> = withIdeButton(");
645
+ expect(result).toContain("'src/components/Button.tsx'");
646
+
647
+ // Verify the original React import is preserved
648
+ expect(result).toContain("import React from 'react';");
649
+
650
+ // Verify the interface is preserved
651
+ expect(result).toContain("interface TestComponentProps");
652
+
653
+ // Verify the component function is properly wrapped (check for message parameter)
654
+ expect(result).toContain("message");
655
+ expect(result).toContain("}) => {");
656
+
657
+ // Verify TypeScript type annotation is preserved
658
+ expect(result).toContain("React.FC<TestComponentProps>");
659
+ });
326
660
  });
327
661
 
328
662
  describe('already wrapped components', function() {
@@ -477,4 +811,6 @@ export default Button;`;
477
811
  expect(result).toContain("'src/components/Button.tsx'");
478
812
  });
479
813
  });
814
+
815
+
480
816
  });
package/src/loader.js CHANGED
@@ -14,8 +14,6 @@ module.exports = function cursorButtonLoader(source) {
14
14
  const filename = this.resourcePath;
15
15
  const options = this.getOptions() || {};
16
16
 
17
- console.log('🔧 Loader called for file:', filename);
18
-
19
17
  const {
20
18
  componentPaths = ['src/components'],
21
19
  projectRoot = process.cwd(),
@@ -25,44 +23,34 @@ module.exports = function cursorButtonLoader(source) {
25
23
 
26
24
  // Only process if enabled
27
25
  if (!enabled) {
28
- console.log('🔧 Loader disabled, returning original source');
29
26
  return source;
30
27
  }
31
28
 
32
29
  // Only process files in specified component directories
33
30
  const relativePath = path.relative(projectRoot, filename);
34
- console.log('🔧 Processing file:', relativePath, 'against paths:', componentPaths);
35
31
 
36
32
  const shouldProcess = componentPaths.some(componentPath => {
37
- console.log('🔧 Checking path:', componentPath);
38
33
  // Check if componentPath contains glob patterns
39
34
  if (componentPath.includes('*')) {
40
35
  const matches = minimatch(relativePath, componentPath);
41
- console.log('🔧 Glob match result:', matches, 'for pattern:', componentPath);
42
36
  return matches;
43
37
  } else {
44
38
  // Fallback to the original behavior for non-glob patterns
45
39
  const matches = filename.includes(path.resolve(projectRoot, componentPath));
46
- console.log('🔧 Direct path match result:', matches);
47
40
  return matches;
48
41
  }
49
42
  });
50
43
 
51
- console.log('🔧 Should process:', shouldProcess);
52
44
 
53
45
  if (!shouldProcess || (!filename.endsWith('.tsx') && !filename.endsWith('.jsx'))) {
54
- console.log('🔧 File does not match criteria, skipping');
55
46
  return source;
56
47
  }
57
48
 
58
49
  // Check if it's already wrapped using simple string check for performance
59
50
  if (source.includes('withIdeButton')) {
60
- console.log('🔧 File already contains withIdeButton, skipping');
61
51
  return source;
62
52
  }
63
53
 
64
- console.log('🔧 Proceeding to transform file:', relativePath);
65
-
66
54
  let ast;
67
55
  try {
68
56
  // Parse the source code into an AST
@@ -94,6 +82,7 @@ module.exports = function cursorButtonLoader(source) {
94
82
  let hasWithIdeButtonImport = false;
95
83
  let lastImportPath = null;
96
84
  let defaultExportPath = null;
85
+ let namedExports = []; // Track named component exports
97
86
 
98
87
  // Traverse the AST to analyze the code
99
88
  traverse(ast, {
@@ -102,7 +91,7 @@ module.exports = function cursorButtonLoader(source) {
102
91
 
103
92
  // Check if withIdeButton is already imported
104
93
  if (path.node.source.value === importPath) {
105
- path.node.specifiers.forEach(spec => {
94
+ path.node.specifiers.forEach((spec) => {
106
95
  if (t.isImportSpecifier(spec) && spec.imported.name === 'withIdeButton') {
107
96
  hasWithIdeButtonImport = true;
108
97
  }
@@ -141,17 +130,46 @@ module.exports = function cursorButtonLoader(source) {
141
130
 
142
131
  // Stop traversal once we find the default export
143
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
+ }
144
162
  }
145
163
  });
146
164
 
147
165
  // Check if we should process this file
148
- if (!hasDefaultExport || (!defaultExportName && !isAnonymousComponent)) {
166
+ if ((!hasDefaultExport || (!defaultExportName && !isAnonymousComponent)) && namedExports.length === 0) {
149
167
  return source;
150
168
  }
151
169
 
152
170
  // Check if component name starts with uppercase (React component convention)
153
- // Skip this check for anonymous components
154
- 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) {
155
173
  return source;
156
174
  }
157
175
 
@@ -165,26 +183,69 @@ module.exports = function cursorButtonLoader(source) {
165
183
  // Transform the AST
166
184
  let modified = false;
167
185
 
168
- // Add the withIdeButton import
169
- const withIdeButtonImport = t.importDeclaration(
170
- [t.importSpecifier(t.identifier('withIdeButton'), t.identifier('withIdeButton'))],
171
- t.stringLiteral(importPath)
172
- );
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
+ );
173
192
 
174
- // Insert import after last existing import or at the beginning
175
- if (lastImportPath) {
176
- lastImportPath.insertAfter(withIdeButtonImport);
177
- modified = true;
178
- } else {
179
- // No imports found, add at the beginning
180
- if (ast.program && ast.program.body && Array.isArray(ast.program.body)) {
181
- ast.program.body.unshift(withIdeButtonImport);
193
+ // Insert import after last existing import or at the beginning
194
+ if (lastImportPath) {
195
+ lastImportPath.insertAfter(withIdeButtonImport);
182
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
+ }
183
203
  }
184
204
  }
185
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
+
186
247
  // Replace the default export with wrapped version
187
- if (defaultExportPath && modified) {
248
+ if (defaultExportPath && (hasDefaultExport && (defaultExportName || isAnonymousComponent))) {
188
249
  let wrappedCall;
189
250
 
190
251
  if (isAnonymousComponent) {
@@ -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: '8px',
39
- right: '8px',
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: '4px',
44
- padding: '4px 8px',
45
- fontSize: '12px',
44
+ borderRadius: '50%',
45
+ padding: 0,
46
46
  cursor: 'pointer',
47
47
  zIndex: 1000,
48
- opacity: 0.7,
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.7')}
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