@inspecto-dev/core 0.2.0-alpha.1 → 0.2.0-alpha.3

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/dist/index.js CHANGED
@@ -1,1268 +1,27 @@
1
- // src/styles.ts
2
- var overlayClass = "inspecto-overlay";
3
- var menuClass = "inspecto-menu";
4
- var menuItemClass = "inspecto-menu-item";
5
- var loadingSpinnerClass = "inspecto-spinner";
6
- var errorMsgClass = "inspecto-error";
7
- var badgeClass = "inspecto-badge";
8
- var menuInputClass = "inspecto-menu-input";
9
- var menuInputWrapperClass = "inspecto-menu-input-wrapper";
10
- var menuInputIconClass = "inspecto-menu-input-icon";
11
- var tooltipClass = "inspecto-tooltip";
12
- var tooltipTopClass = "inspecto-tooltip-top";
13
- var tooltipBottomClass = "inspecto-tooltip-bottom";
14
- var tagClass = "inspecto-tag";
15
- var idClass = "inspecto-id";
16
- var classClass = "inspecto-class";
17
- var dimClass = "inspecto-dim";
18
- var separatorClass = "inspecto-separator";
19
- var sourceClass = "inspecto-source";
20
- var shortcutIconClass = "ai-shortcut-icon";
21
- var darkVars = `
22
- --inspecto-menu-bg: #252526;
23
- --inspecto-menu-border: #454545;
24
- --inspecto-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
25
- --inspecto-text: #cccccc;
26
- --inspecto-text-muted: #858585;
27
- --inspecto-hover-bg: #04395e;
28
- --inspecto-hover-text: #ffffff;
29
- --inspecto-hover-icon: #ffffff;
30
- --inspecto-input-bg: #3c3c3c;
31
- --inspecto-input-border: #007acc;
32
- --inspecto-shortcut-text: #858585;
33
- --inspecto-badge-bg: rgba(30, 30, 30, 0.7);
34
- --inspecto-badge-text: #e5e5e5;
35
- --inspecto-badge-active-bg: #007acc;
36
- --inspecto-badge-active-text: #ffffff;
37
- --inspecto-badge-border: 1px solid rgba(255, 255, 255, 0.1);
38
-
39
- --inspecto-tooltip-bg: #222222;
40
- --inspecto-tooltip-text: #cccccc;
41
- --inspecto-tooltip-border: #444;
42
- --inspecto-tooltip-shadow: 0 2px 10px rgba(0,0,0,0.5);
43
- --inspecto-tag-color: #d16969;
44
- --inspecto-id-color: #d16969;
45
- --inspecto-class-color: #9cdcfe;
46
- --inspecto-dim-color: #858585;
47
- --inspecto-error-color: #ef4444;
48
- `;
49
- var inspectorStyles = `
50
- :host {
51
- /* Light theme (default) */
52
- --inspecto-menu-bg: #ffffff;
53
- --inspecto-menu-border: #d4d4d4;
54
- --inspecto-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
55
- --inspecto-text: #333333;
56
- --inspecto-text-muted: #6b7280;
57
- --inspecto-hover-bg: #0060c0;
58
- --inspecto-hover-text: #ffffff;
59
- --inspecto-hover-icon: #ffffff;
60
- --inspecto-input-bg: #ffffff;
61
- --inspecto-input-border: #007acc;
62
- --inspecto-shortcut-text: #9ca3af;
63
- --inspecto-badge-bg: rgba(30, 30, 30, 0.7);
64
- --inspecto-badge-text: #e5e5e5;
65
- --inspecto-badge-active-bg: #007acc;
66
- --inspecto-badge-active-text: #ffffff;
67
- --inspecto-badge-border: 1px solid rgba(255, 255, 255, 0.1);
68
-
69
- /* Chrome DevTools like colors */
70
- --inspecto-overlay-border: #4285f4; /* Google Blue */
71
- --inspecto-overlay-bg: rgba(66, 133, 244, 0.2);
72
- --inspecto-tooltip-bg: #ffffff;
73
- --inspecto-tooltip-text: #333333;
74
- --inspecto-tooltip-border: #ccc;
75
- --inspecto-tooltip-shadow: 0 2px 10px rgba(0,0,0,0.1);
76
-
77
- --inspecto-tag-color: #8b008b; /* Dark magenta */
78
- --inspecto-id-color: #8b008b;
79
- --inspecto-class-color: #00008b; /* Dark blue */
80
- --inspecto-dim-color: #555555;
81
- --inspecto-error-color: #ef4444;
82
- }
83
-
84
- :host([data-theme="dark"]) {
85
- ${darkVars}
86
- }
87
-
88
- @media (prefers-color-scheme: dark) {
89
- :host(:not([data-theme="light"])) {
90
- ${darkVars}
91
- }
92
- }
93
-
94
- .${overlayClass} {
95
- position: fixed;
96
- pointer-events: none;
97
- z-index: 2147483646;
98
- border: 1px dashed var(--inspecto-overlay-border);
99
- background: var(--inspecto-overlay-bg);
100
- box-sizing: border-box;
101
- transition: all 0.05s linear;
102
- }
103
-
104
- .${tooltipClass} {
105
- position: fixed;
106
- pointer-events: none;
107
- z-index: 2147483647;
108
- background: var(--inspecto-tooltip-bg);
109
- color: var(--inspecto-tooltip-text);
110
- border: 1px solid var(--inspecto-tooltip-border);
111
- border-radius: 4px;
112
- box-shadow: var(--inspecto-tooltip-shadow);
113
- padding: 6px 10px;
114
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
115
- font-size: 12px;
116
- line-height: 1.4;
117
- transition: all 0.05s linear;
118
- display: flex;
119
- flex-direction: column;
120
- gap: 4px;
121
- }
122
-
123
- /* Create the small pointer arrow like Chrome DevTools */
124
- .${tooltipClass}::after {
125
- content: '';
126
- position: absolute;
127
- width: 0;
128
- height: 0;
129
- border-style: solid;
130
- }
131
-
132
- .${tooltipTopClass}::after {
133
- bottom: -6px;
134
- left: var(--inspecto-arrow-left, 10px);
135
- border-width: 6px 6px 0 6px;
136
- border-color: var(--inspecto-tooltip-bg) transparent transparent transparent;
137
- }
138
-
139
- .${tooltipBottomClass}::after {
140
- top: -6px;
141
- left: var(--inspecto-arrow-left, 10px);
142
- border-width: 0 6px 6px 6px;
143
- border-color: transparent transparent var(--inspecto-tooltip-bg) transparent;
144
- }
145
-
146
- /* Outline for the arrow to match border */
147
- .${tooltipClass}::before {
148
- content: '';
149
- position: absolute;
150
- width: 0;
151
- height: 0;
152
- border-style: solid;
153
- }
154
-
155
- .${tooltipTopClass}::before {
156
- bottom: -7px;
157
- left: calc(var(--inspecto-arrow-left, 10px) - 1px);
158
- border-width: 7px 7px 0 7px;
159
- border-color: var(--inspecto-tooltip-border) transparent transparent transparent;
160
- }
161
-
162
- .${tooltipBottomClass}::before {
163
- top: -7px;
164
- left: calc(var(--inspecto-arrow-left, 10px) - 1px);
165
- border-width: 0 7px 7px 7px;
166
- border-color: transparent transparent var(--inspecto-tooltip-border) transparent;
167
- }
168
-
169
- .${tagClass} {
170
- color: var(--inspecto-tag-color);
171
- font-weight: 600;
172
- font-family: monospace;
173
- }
174
-
175
- .${idClass} {
176
- color: var(--inspecto-id-color);
177
- font-weight: 600;
178
- font-family: monospace;
179
- }
180
-
181
- .${classClass} {
182
- color: var(--inspecto-class-color);
183
- font-family: monospace;
184
- }
185
-
186
- .${dimClass} {
187
- color: var(--inspecto-dim-color);
188
- margin-left: 4px;
189
- }
190
-
191
- .${separatorClass} {
192
- height: 1px;
193
- background: var(--inspecto-tooltip-border);
194
- margin: 2px -10px;
195
- opacity: 0.5;
196
- }
197
-
198
- .${sourceClass} {
199
- font-family: 'SF Mono', 'Fira Code', monospace;
200
- font-size: 11px;
201
- color: var(--inspecto-text-muted);
202
- white-space: nowrap;
203
- overflow: hidden;
204
- text-overflow: ellipsis;
205
- max-width: 300px;
206
- }
207
-
208
- .${menuClass} {
209
- position: fixed;
210
- z-index: 2147483647;
211
- background: var(--inspecto-menu-bg);
212
- border: 1px solid var(--inspecto-menu-border);
213
- border-radius: 6px;
214
- padding: 6px;
215
- min-width: 300px;
216
- box-shadow: var(--inspecto-menu-shadow);
217
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
218
- color: var(--inspecto-text);
219
- }
220
-
221
- .${menuInputWrapperClass} {
222
- display: flex;
223
- align-items: center;
224
- border: 1px solid var(--inspecto-menu-border);
225
- border-radius: 4px;
226
- padding: 6px 8px;
227
- margin: 4px;
228
- margin-bottom: 8px;
229
- }
230
-
231
- .${menuInputWrapperClass}:focus-within {
232
- border-color: var(--inspecto-input-border);
233
- }
234
-
235
- .${menuInputClass} {
236
- width: 100%;
237
- border: none;
238
- outline: none;
239
- font-size: 13px;
240
- color: var(--inspecto-text);
241
- background: transparent;
242
- }
243
-
244
- .${menuInputClass}::placeholder {
245
- color: var(--inspecto-text-muted);
246
- }
247
-
248
- .${menuInputIconClass} {
249
- color: var(--inspecto-text-muted);
250
- display: flex;
251
- align-items: center;
252
- justify-content: center;
253
- margin-left: 4px;
254
- }
255
-
256
- .${menuInputIconClass}:hover {
257
- color: var(--inspecto-text);
258
- }
259
-
260
- .${menuItemClass} {
261
- display: flex;
262
- align-items: center;
263
- gap: 8px;
264
- width: 100%;
265
- padding: 6px 10px;
266
- margin: 2px 0;
267
- border: none;
268
- border-radius: 4px;
269
- background: transparent;
270
- color: var(--inspecto-text);
271
- font-size: 13px;
272
- cursor: pointer;
273
- text-align: left;
274
- }
275
-
276
- .${menuItemClass}:hover {
277
- background: var(--inspecto-hover-bg);
278
- color: var(--inspecto-hover-text);
279
- }
280
-
281
- .${menuItemClass} .${shortcutIconClass} {
282
- margin-left: auto;
283
- color: var(--inspecto-text-muted);
284
- }
285
-
286
- .${menuItemClass}:hover .${shortcutIconClass} {
287
- color: var(--inspecto-hover-icon);
288
- }
289
-
290
- @keyframes spin {
291
- to { transform: rotate(360deg); }
292
- }
293
-
294
- .${loadingSpinnerClass} {
295
- width: 14px;
296
- height: 14px;
297
- border: 2px solid var(--inspecto-overlay-border);
298
- border-top-color: transparent;
299
- border-radius: 50%;
300
- animation: spin 0.7s linear infinite;
301
- margin: 4px auto;
302
- display: block;
303
- }
304
-
305
- .${errorMsgClass} {
306
- font-size: 11px;
307
- color: var(--inspecto-error-color);
308
- padding: 4px 8px;
309
- text-align: center;
310
- }
311
-
312
- .${badgeClass} {
313
- position: fixed;
314
- bottom: 16px;
315
- right: 16px;
316
- z-index: 2147483645;
317
- background: var(--inspecto-badge-bg);
318
- color: var(--inspecto-badge-text);
319
- border: var(--inspecto-badge-border);
320
- border-radius: 20px;
321
- padding: 6px 12px;
322
- font-size: 12px;
323
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
324
- cursor: grab;
325
- opacity: 0.85;
326
- transition: background 0.2s, color 0.2s, opacity 0.2s, box-shadow 0.2s;
327
- pointer-events: all;
328
- backdrop-filter: blur(4px);
329
- -webkit-backdrop-filter: blur(4px);
330
- display: flex;
331
- align-items: center;
332
- gap: 6px;
333
- user-select: none;
334
- -webkit-user-select: none;
335
- touch-action: none;
336
- }
337
-
338
- .${badgeClass}:active {
339
- cursor: grabbing;
340
- }
341
-
342
- .${badgeClass}-close {
343
- display: inline-flex;
344
- align-items: center;
345
- justify-content: center;
346
- width: 16px;
347
- height: 16px;
348
- border-radius: 50%;
349
- background: transparent;
350
- color: currentColor;
351
- font-size: 14px;
352
- line-height: 1;
353
- opacity: 0.5;
354
- transition: opacity 0.2s, background 0.2s;
355
- margin-left: 2px;
356
- cursor: pointer;
357
- }
358
-
359
- .${badgeClass}-close:hover {
360
- opacity: 1;
361
- background: rgba(255, 255, 255, 0.2);
362
- }
363
-
364
- .${badgeClass}.active {
365
- background: var(--inspecto-badge-active-bg);
366
- color: var(--inspecto-badge-active-text);
367
- border: 1px solid transparent;
368
- box-shadow: 0 0 10px rgba(0, 122, 204, 0.3);
369
- }
370
-
371
- .${badgeClass}.disabled {
372
- background: rgba(30, 30, 30, 0.4);
373
- color: rgba(229, 229, 229, 0.5);
374
- text-decoration: line-through;
375
- border: 1px dashed rgba(255, 255, 255, 0.1);
376
- }
377
-
378
- .${badgeClass}.disabled .${badgeClass}-close {
379
- opacity: 0.8;
380
- text-decoration: none;
381
- transform: rotate(45deg);
382
- }
383
-
384
- .${badgeClass}:hover {
385
- opacity: 1;
386
- }
387
- `;
388
-
389
- // src/overlay.ts
390
- var GAP = 8;
391
- var EDGE_MARGIN = 4;
392
- function createOverlay(shadowRoot) {
393
- const overlay = document.createElement("div");
394
- overlay.className = overlayClass;
395
- overlay.style.display = "none";
396
- const tooltip = document.createElement("div");
397
- tooltip.className = tooltipClass;
398
- const tagSpan = document.createElement("span");
399
- tagSpan.className = tagClass;
400
- const idSpan = document.createElement("span");
401
- idSpan.className = idClass;
402
- const classSpan = document.createElement("span");
403
- classSpan.className = classClass;
404
- const dimSpan = document.createElement("span");
405
- dimSpan.className = dimClass;
406
- const separator = document.createElement("div");
407
- separator.className = separatorClass;
408
- const sourceSpan = document.createElement("div");
409
- sourceSpan.className = sourceClass;
410
- tooltip.appendChild(tagSpan);
411
- tooltip.appendChild(idSpan);
412
- tooltip.appendChild(classSpan);
413
- tooltip.appendChild(document.createTextNode(" "));
414
- tooltip.appendChild(dimSpan);
415
- tooltip.appendChild(separator);
416
- tooltip.appendChild(sourceSpan);
417
- shadowRoot.appendChild(overlay);
418
- shadowRoot.appendChild(tooltip);
419
- function show(el, sourceLabel) {
420
- const rect = el.getBoundingClientRect();
421
- overlay.style.display = "block";
422
- overlay.style.left = `${rect.left}px`;
423
- overlay.style.top = `${rect.top}px`;
424
- overlay.style.width = `${rect.width}px`;
425
- overlay.style.height = `${rect.height}px`;
426
- const tagName = el.tagName.toLowerCase();
427
- tagSpan.textContent = tagName;
428
- idSpan.textContent = el.id ? `#${el.id}` : "";
429
- const classes = Array.from(el.classList).map((c) => `.${c}`).join("");
430
- classSpan.textContent = classes;
431
- dimSpan.textContent = `${Math.round(rect.width)} \xD7 ${Math.round(rect.height)}`;
432
- sourceSpan.textContent = sourceLabel;
433
- tooltip.style.visibility = "hidden";
434
- tooltip.style.display = "block";
435
- const tooltipRect = tooltip.getBoundingClientRect();
436
- const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
437
- const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
438
- let tooltipTop = rect.top - tooltipRect.height - GAP;
439
- let isBottom = false;
440
- if (tooltipTop < EDGE_MARGIN) {
441
- tooltipTop = rect.bottom + GAP;
442
- if (tooltipTop + tooltipRect.height > viewportHeight - EDGE_MARGIN) {
443
- tooltipTop = viewportHeight - tooltipRect.height - EDGE_MARGIN;
444
- }
445
- isBottom = true;
446
- }
447
- tooltip.classList.toggle(tooltipBottomClass, isBottom);
448
- tooltip.classList.toggle(tooltipTopClass, !isBottom);
449
- let tooltipLeft = rect.left;
450
- if (tooltipLeft + tooltipRect.width > viewportWidth - EDGE_MARGIN) {
451
- tooltipLeft = viewportWidth - tooltipRect.width - EDGE_MARGIN;
452
- }
453
- if (tooltipLeft < EDGE_MARGIN) {
454
- tooltipLeft = EDGE_MARGIN;
455
- }
456
- const targetPointX = rect.left + Math.min(15, rect.width / 2);
457
- let arrowLeft = targetPointX - tooltipLeft;
458
- arrowLeft = Math.max(6, Math.min(arrowLeft, tooltipRect.width - 18));
459
- tooltip.style.left = `${tooltipLeft}px`;
460
- tooltip.style.top = `${tooltipTop}px`;
461
- tooltip.style.setProperty("--inspecto-arrow-left", `${arrowLeft}px`);
462
- tooltip.style.visibility = "visible";
463
- }
464
- function hide() {
465
- overlay.style.display = "none";
466
- tooltip.style.display = "none";
467
- }
468
- return { show, hide };
469
- }
470
-
471
- // src/intents.ts
472
- function CUSTOM_PROMPT_TEMPLATE(userPrompt) {
473
- return userPrompt;
474
- }
475
- var DEFAULT_INTENTS = [
476
- // ── 1. Explain Component ─────────────────────────────────────────────────
477
- // Frequency: ★★★★★ — Most common action when navigating unfamiliar codebases
478
- {
479
- id: "explain",
480
- label: "Explain Component",
481
- prompt: `The following is a {{framework}} component from \`{{file}}\` (line {{line}}).
482
-
483
- Please explain:
484
-
485
- 1. What this component does and its responsibility in the UI
486
- 2. Key props and their purpose
487
- 3. Important state or side effects (if applicable)
488
- 4. Any non-obvious logic or edge cases worth noting`
489
- },
490
- // ── 2. Fix Bug ───────────────────────────────────────────────────────────
491
- // Frequency: ★★★★★ — Debugging is the highest time-cost activity in frontend dev
492
- {
493
- id: "fix-bug",
494
- label: "Fix Bug",
495
- prompt: `I found a bug in the following {{framework}} component from \`{{file}}\` (line {{line}}).
496
-
497
- Please:
498
-
499
- 1. Identify potential bugs or issues in this code
500
- 2. Explain the root cause of each issue
501
- 3. Provide a fixed version with minimal changes
502
-
503
- If you need more context (e.g. parent component, API response shape),
504
- please ask before suggesting a fix.`
505
- },
506
- // ── 3. Fix Styles ────────────────────────────────────────────────────────
507
- // Frequency: ★★★★ — Styling issues are top-3 daily pain points for frontend devs
508
- {
509
- id: "fix-styles",
510
- label: "Fix Styles",
511
- prompt: `The following component from \`{{file}}\` (line {{line}}) has a styling issue.
512
-
513
- Please:
514
-
515
- 1. Review the current styles (className / inline styles / CSS-in-JS / Style blocks)
516
- 2. Identify common issues: layout shifts, overflow, z-index conflicts,
517
- responsive breakpoints, or visual inconsistencies
518
- 3. Suggest fixes using the same styling approach already in use
519
-
520
- Note: Maintain the existing styling conventions (e.g. Tailwind, CSS Modules, scoped styles).`
521
- },
522
- // ── 4. Refactor Component ────────────────────────────────────────────────
523
- // Frequency: ★★★★ — Sustained demand after features stabilize; large component splits
524
- {
525
- id: "refactor",
526
- label: "Refactor Component",
527
- prompt: `Please refactor the following {{framework}} component from \`{{file}}\` (line {{line}}).
528
-
529
- Refactoring goals (apply as relevant):
530
-
531
- - Extract reusable sub-components or composables/hooks
532
- - Improve readability and reduce complexity
533
- - Remove redundant state or unnecessary re-renders
534
- - Apply {{framework}} best practices
535
- - Maintain existing behavior \u2014 no functional changes
536
-
537
- Please show the refactored version with a brief explanation of each change.`
538
- },
539
- // ── 5. Code Review ───────────────────────────────────────────────────────
540
- // Frequency: ★★★ — Concentrated at PR stage; slightly less frequent than daily fixes
541
- {
542
- id: "code-review",
543
- label: "Code Review",
544
- prompt: `Please do a code review for the following {{framework}} component from \`{{file}}\` (line {{line}}).
545
-
546
- Review dimensions:
547
-
548
- - Correctness: logic errors, edge cases, race conditions
549
- - {{framework}} best practices: lifecycle usage, key props, reactivity rules
550
- - Performance: unnecessary renders, missing memoization
551
- - Accessibility: ARIA attributes, keyboard navigation, semantic HTML
552
- - Security: XSS risks, unsafe HTML injection, user input handling
553
- - Maintainability: naming clarity, code duplication, complexity
554
-
555
- Format your response as a prioritized list: \u{1F534} Critical / \u{1F7E1} Warning / \u{1F7E2} Suggestion.`
556
- },
557
- // ── 6. Generate Test ─────────────────────────────────────────────────────
558
- // Frequency: ★★★ — Common but often deferred; great AI use case
559
- {
560
- id: "generate-test",
561
- label: "Generate Test",
562
- prompt: `Please generate unit tests for the following {{framework}} component from \`{{file}}\` (line {{line}}).
563
-
564
- Requirements:
565
-
566
- - Use Vitest + Testing Library (or Jest if the codebase implies it)
567
- - Cover: render correctness, user interactions, edge cases, error states
568
- - Mock external dependencies (API calls, context/providers, router)
569
- - Use accessible queries (getByRole, getByLabelText) over getByTestId
570
-
571
- Generate a complete, runnable test file. Include all import statements.`
572
- },
573
- // ── 7. Performance Analysis ──────────────────────────────────────────────
574
- // Frequency: ★★ — Targeted use during perf sprints; not a daily operation
575
- {
576
- id: "performance",
577
- label: "Performance Analysis",
578
- prompt: `Please analyze the performance of the following {{framework}} component from \`{{file}}\` (line {{line}}).
579
-
580
- Focus on:
581
-
582
- 1. Unnecessary re-renders or reactive updates
583
- 2. Expensive computations that should be memoized/computed
584
- 3. Heavy operations in the render path
585
- 4. Dependency arrays or watchers \u2014 missing or over-specified
586
- 5. Large bundle impact (heavy imports that could be lazy-loaded)
587
-
588
- For each issue found, provide: problem description \u2192 recommended fix \u2192 expected impact.`
589
- },
590
- // ── 8. Open in Editor ────────────────────────────────────────────────────
591
- // Type: local action (no AI prompt) — jumps directly to source in IDE
592
- {
593
- id: "open-in-editor",
594
- label: "Open in Editor",
595
- prompt: "",
596
- // unused — isAction handles this
597
- isAction: true
598
- }
599
- ];
600
- function detectFramework(fileName) {
601
- const ext = fileName.split(".").pop()?.toLowerCase() || "";
602
- switch (ext) {
603
- case "vue":
604
- return "Vue";
605
- case "svelte":
606
- return "Svelte";
607
- case "astro":
608
- return "Astro";
609
- case "jsx":
610
- case "tsx":
611
- return "React";
612
- case "ts":
613
- case "js":
614
- return "JavaScript/TypeScript";
615
- default:
616
- return "UI";
617
- }
618
- }
619
- function buildPrompt(template, location, snippetResult) {
620
- const shortFile = location.file.split("/").pop() ?? location.file;
621
- const ext = shortFile.split(".").pop()?.toLowerCase() || "tsx";
622
- const framework = detectFramework(shortFile);
623
- let finalPrompt = template.replace(/\{\{file\}\}/g, location.file).replace(/\{\{line\}\}/g, String(location.line)).replace(/\{\{column\}\}/g, String(location.column)).replace(/\{\{ext\}\}/g, ext).replace(/\{\{framework\}\}/g, framework).replace(/\{\{name\}\}/g, shortFile);
624
- if (snippetResult && snippetResult.snippet) {
625
- const name = snippetResult.name ?? shortFile;
626
- finalPrompt = finalPrompt.replace(/\{\{name\}\}/g, name);
627
- finalPrompt += `
628
-
629
- Context from \`${location.file}\` (line ${location.line}):
630
- \`\`\`${ext}
631
- ${snippetResult.snippet}
632
- \`\`\``;
633
- }
634
- return finalPrompt;
635
- }
636
-
637
- // src/http.ts
638
- var BASE_URL = globalThis.__AI_INSPECTOR_SERVER_URL__ || "http://127.0.0.1:5678";
639
- function setBaseUrl(url) {
640
- BASE_URL = url.replace(/\/$/, "");
641
- }
642
- var cachedConfig = null;
643
- async function fetchIdeInfo(force = false) {
644
- if (cachedConfig && !force) return cachedConfig;
645
- try {
646
- const res = await fetch(`${BASE_URL}/config`);
647
- if (!res.ok) return null;
648
- cachedConfig = await res.json();
649
- return cachedConfig;
650
- } catch {
651
- return null;
652
- }
653
- }
654
- async function openFile(req) {
655
- try {
656
- const res = await fetch(`${BASE_URL}/open`, {
657
- method: "POST",
658
- headers: { "Content-Type": "application/json" },
659
- body: JSON.stringify(req)
660
- });
661
- return res.ok;
662
- } catch {
663
- return false;
664
- }
665
- }
666
- async function fetchSnippet(file, line, column, maxLines = 100) {
667
- const params = new URLSearchParams({
668
- file,
669
- line: String(line),
670
- column: String(column),
671
- maxLines: String(maxLines)
672
- });
673
- const res = await fetch(`${BASE_URL}/snippet?${params}`);
674
- if (!res.ok) {
675
- const err = await res.json().catch(() => ({}));
676
- throw Object.assign(new Error("snippet fetch failed"), { errorCode: err.errorCode });
677
- }
678
- return res.json();
679
- }
680
- async function sendToAi(req) {
681
- const res = await fetch(`${BASE_URL}/send-to-ai`, {
682
- method: "POST",
683
- headers: { "Content-Type": "application/json" },
684
- body: JSON.stringify(req)
685
- });
686
- if (!res.ok) {
687
- const err = await res.json().catch(() => ({}));
688
- return {
689
- success: false,
690
- error: err.error ?? "Request failed",
691
- errorCode: err.errorCode
692
- };
693
- }
694
- return res.json();
695
- }
696
-
697
- // src/menu.ts
698
- var MENU_WIDTH = 280;
699
- function showIntentMenu(shadowRoot, location, clickX, clickY, options, onClose) {
700
- const maxSnippetLines = options.maxSnippetLines ?? 100;
701
- const includeSnippet = options.includeSnippet ?? false;
702
- const menu = document.createElement("div");
703
- menu.className = menuClass;
704
- const { input, inputWrapper, sendIcon } = createAskInput(options.askPlaceholder);
705
- menu.appendChild(inputWrapper);
706
- const separator = document.createElement("div");
707
- separator.style.height = "1px";
708
- separator.style.background = "var(--inspecto-menu-border)";
709
- separator.style.margin = "8px 4px 6px 4px";
710
- menu.appendChild(separator);
711
- const loadingEl = document.createElement("div");
712
- loadingEl.className = loadingSpinnerClass;
713
- menu.appendChild(loadingEl);
714
- menu.style.left = `${Math.min(clickX, window.innerWidth - MENU_WIDTH)}px`;
715
- menu.style.visibility = "hidden";
716
- menu.style.display = "block";
717
- shadowRoot.appendChild(menu);
718
- const updatePosition = () => {
719
- const rect = menu.getBoundingClientRect();
720
- menu.style.top = `${Math.min(clickY + 8, window.innerHeight - rect.height - 8)}px`;
721
- };
722
- updatePosition();
723
- menu.style.visibility = "visible";
724
- setTimeout(() => input.focus(), 0);
725
- const onDocClick = (e) => {
726
- const path = e.composedPath();
727
- if (path.includes(menu)) return;
728
- cleanup();
729
- };
730
- setTimeout(() => document.addEventListener("click", onDocClick, { capture: true }), 0);
731
- function cleanup() {
732
- document.removeEventListener("click", onDocClick, { capture: true });
733
- menu.remove();
734
- onClose();
735
- }
736
- const handleSend = async (promptText, snippetText, disable, restore) => {
737
- disable();
738
- await openFile(location);
739
- await new Promise((r) => setTimeout(r, 100));
740
- const result = await sendToAi({ location, snippet: snippetText, prompt: promptText });
741
- if (result.success) {
742
- cleanup();
743
- } else {
744
- restore();
745
- showError(menu, result.error ?? "Unknown error", result.errorCode);
746
- }
747
- };
748
- const submitAsk = async () => {
749
- if (!input.value.trim()) return;
750
- input.disabled = true;
751
- sendIcon.style.pointerEvents = "none";
752
- try {
753
- let snippetResult = null;
754
- if (includeSnippet) {
755
- snippetResult = await fetchSnippet(
756
- location.file,
757
- location.line,
758
- location.column,
759
- maxSnippetLines
760
- );
761
- }
762
- const prompt = buildPrompt(
763
- CUSTOM_PROMPT_TEMPLATE(input.value.trim()),
764
- location,
765
- snippetResult
766
- );
767
- await handleSend(
768
- prompt,
769
- snippetResult?.snippet || "",
770
- () => {
771
- },
772
- // already disabled
773
- () => {
774
- input.disabled = false;
775
- sendIcon.style.pointerEvents = "auto";
776
- }
777
- );
778
- } catch (err) {
779
- input.disabled = false;
780
- sendIcon.style.pointerEvents = "auto";
781
- showError(menu, err.message, err.errorCode);
782
- }
783
- };
784
- input.addEventListener("keydown", (e) => {
785
- if (e.key === "Enter") submitAsk();
786
- });
787
- sendIcon.addEventListener("click", submitAsk);
788
- fetchIdeInfo().then((ideInfo) => {
789
- loadingEl.remove();
790
- const intents = resolveIntents(ideInfo?.prompts);
791
- for (const intent of intents) {
792
- if (intent.isAction && intent.id === "open-in-editor") {
793
- const btn2 = document.createElement("button");
794
- btn2.className = menuItemClass;
795
- const span = document.createElement("span");
796
- span.textContent = intent.label ?? "Unknown";
797
- btn2.appendChild(span);
798
- const shortcutDiv = document.createElement("div");
799
- shortcutDiv.className = shortcutIconClass;
800
- shortcutDiv.textContent = "\u21B5";
801
- btn2.appendChild(shortcutDiv);
802
- btn2.addEventListener("click", (e) => {
803
- e.stopPropagation();
804
- openFile(location);
805
- cleanup();
806
- });
807
- menu.appendChild(btn2);
808
- continue;
809
- }
810
- let fullPromptTemplate = intent.prompt ?? "";
811
- if (intent.prependPrompt)
812
- fullPromptTemplate = intent.prependPrompt + "\n\n" + fullPromptTemplate;
813
- if (intent.appendPrompt)
814
- fullPromptTemplate = fullPromptTemplate + "\n\n" + intent.appendPrompt;
815
- const label = intent.label ?? intent.id ?? "Unknown";
816
- const btn = document.createElement("button");
817
- btn.className = menuItemClass;
818
- btn.textContent = label;
819
- btn.addEventListener("click", async (e) => {
820
- e.stopPropagation();
821
- btn.disabled = true;
822
- btn.textContent = "Sending...";
823
- try {
824
- let snippetResult = null;
825
- if (includeSnippet) {
826
- snippetResult = await fetchSnippet(
827
- location.file,
828
- location.line,
829
- location.column,
830
- maxSnippetLines
831
- );
832
- }
833
- const prompt = buildPrompt(fullPromptTemplate, location, snippetResult);
834
- await handleSend(
835
- prompt,
836
- snippetResult?.snippet || "",
837
- () => {
838
- },
839
- // already disabled
840
- () => {
841
- btn.disabled = false;
842
- btn.textContent = label;
843
- }
844
- );
845
- } catch (err) {
846
- btn.disabled = false;
847
- btn.textContent = label;
848
- showError(menu, err.message, err.errorCode);
849
- }
850
- });
851
- menu.appendChild(btn);
852
- }
853
- updatePosition();
854
- }).catch((err) => {
855
- loadingEl.remove();
856
- const isServerDown = err instanceof TypeError;
857
- showError(
858
- menu,
859
- isServerDown ? "Cannot connect to inspector server. Is the dev server running?" : err.message,
860
- err.errorCode ?? "UNKNOWN"
861
- );
862
- updatePosition();
863
- });
864
- return cleanup;
865
- }
866
- function resolveIntents(serverPrompts) {
867
- const baseMap = /* @__PURE__ */ new Map();
868
- for (const intent of DEFAULT_INTENTS) {
869
- if (intent.id) baseMap.set(intent.id, { ...intent });
870
- }
871
- const defaults = () => ensureOpenInEditorLast(Array.from(baseMap.values()));
872
- if (!serverPrompts) return defaults();
873
- const isReplace = !Array.isArray(serverPrompts) && typeof serverPrompts === "object" && serverPrompts.$replace === true;
874
- const promptsArray = Array.isArray(serverPrompts) ? serverPrompts : isReplace ? serverPrompts.items : [];
875
- if (!promptsArray || promptsArray.length === 0) return defaults();
876
- if (isReplace) {
877
- const result = [];
878
- for (const item of promptsArray) {
879
- if (typeof item === "string") {
880
- if (baseMap.has(item)) {
881
- result.push(baseMap.get(item));
882
- } else {
883
- console.warn(
884
- `[inspecto] Unknown built-in intent id: "${item}". Available: ${[...baseMap.keys()].join(", ")}`
885
- );
886
- }
887
- } else if (typeof item === "object") {
888
- if (!item.id) {
889
- console.warn('[inspecto] Intent object missing required "id" field, skipping.');
890
- continue;
891
- }
892
- if (item.enabled === false) {
893
- console.warn(
894
- `[inspecto] Intent "${item.id}" is listed in $replace but has enabled:false \u2014 it will be excluded.`
895
- );
896
- continue;
897
- }
898
- if (item.isAction && item.id !== "open-in-editor") {
899
- console.warn(
900
- `[inspecto] isAction is reserved for built-in actions. Ignoring intent "${item.id}".`
901
- );
902
- continue;
903
- }
904
- result.push(baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item);
905
- }
906
- }
907
- return ensureOpenInEditorLast(result);
908
- }
909
- const merged = Array.from(baseMap.values());
910
- for (const item of promptsArray) {
911
- if (typeof item === "string") {
912
- if (!baseMap.has(item)) {
913
- console.warn(
914
- `[inspecto] Unknown built-in intent id: "${item}". In append mode, strings have no effect on ordering \u2014 use $replace to control order.`
915
- );
916
- }
917
- continue;
918
- }
919
- if (typeof item === "object") {
920
- if (!item.id) {
921
- console.warn('[inspecto] Intent object missing required "id" field, skipping.');
922
- continue;
923
- }
924
- if (item.isAction && item.id !== "open-in-editor") {
925
- console.warn(
926
- `[inspecto] isAction is reserved for built-in actions. Ignoring intent "${item.id}".`
927
- );
928
- continue;
929
- }
930
- const existingIdx = merged.findIndex((i) => i.id === item.id);
931
- if (existingIdx !== -1) {
932
- if (item.enabled === false) {
933
- merged.splice(existingIdx, 1);
934
- } else {
935
- merged[existingIdx] = { ...merged[existingIdx], ...item };
936
- }
937
- } else {
938
- if (item.enabled !== false) {
939
- merged.push(item);
940
- }
941
- }
942
- }
943
- }
944
- return ensureOpenInEditorLast(merged);
945
- }
946
- function ensureOpenInEditorLast(intents) {
947
- const idx = intents.findIndex((i) => i.id === "open-in-editor");
948
- if (idx === -1 || idx === intents.length - 1) return intents;
949
- const result = [...intents];
950
- const item = result.splice(idx, 1)[0];
951
- result.push(item);
952
- return result;
953
- }
954
- function createAskInput(placeholder) {
955
- const inputWrapper = document.createElement("div");
956
- inputWrapper.className = menuInputWrapperClass;
957
- const input = document.createElement("input");
958
- input.className = menuInputClass;
959
- input.type = "text";
960
- input.placeholder = placeholder ?? "Describe how to change this component...";
961
- const sendIcon = document.createElement("div");
962
- sendIcon.className = menuInputIconClass;
963
- sendIcon.innerHTML = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg>`;
964
- sendIcon.style.cursor = "pointer";
965
- inputWrapper.appendChild(input);
966
- inputWrapper.appendChild(sendIcon);
967
- return { input, inputWrapper, sendIcon };
968
- }
969
- function showError(menu, message, errorCode) {
970
- menu.querySelector(`.${errorMsgClass}`)?.remove();
971
- const errEl = document.createElement("div");
972
- errEl.className = errorMsgClass;
973
- errEl.textContent = errorCode === "FILE_NOT_FOUND" ? "Source file not found. Is the server running?" : `Error: ${message}`;
974
- menu.appendChild(errEl);
975
- }
976
-
977
- // src/component.ts
978
- var ATTR_NAME = "data-inspecto";
979
- function parseAttrValue(value) {
980
- const parts = value.split(":");
981
- if (parts.length < 3) return null;
982
- const col = parseInt(parts[parts.length - 1], 10);
983
- const line = parseInt(parts[parts.length - 2], 10);
984
- const file = parts.slice(0, parts.length - 2).join(":");
985
- if (isNaN(line) || isNaN(col) || !file) return null;
986
- return { file, line, column: col };
987
- }
988
- function findInspectable(el) {
989
- while (el) {
990
- if (el.hasAttribute(ATTR_NAME)) return el;
991
- el = el.parentElement;
992
- }
993
- return null;
994
- }
995
- function hotKeysHeld(event, hotKeys) {
996
- return hotKeys.every((key) => event[key]);
997
- }
998
- var BaseElement = typeof HTMLElement !== "undefined" ? HTMLElement : class {
999
- };
1000
- var InspectoElement = class extends BaseElement {
1001
- constructor() {
1002
- super(...arguments);
1003
- this.options = {};
1004
- this.serverHotKeys = null;
1005
- this.active = false;
1006
- this.disabled = false;
1007
- this.isDragging = false;
1008
- this.hasMoved = false;
1009
- this.dragStartX = 0;
1010
- this.dragStartY = 0;
1011
- this.badgeInitialRight = 16;
1012
- this.badgeInitialBottom = 16;
1013
- this.cleanupMenu = null;
1014
- this.onDragStart = (e) => {
1015
- if (e.button !== 0) return;
1016
- if (e.target.classList?.contains(`${badgeClass}-close`)) return;
1017
- e.preventDefault();
1018
- this.isDragging = true;
1019
- this.hasMoved = false;
1020
- const rect = this.badge.getBoundingClientRect();
1021
- this.dragStartX = e.clientX - rect.left;
1022
- this.dragStartY = e.clientY - rect.top;
1023
- document.addEventListener("mousemove", this.onDragMove);
1024
- document.addEventListener("mouseup", this.onDragEnd);
1025
- };
1026
- this.onDragMove = (e) => {
1027
- if (!this.isDragging) return;
1028
- this.hasMoved = true;
1029
- let newLeft = e.clientX - this.dragStartX;
1030
- let newTop = e.clientY - this.dragStartY;
1031
- const badgeWidth = this.badge.offsetWidth;
1032
- const badgeHeight = this.badge.offsetHeight;
1033
- newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - badgeWidth));
1034
- newTop = Math.max(0, Math.min(newTop, window.innerHeight - badgeHeight));
1035
- this.badge.style.transition = "none";
1036
- this.badge.style.right = "auto";
1037
- this.badge.style.bottom = "auto";
1038
- this.badge.style.left = `${newLeft}px`;
1039
- this.badge.style.top = `${newTop}px`;
1040
- };
1041
- this.onDragEnd = () => {
1042
- document.removeEventListener("mousemove", this.onDragMove);
1043
- document.removeEventListener("mouseup", this.onDragEnd);
1044
- this.badge.style.transition = "";
1045
- setTimeout(() => {
1046
- this.isDragging = false;
1047
- }, 0);
1048
- };
1049
- this.onMouseMove = (e) => {
1050
- const isActive = this.isInspectorActive(e);
1051
- if (!isActive) {
1052
- this.overlay.hide();
1053
- return;
1054
- }
1055
- const target = findInspectable(e.target);
1056
- if (!target) {
1057
- this.overlay.hide();
1058
- return;
1059
- }
1060
- const attrValue = target.getAttribute(ATTR_NAME);
1061
- const loc = parseAttrValue(attrValue);
1062
- const label = loc ? `${loc.file.split("/").pop() ?? ""}:${loc.line}` : attrValue;
1063
- this.overlay.show(target, label);
1064
- e.stopPropagation();
1065
- };
1066
- this.onClick = (e) => {
1067
- this.handleTrigger(e);
1068
- };
1069
- this.onContextMenu = (e) => {
1070
- if (this.isInspectorActive(e)) {
1071
- this.handleTrigger(e);
1072
- }
1073
- };
1074
- this.onKeyDown = (e) => {
1075
- if (e.key === "Escape") {
1076
- this.cleanupMenu?.();
1077
- this.overlay.hide();
1078
- }
1079
- };
1080
- }
1081
- connectedCallback() {
1082
- this.shadowRootEl = this.attachShadow({ mode: "open" });
1083
- const style = document.createElement("style");
1084
- style.textContent = inspectorStyles;
1085
- this.shadowRootEl.appendChild(style);
1086
- this.overlay = createOverlay(this.shadowRootEl);
1087
- this.badge = this.createBadge();
1088
- this.setupListeners();
1089
- if (this.options.defaultActive) {
1090
- this.setActive(true);
1091
- }
1092
- }
1093
- disconnectedCallback() {
1094
- this.teardownListeners();
1095
- }
1096
- configure(options) {
1097
- this.options = options;
1098
- if (options.serverUrl) {
1099
- setBaseUrl(options.serverUrl);
1100
- }
1101
- if (options.theme === "dark") {
1102
- this.setAttribute("data-theme", "dark");
1103
- } else if (options.theme === "light") {
1104
- this.setAttribute("data-theme", "light");
1105
- } else {
1106
- this.removeAttribute("data-theme");
1107
- }
1108
- fetchIdeInfo(true).then((info) => {
1109
- if (info?.hotKeys !== void 0) {
1110
- this.serverHotKeys = info.hotKeys;
1111
- this.updateBadgeContent();
1112
- }
1113
- if (info?.includeSnippet !== void 0) {
1114
- this.options.includeSnippet = info.includeSnippet;
1115
- }
1116
- }).catch(() => {
1117
- });
1118
- }
1119
- createBadge() {
1120
- const btn = document.createElement("button");
1121
- btn.className = badgeClass;
1122
- btn.style.display = "flex";
1123
- const textSpan = document.createElement("span");
1124
- textSpan.textContent = "Inspecto Ready";
1125
- const closeBtn = document.createElement("span");
1126
- closeBtn.className = `${badgeClass}-close`;
1127
- closeBtn.innerHTML = "\xD7";
1128
- closeBtn.title = "Pause Inspector";
1129
- closeBtn.addEventListener("click", (e) => {
1130
- e.stopPropagation();
1131
- this.toggleDisabled();
1132
- });
1133
- btn.appendChild(textSpan);
1134
- btn.appendChild(closeBtn);
1135
- btn.addEventListener("mousedown", this.onDragStart);
1136
- btn.addEventListener("click", (e) => {
1137
- if (this.hasMoved) {
1138
- this.hasMoved = false;
1139
- return;
1140
- }
1141
- if (this.disabled) {
1142
- this.toggleDisabled();
1143
- } else {
1144
- this.setActive(!this.active);
1145
- }
1146
- });
1147
- this.shadowRootEl.appendChild(btn);
1148
- return btn;
1149
- }
1150
- toggleDisabled() {
1151
- this.disabled = !this.disabled;
1152
- if (this.disabled) {
1153
- this.active = false;
1154
- this.overlay.hide();
1155
- this.cleanupMenu?.();
1156
- this.cleanupMenu = null;
1157
- }
1158
- this.updateBadgeContent();
1159
- }
1160
- dismiss() {
1161
- this.badge.style.display = "none";
1162
- this.setActive(false);
1163
- }
1164
- getHotKeyHint() {
1165
- const hotKeys = this.getEffectiveHotKeys();
1166
- if (hotKeys === false || hotKeys.length === 0) return "Inspecto Ready";
1167
- const isMac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
1168
- const keys = hotKeys.map((k) => {
1169
- if (k === "altKey") return isMac ? "\u2325" : "Alt";
1170
- if (k === "metaKey") return isMac ? "\u2318" : "Win";
1171
- if (k === "ctrlKey") return isMac ? "\u2303" : "Ctrl";
1172
- if (k === "shiftKey") return isMac ? "\u21E7" : "Shift";
1173
- return k;
1174
- });
1175
- return `Hold ${keys.join(" + ")} to Inspect`;
1176
- }
1177
- getEffectiveHotKeys() {
1178
- if (this.options.hotKeys !== void 0) return this.options.hotKeys;
1179
- if (this.serverHotKeys !== null) return this.serverHotKeys;
1180
- return ["altKey"];
1181
- }
1182
- updateBadgeContent() {
1183
- const textSpan = this.badge.querySelector("span");
1184
- if (!textSpan) return;
1185
- if (this.disabled) {
1186
- textSpan.textContent = "Inspector Paused";
1187
- this.badge.classList.remove("active");
1188
- this.badge.classList.add("disabled");
1189
- } else if (this.active) {
1190
- textSpan.textContent = "\u{1F50D} Inspecting...";
1191
- this.badge.classList.remove("disabled");
1192
- this.badge.classList.add("active");
1193
- } else {
1194
- textSpan.textContent = this.getHotKeyHint();
1195
- this.badge.classList.remove("active", "disabled");
1196
- }
1197
- }
1198
- setActive(value) {
1199
- this.active = value;
1200
- this.updateBadgeContent();
1201
- if (!value) {
1202
- this.overlay.hide();
1203
- this.cleanupMenu?.();
1204
- this.cleanupMenu = null;
1205
- }
1206
- }
1207
- handleTrigger(e) {
1208
- if (!this.isInspectorActive(e)) return;
1209
- const target = findInspectable(e.target);
1210
- if (!target) return;
1211
- e.preventDefault();
1212
- e.stopPropagation();
1213
- const attrValue = target.getAttribute(ATTR_NAME);
1214
- const loc = parseAttrValue(attrValue);
1215
- if (!loc) return;
1216
- this.cleanupMenu?.();
1217
- this.cleanupMenu = showIntentMenu(
1218
- this.shadowRootEl,
1219
- loc,
1220
- e.clientX,
1221
- e.clientY,
1222
- this.options,
1223
- () => {
1224
- this.cleanupMenu = null;
1225
- }
1226
- );
1227
- }
1228
- isInspectorActive(e) {
1229
- if (this.disabled) return false;
1230
- if (this.active) return true;
1231
- const hotKeys = this.getEffectiveHotKeys();
1232
- if (hotKeys === false) return false;
1233
- return hotKeysHeld(e, hotKeys);
1234
- }
1235
- setupListeners() {
1236
- document.addEventListener("mousemove", this.onMouseMove, true);
1237
- document.addEventListener("click", this.onClick, true);
1238
- document.addEventListener("contextmenu", this.onContextMenu, true);
1239
- document.addEventListener("keydown", this.onKeyDown, true);
1240
- }
1241
- teardownListeners() {
1242
- document.removeEventListener("mousemove", this.onMouseMove, true);
1243
- document.removeEventListener("click", this.onClick, true);
1244
- document.removeEventListener("contextmenu", this.onContextMenu, true);
1245
- document.removeEventListener("keydown", this.onKeyDown, true);
1246
- }
1247
- };
1248
- if (typeof customElements !== "undefined") {
1249
- customElements.define("inspecto-overlay", InspectoElement);
1250
- }
1
+ import {
2
+ __async
3
+ } from "./chunk-C4KO2HLL.js";
1251
4
 
1252
5
  // src/index.ts
1253
6
  var TAG_NAME = "inspecto-overlay";
1254
- function mountInspector(options = {}) {
1255
- const existing = document.querySelector(TAG_NAME);
1256
- if (existing) {
1257
- existing.configure(options);
1258
- return existing;
1259
- }
1260
- const el = document.createElement(TAG_NAME);
1261
- el.configure(options);
1262
- document.body.appendChild(el);
1263
- return el;
7
+ function mountInspector() {
8
+ return __async(this, arguments, function* (options = {}) {
9
+ if (typeof document === "undefined") return null;
10
+ const { InspectoElement } = yield import("./component-4WPU23TV.js");
11
+ const existing = document.querySelector(TAG_NAME);
12
+ if (existing) {
13
+ ;
14
+ existing.configure(options);
15
+ return existing;
16
+ }
17
+ const el = document.createElement(TAG_NAME);
18
+ el.configure(options);
19
+ document.body.appendChild(el);
20
+ return el;
21
+ });
1264
22
  }
1265
23
  function unmountInspector() {
24
+ if (typeof document === "undefined") return;
1266
25
  const existing = document.querySelector(TAG_NAME);
1267
26
  if (existing) {
1268
27
  existing.remove();
@@ -1275,7 +34,6 @@ if (typeof window !== "undefined") {
1275
34
  };
1276
35
  }
1277
36
  export {
1278
- InspectoElement,
1279
37
  mountInspector,
1280
38
  unmountInspector
1281
39
  };