uilint-react 0.1.38 → 0.1.40

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.
@@ -0,0 +1,927 @@
1
+ "use client";
2
+ import {
3
+ buildEditorUrl,
4
+ useUILintContext,
5
+ useUILintStore
6
+ } from "./chunk-LAL3JTAA.js";
7
+
8
+ // src/components/ui-lint/InspectionPanel.tsx
9
+ import {
10
+ useState,
11
+ useEffect,
12
+ useCallback,
13
+ useMemo,
14
+ useRef
15
+ } from "react";
16
+ import { createPortal } from "react-dom";
17
+
18
+ // src/components/ui-lint/source-fetcher.ts
19
+ var sourceCache = /* @__PURE__ */ new Map();
20
+ var CACHE_TTL = 5 * 60 * 1e3;
21
+ var API_ENDPOINT = "/api/.uilint/source";
22
+ async function fetchSource(filePath) {
23
+ const cached = sourceCache.get(filePath);
24
+ if (cached && Date.now() - cached.fetchedAt < CACHE_TTL) {
25
+ return {
26
+ content: cached.content,
27
+ relativePath: cached.relativePath
28
+ };
29
+ }
30
+ try {
31
+ const response = await fetch(
32
+ `${API_ENDPOINT}?path=${encodeURIComponent(filePath)}`
33
+ );
34
+ if (!response.ok) {
35
+ console.warn(`[UILint] Failed to fetch source: ${response.statusText}`);
36
+ return null;
37
+ }
38
+ const data = await response.json();
39
+ sourceCache.set(filePath, {
40
+ ...data,
41
+ fetchedAt: Date.now()
42
+ });
43
+ return data;
44
+ } catch (error) {
45
+ console.error("[UILint] Error fetching source:", error);
46
+ return null;
47
+ }
48
+ }
49
+ async function fetchSourceWithContext(source, contextLines = 5) {
50
+ const result = await fetchSource(source.fileName);
51
+ if (!result) return null;
52
+ const allLines = result.content.split("\n");
53
+ const targetLine = source.lineNumber - 1;
54
+ const startLine = Math.max(0, targetLine - contextLines);
55
+ const endLine = Math.min(allLines.length, targetLine + contextLines + 1);
56
+ return {
57
+ lines: allLines.slice(startLine, endLine),
58
+ startLine: startLine + 1,
59
+ // Back to 1-indexed
60
+ highlightLine: source.lineNumber,
61
+ relativePath: result.relativePath
62
+ };
63
+ }
64
+ async function fetchSourceWithWindow(source, window2) {
65
+ const result = await fetchSource(source.fileName);
66
+ if (!result) return null;
67
+ const allLines = result.content.split("\n");
68
+ const targetLine = source.lineNumber - 1;
69
+ const startLine = Math.max(0, targetLine - Math.max(0, window2.linesAbove));
70
+ const endLine = Math.min(
71
+ allLines.length,
72
+ targetLine + Math.max(0, window2.linesBelow) + 1
73
+ );
74
+ return {
75
+ lines: allLines.slice(startLine, endLine),
76
+ startLine: startLine + 1,
77
+ // Back to 1-indexed
78
+ highlightLine: source.lineNumber,
79
+ relativePath: result.relativePath
80
+ };
81
+ }
82
+ function clearSourceCache() {
83
+ sourceCache.clear();
84
+ }
85
+ function getCachedSource(filePath) {
86
+ const cached = sourceCache.get(filePath);
87
+ if (!cached) return null;
88
+ if (Date.now() - cached.fetchedAt >= CACHE_TTL) {
89
+ sourceCache.delete(filePath);
90
+ return null;
91
+ }
92
+ return {
93
+ content: cached.content,
94
+ relativePath: cached.relativePath
95
+ };
96
+ }
97
+ async function prefetchSources(filePaths) {
98
+ const uniquePaths = [...new Set(filePaths)].filter((path) => {
99
+ const cached = sourceCache.get(path);
100
+ return !cached || Date.now() - cached.fetchedAt >= CACHE_TTL;
101
+ });
102
+ const BATCH_SIZE = 5;
103
+ for (let i = 0; i < uniquePaths.length; i += BATCH_SIZE) {
104
+ const batch = uniquePaths.slice(i, i + BATCH_SIZE);
105
+ await Promise.all(batch.map(fetchSource));
106
+ }
107
+ }
108
+
109
+ // src/components/ui-lint/InspectionPanel.tsx
110
+ import { jsx, jsxs } from "react/jsx-runtime";
111
+ var STYLES = {
112
+ bg: "rgba(17, 24, 39, 0.98)",
113
+ bgSurface: "rgba(31, 41, 55, 0.95)",
114
+ border: "rgba(75, 85, 99, 0.6)",
115
+ text: "#F9FAFB",
116
+ textMuted: "#9CA3AF",
117
+ textDim: "#6B7280",
118
+ accent: "#3B82F6",
119
+ accentHover: "#2563EB",
120
+ success: "#10B981",
121
+ warning: "#F59E0B",
122
+ error: "#EF4444",
123
+ shadow: "0 8px 32px rgba(0, 0, 0, 0.5)",
124
+ blur: "blur(12px)",
125
+ font: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
126
+ fontMono: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace'
127
+ };
128
+ var POPOVER_WIDTH = 380;
129
+ var POPOVER_MAX_HEIGHT = 450;
130
+ function InspectionPanel() {
131
+ const {
132
+ inspectedElement,
133
+ setInspectedElement,
134
+ elementIssuesCache,
135
+ autoScanState
136
+ } = useUILintContext();
137
+ const appRoot = useUILintStore((s) => s.appRoot);
138
+ const workspaceRoot = useUILintStore((s) => s.workspaceRoot);
139
+ const editorBaseDir = appRoot || workspaceRoot;
140
+ const [mounted, setMounted] = useState(false);
141
+ const popoverRef = useRef(null);
142
+ useEffect(() => {
143
+ setMounted(true);
144
+ }, []);
145
+ useEffect(() => {
146
+ if (!inspectedElement) return;
147
+ const handleClickOutside = (e) => {
148
+ const target = e.target;
149
+ if (target?.closest?.("[data-ui-lint]")) return;
150
+ setInspectedElement(null);
151
+ };
152
+ const timer = setTimeout(() => {
153
+ document.addEventListener("click", handleClickOutside);
154
+ }, 50);
155
+ return () => {
156
+ clearTimeout(timer);
157
+ document.removeEventListener("click", handleClickOutside);
158
+ };
159
+ }, [inspectedElement, setInspectedElement]);
160
+ const cachedIssue = useMemo(() => {
161
+ if (!inspectedElement) return null;
162
+ if (inspectedElement.scannedElementId) {
163
+ const cached = elementIssuesCache.get(inspectedElement.scannedElementId);
164
+ if (cached) return cached;
165
+ }
166
+ if (inspectedElement.source) {
167
+ for (const [, issue] of elementIssuesCache) {
168
+ const scannedElement = autoScanState.elements.find(
169
+ (el) => el.id === issue.elementId
170
+ );
171
+ if (scannedElement?.source?.fileName === inspectedElement.source.fileName) {
172
+ return issue;
173
+ }
174
+ }
175
+ }
176
+ return null;
177
+ }, [inspectedElement, elementIssuesCache, autoScanState.elements]);
178
+ const eslintIssues = useMemo(() => cachedIssue?.issues || [], [cachedIssue]);
179
+ const position = useMemo(() => {
180
+ if (!inspectedElement) return { top: 0, left: 0 };
181
+ const { rect } = inspectedElement;
182
+ const padding = 12;
183
+ let left = rect.right + padding;
184
+ let top = rect.top;
185
+ if (left + POPOVER_WIDTH > window.innerWidth - padding) {
186
+ left = rect.left - POPOVER_WIDTH - padding;
187
+ }
188
+ if (left < padding) {
189
+ left = Math.max(padding, rect.left);
190
+ top = rect.bottom + padding;
191
+ }
192
+ if (top + POPOVER_MAX_HEIGHT > window.innerHeight - padding) {
193
+ top = Math.max(
194
+ padding,
195
+ window.innerHeight - POPOVER_MAX_HEIGHT - padding
196
+ );
197
+ }
198
+ if (top < padding) {
199
+ top = padding;
200
+ }
201
+ return { top, left };
202
+ }, [inspectedElement]);
203
+ if (!mounted || !inspectedElement) return null;
204
+ const content = /* @__PURE__ */ jsxs(
205
+ "div",
206
+ {
207
+ ref: popoverRef,
208
+ "data-ui-lint": true,
209
+ onClick: (e) => e.stopPropagation(),
210
+ style: {
211
+ position: "fixed",
212
+ top: position.top,
213
+ left: position.left,
214
+ width: POPOVER_WIDTH,
215
+ maxHeight: POPOVER_MAX_HEIGHT,
216
+ backgroundColor: STYLES.bg,
217
+ backdropFilter: STYLES.blur,
218
+ WebkitBackdropFilter: STYLES.blur,
219
+ border: `1px solid ${STYLES.border}`,
220
+ borderRadius: "12px",
221
+ boxShadow: STYLES.shadow,
222
+ fontFamily: STYLES.font,
223
+ color: STYLES.text,
224
+ overflow: "hidden",
225
+ zIndex: 99998,
226
+ animation: "uilint-popover-appear 0.15s ease-out"
227
+ },
228
+ children: [
229
+ /* @__PURE__ */ jsx("style", { children: `
230
+ @keyframes uilint-popover-appear {
231
+ from { opacity: 0; transform: scale(0.95); }
232
+ to { opacity: 1; transform: scale(1); }
233
+ }
234
+ @keyframes uilint-spin {
235
+ from { transform: rotate(0deg); }
236
+ to { transform: rotate(360deg); }
237
+ }
238
+ ` }),
239
+ /* @__PURE__ */ jsx(
240
+ PopoverHeader,
241
+ {
242
+ element: inspectedElement,
243
+ issueCount: eslintIssues.length,
244
+ workspaceRoot: editorBaseDir,
245
+ onClose: () => setInspectedElement(null)
246
+ }
247
+ ),
248
+ /* @__PURE__ */ jsxs(
249
+ "div",
250
+ {
251
+ style: {
252
+ maxHeight: POPOVER_MAX_HEIGHT - 60,
253
+ overflowY: "auto"
254
+ },
255
+ children: [
256
+ cachedIssue?.status === "scanning" && /* @__PURE__ */ jsxs(
257
+ "div",
258
+ {
259
+ style: {
260
+ display: "flex",
261
+ alignItems: "center",
262
+ justifyContent: "center",
263
+ padding: "32px",
264
+ gap: "12px"
265
+ },
266
+ children: [
267
+ /* @__PURE__ */ jsx(
268
+ "div",
269
+ {
270
+ style: {
271
+ width: "20px",
272
+ height: "20px",
273
+ border: `2px solid ${STYLES.border}`,
274
+ borderTopColor: STYLES.accent,
275
+ borderRadius: "50%",
276
+ animation: "uilint-spin 0.8s linear infinite"
277
+ }
278
+ }
279
+ ),
280
+ /* @__PURE__ */ jsx("span", { style: { color: STYLES.textMuted, fontSize: "13px" }, children: "Scanning..." })
281
+ ]
282
+ }
283
+ ),
284
+ cachedIssue?.status === "error" && /* @__PURE__ */ jsx(
285
+ "div",
286
+ {
287
+ style: {
288
+ padding: "16px",
289
+ margin: "12px",
290
+ backgroundColor: "rgba(239, 68, 68, 0.1)",
291
+ border: "1px solid rgba(239, 68, 68, 0.3)",
292
+ borderRadius: "8px",
293
+ color: STYLES.error,
294
+ fontSize: "12px",
295
+ textAlign: "center"
296
+ },
297
+ children: "Failed to analyze this element"
298
+ }
299
+ ),
300
+ cachedIssue?.status === "complete" && eslintIssues.length === 0 && /* @__PURE__ */ jsxs(
301
+ "div",
302
+ {
303
+ style: {
304
+ display: "flex",
305
+ alignItems: "center",
306
+ justifyContent: "center",
307
+ padding: "32px",
308
+ gap: "8px",
309
+ color: STYLES.success,
310
+ fontSize: "13px"
311
+ },
312
+ children: [
313
+ /* @__PURE__ */ jsx(CheckIcon, {}),
314
+ "No issues found"
315
+ ]
316
+ }
317
+ ),
318
+ cachedIssue?.status === "complete" && eslintIssues.length > 0 && /* @__PURE__ */ jsx(
319
+ IssuesList,
320
+ {
321
+ issues: eslintIssues,
322
+ source: inspectedElement.source,
323
+ workspaceRoot: editorBaseDir
324
+ }
325
+ ),
326
+ !cachedIssue && /* @__PURE__ */ jsx(
327
+ "div",
328
+ {
329
+ style: {
330
+ padding: "24px 16px",
331
+ textAlign: "center",
332
+ color: STYLES.textMuted,
333
+ fontSize: "12px"
334
+ },
335
+ children: "Enable live scanning to analyze this element"
336
+ }
337
+ )
338
+ ]
339
+ }
340
+ )
341
+ ]
342
+ }
343
+ );
344
+ return createPortal(content, document.body);
345
+ }
346
+ function PopoverHeader({
347
+ element,
348
+ issueCount,
349
+ workspaceRoot,
350
+ onClose
351
+ }) {
352
+ const fileName = element.source.fileName.split("/").pop() || "Unknown";
353
+ const lineNumber = element.source.lineNumber;
354
+ const handleOpenInCursor = useCallback(() => {
355
+ const url = buildEditorUrl(element.source, "cursor", workspaceRoot);
356
+ window.open(url, "_blank");
357
+ }, [element.source, workspaceRoot]);
358
+ return /* @__PURE__ */ jsxs(
359
+ "div",
360
+ {
361
+ style: {
362
+ display: "flex",
363
+ alignItems: "center",
364
+ justifyContent: "space-between",
365
+ padding: "12px 14px",
366
+ borderBottom: `1px solid ${STYLES.border}`,
367
+ backgroundColor: STYLES.bgSurface
368
+ },
369
+ children: [
370
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "10px" }, children: [
371
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
372
+ "div",
373
+ {
374
+ style: {
375
+ display: "flex",
376
+ alignItems: "center",
377
+ gap: "6px",
378
+ fontSize: "13px",
379
+ fontWeight: 600
380
+ },
381
+ children: [
382
+ /* @__PURE__ */ jsx("span", { style: { fontFamily: STYLES.fontMono }, children: fileName }),
383
+ /* @__PURE__ */ jsxs("span", { style: { color: STYLES.textDim, fontWeight: 400 }, children: [
384
+ ":",
385
+ lineNumber
386
+ ] })
387
+ ]
388
+ }
389
+ ) }),
390
+ issueCount > 0 && /* @__PURE__ */ jsx(
391
+ "span",
392
+ {
393
+ style: {
394
+ display: "inline-flex",
395
+ alignItems: "center",
396
+ justifyContent: "center",
397
+ minWidth: "20px",
398
+ height: "20px",
399
+ padding: "0 6px",
400
+ borderRadius: "10px",
401
+ backgroundColor: STYLES.warning,
402
+ color: "#FFFFFF",
403
+ fontSize: "11px",
404
+ fontWeight: 700
405
+ },
406
+ children: issueCount
407
+ }
408
+ )
409
+ ] }),
410
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "6px" }, children: [
411
+ /* @__PURE__ */ jsxs(
412
+ "button",
413
+ {
414
+ onClick: handleOpenInCursor,
415
+ style: {
416
+ display: "flex",
417
+ alignItems: "center",
418
+ gap: "4px",
419
+ padding: "5px 8px",
420
+ borderRadius: "6px",
421
+ border: "none",
422
+ backgroundColor: STYLES.accent,
423
+ color: "#FFFFFF",
424
+ fontSize: "11px",
425
+ fontWeight: 500,
426
+ cursor: "pointer",
427
+ transition: "background-color 0.15s"
428
+ },
429
+ onMouseEnter: (e) => {
430
+ e.currentTarget.style.backgroundColor = STYLES.accentHover;
431
+ },
432
+ onMouseLeave: (e) => {
433
+ e.currentTarget.style.backgroundColor = STYLES.accent;
434
+ },
435
+ title: "Open in Cursor",
436
+ children: [
437
+ /* @__PURE__ */ jsx(ExternalLinkIcon, {}),
438
+ "Open in Cursor"
439
+ ]
440
+ }
441
+ ),
442
+ /* @__PURE__ */ jsx(
443
+ "button",
444
+ {
445
+ onClick: onClose,
446
+ style: {
447
+ display: "flex",
448
+ alignItems: "center",
449
+ justifyContent: "center",
450
+ width: "26px",
451
+ height: "26px",
452
+ borderRadius: "6px",
453
+ border: "none",
454
+ backgroundColor: "transparent",
455
+ color: STYLES.textMuted,
456
+ cursor: "pointer",
457
+ transition: "all 0.15s"
458
+ },
459
+ onMouseEnter: (e) => {
460
+ e.currentTarget.style.backgroundColor = STYLES.bgSurface;
461
+ e.currentTarget.style.color = STYLES.text;
462
+ },
463
+ onMouseLeave: (e) => {
464
+ e.currentTarget.style.backgroundColor = "transparent";
465
+ e.currentTarget.style.color = STYLES.textMuted;
466
+ },
467
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
468
+ }
469
+ )
470
+ ] })
471
+ ]
472
+ }
473
+ );
474
+ }
475
+ function IssuesList({
476
+ issues,
477
+ source,
478
+ workspaceRoot
479
+ }) {
480
+ return /* @__PURE__ */ jsx("div", { style: { padding: "8px" }, children: issues.map((issue, index) => /* @__PURE__ */ jsx(
481
+ IssueCard,
482
+ {
483
+ issue,
484
+ source,
485
+ workspaceRoot,
486
+ isLast: index === issues.length - 1
487
+ },
488
+ index
489
+ )) });
490
+ }
491
+ function IssueCard({
492
+ issue,
493
+ source,
494
+ workspaceRoot,
495
+ isLast
496
+ }) {
497
+ const [linesAbove, setLinesAbove] = useState(1);
498
+ const [linesBelow, setLinesBelow] = useState(1);
499
+ const [codeData, setCodeData] = useState(null);
500
+ const [loading, setLoading] = useState(true);
501
+ useEffect(() => {
502
+ const issueSource = {
503
+ fileName: source.fileName,
504
+ lineNumber: issue.line,
505
+ columnNumber: issue.column
506
+ };
507
+ setLoading(true);
508
+ fetchSourceWithWindow(issueSource, { linesAbove, linesBelow }).then((data) => {
509
+ if (data) {
510
+ setCodeData({
511
+ lines: data.lines,
512
+ startLine: data.startLine,
513
+ highlightLine: data.highlightLine
514
+ });
515
+ }
516
+ }).finally(() => {
517
+ setLoading(false);
518
+ });
519
+ }, [source.fileName, issue.line, issue.column, linesAbove, linesBelow]);
520
+ const handleOpenInCursor = useCallback(() => {
521
+ const issueSource = {
522
+ fileName: source.fileName,
523
+ lineNumber: issue.line,
524
+ columnNumber: issue.column
525
+ };
526
+ const url = buildEditorUrl(issueSource, "cursor", workspaceRoot);
527
+ window.open(url, "_blank");
528
+ }, [source.fileName, issue.line, issue.column, workspaceRoot]);
529
+ return /* @__PURE__ */ jsxs(
530
+ "div",
531
+ {
532
+ style: {
533
+ padding: "10px",
534
+ marginBottom: isLast ? 0 : "8px",
535
+ backgroundColor: STYLES.bgSurface,
536
+ borderRadius: "8px",
537
+ border: `1px solid ${STYLES.border}`
538
+ },
539
+ children: [
540
+ /* @__PURE__ */ jsxs(
541
+ "div",
542
+ {
543
+ style: {
544
+ display: "flex",
545
+ alignItems: "flex-start",
546
+ gap: "8px",
547
+ marginBottom: "8px"
548
+ },
549
+ children: [
550
+ /* @__PURE__ */ jsx(WarningIcon, {}),
551
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
552
+ /* @__PURE__ */ jsx(
553
+ "div",
554
+ {
555
+ style: {
556
+ fontSize: "12px",
557
+ color: STYLES.text,
558
+ lineHeight: 1.4,
559
+ marginBottom: "4px"
560
+ },
561
+ children: issue.message
562
+ }
563
+ ),
564
+ /* @__PURE__ */ jsxs(
565
+ "div",
566
+ {
567
+ style: {
568
+ display: "flex",
569
+ alignItems: "center",
570
+ gap: "8px",
571
+ fontSize: "10px",
572
+ color: STYLES.textDim
573
+ },
574
+ children: [
575
+ issue.ruleId && /* @__PURE__ */ jsx(
576
+ "span",
577
+ {
578
+ style: {
579
+ padding: "2px 5px",
580
+ backgroundColor: "rgba(239, 68, 68, 0.15)",
581
+ borderRadius: "4px",
582
+ color: STYLES.error,
583
+ fontFamily: STYLES.fontMono
584
+ },
585
+ children: issue.ruleId
586
+ }
587
+ ),
588
+ /* @__PURE__ */ jsxs("span", { style: { fontFamily: STYLES.fontMono }, children: [
589
+ "Line ",
590
+ issue.line,
591
+ issue.column ? `:${issue.column}` : ""
592
+ ] })
593
+ ]
594
+ }
595
+ )
596
+ ] })
597
+ ]
598
+ }
599
+ ),
600
+ /* @__PURE__ */ jsxs(
601
+ "div",
602
+ {
603
+ style: {
604
+ backgroundColor: STYLES.bg,
605
+ borderRadius: "6px",
606
+ overflow: "hidden",
607
+ border: `1px solid ${STYLES.border}`
608
+ },
609
+ children: [
610
+ /* @__PURE__ */ jsx(
611
+ "div",
612
+ {
613
+ style: {
614
+ display: "flex",
615
+ justifyContent: "center",
616
+ padding: "6px",
617
+ borderBottom: `1px solid ${STYLES.border}`,
618
+ backgroundColor: "rgba(17, 24, 39, 0.35)"
619
+ },
620
+ children: /* @__PURE__ */ jsxs(
621
+ "button",
622
+ {
623
+ onClick: () => setLinesAbove((n) => n + 3),
624
+ style: {
625
+ display: "flex",
626
+ alignItems: "center",
627
+ gap: "4px",
628
+ padding: "3px 8px",
629
+ borderRadius: "999px",
630
+ border: `1px solid ${STYLES.border}`,
631
+ backgroundColor: "transparent",
632
+ color: STYLES.textMuted,
633
+ fontSize: "10px",
634
+ cursor: "pointer"
635
+ },
636
+ title: "Show more lines above",
637
+ children: [
638
+ /* @__PURE__ */ jsx(ChevronUpIcon, {}),
639
+ "+3 above"
640
+ ]
641
+ }
642
+ )
643
+ }
644
+ ),
645
+ loading ? /* @__PURE__ */ jsx(
646
+ "div",
647
+ {
648
+ style: {
649
+ padding: "12px",
650
+ textAlign: "center",
651
+ color: STYLES.textDim,
652
+ fontSize: "11px"
653
+ },
654
+ children: "Loading..."
655
+ }
656
+ ) : codeData ? /* @__PURE__ */ jsx(
657
+ "pre",
658
+ {
659
+ style: {
660
+ margin: 0,
661
+ padding: "8px 0",
662
+ overflow: "auto",
663
+ fontSize: "11px",
664
+ lineHeight: "1.5",
665
+ fontFamily: STYLES.fontMono
666
+ },
667
+ children: codeData.lines.map((line, index) => {
668
+ const lineNumber = codeData.startLine + index;
669
+ const isHighlight = lineNumber === codeData.highlightLine;
670
+ return /* @__PURE__ */ jsxs(
671
+ "div",
672
+ {
673
+ style: {
674
+ display: "flex",
675
+ backgroundColor: isHighlight ? "rgba(239, 68, 68, 0.15)" : "transparent",
676
+ borderLeft: isHighlight ? `2px solid ${STYLES.error}` : "2px solid transparent"
677
+ },
678
+ children: [
679
+ /* @__PURE__ */ jsx(
680
+ "span",
681
+ {
682
+ style: {
683
+ display: "inline-block",
684
+ width: "36px",
685
+ paddingRight: "8px",
686
+ paddingLeft: "8px",
687
+ textAlign: "right",
688
+ color: isHighlight ? STYLES.error : STYLES.textDim,
689
+ userSelect: "none",
690
+ flexShrink: 0
691
+ },
692
+ children: lineNumber
693
+ }
694
+ ),
695
+ /* @__PURE__ */ jsx(
696
+ "code",
697
+ {
698
+ style: {
699
+ color: isHighlight ? STYLES.text : STYLES.textMuted,
700
+ whiteSpace: "pre",
701
+ paddingRight: "8px"
702
+ },
703
+ children: line || " "
704
+ }
705
+ )
706
+ ]
707
+ },
708
+ lineNumber
709
+ );
710
+ })
711
+ }
712
+ ) : /* @__PURE__ */ jsx(
713
+ "div",
714
+ {
715
+ style: {
716
+ padding: "12px",
717
+ textAlign: "center",
718
+ color: STYLES.textDim,
719
+ fontSize: "11px"
720
+ },
721
+ children: "Could not load source"
722
+ }
723
+ ),
724
+ /* @__PURE__ */ jsx(
725
+ "div",
726
+ {
727
+ style: {
728
+ display: "flex",
729
+ justifyContent: "center",
730
+ padding: "6px",
731
+ borderTop: `1px solid ${STYLES.border}`,
732
+ backgroundColor: "rgba(17, 24, 39, 0.35)"
733
+ },
734
+ children: /* @__PURE__ */ jsxs(
735
+ "button",
736
+ {
737
+ onClick: () => setLinesBelow((n) => n + 3),
738
+ style: {
739
+ display: "flex",
740
+ alignItems: "center",
741
+ gap: "4px",
742
+ padding: "3px 8px",
743
+ borderRadius: "999px",
744
+ border: `1px solid ${STYLES.border}`,
745
+ backgroundColor: "transparent",
746
+ color: STYLES.textMuted,
747
+ fontSize: "10px",
748
+ cursor: "pointer"
749
+ },
750
+ title: "Show more lines below",
751
+ children: [
752
+ "+3 below",
753
+ /* @__PURE__ */ jsx(ChevronDownIcon, {})
754
+ ]
755
+ }
756
+ )
757
+ }
758
+ )
759
+ ]
760
+ }
761
+ ),
762
+ /* @__PURE__ */ jsxs(
763
+ "div",
764
+ {
765
+ style: {
766
+ display: "flex",
767
+ alignItems: "center",
768
+ justifyContent: "space-between",
769
+ marginTop: "8px"
770
+ },
771
+ children: [
772
+ /* @__PURE__ */ jsx(
773
+ "button",
774
+ {
775
+ onClick: () => {
776
+ setLinesAbove(1);
777
+ setLinesBelow(1);
778
+ },
779
+ style: {
780
+ display: "flex",
781
+ alignItems: "center",
782
+ gap: "4px",
783
+ padding: "4px 8px",
784
+ borderRadius: "4px",
785
+ border: "none",
786
+ backgroundColor: "transparent",
787
+ color: STYLES.textMuted,
788
+ fontSize: "10px",
789
+ cursor: "pointer",
790
+ transition: "color 0.15s"
791
+ },
792
+ onMouseEnter: (e) => {
793
+ e.currentTarget.style.color = STYLES.text;
794
+ },
795
+ onMouseLeave: (e) => {
796
+ e.currentTarget.style.color = STYLES.textMuted;
797
+ },
798
+ children: "Reset context"
799
+ }
800
+ ),
801
+ /* @__PURE__ */ jsxs(
802
+ "button",
803
+ {
804
+ onClick: handleOpenInCursor,
805
+ style: {
806
+ display: "flex",
807
+ alignItems: "center",
808
+ gap: "4px",
809
+ padding: "4px 8px",
810
+ borderRadius: "4px",
811
+ border: "none",
812
+ backgroundColor: "transparent",
813
+ color: STYLES.accent,
814
+ fontSize: "10px",
815
+ cursor: "pointer",
816
+ transition: "opacity 0.15s"
817
+ },
818
+ onMouseEnter: (e) => {
819
+ e.currentTarget.style.opacity = "0.8";
820
+ },
821
+ onMouseLeave: (e) => {
822
+ e.currentTarget.style.opacity = "1";
823
+ },
824
+ children: [
825
+ /* @__PURE__ */ jsx(ExternalLinkIcon, {}),
826
+ "Open in Cursor"
827
+ ]
828
+ }
829
+ )
830
+ ]
831
+ }
832
+ )
833
+ ]
834
+ }
835
+ );
836
+ }
837
+ function CheckIcon() {
838
+ return /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
839
+ "path",
840
+ {
841
+ d: "M20 6L9 17l-5-5",
842
+ stroke: "currentColor",
843
+ strokeWidth: "2",
844
+ strokeLinecap: "round",
845
+ strokeLinejoin: "round"
846
+ }
847
+ ) });
848
+ }
849
+ function ExternalLinkIcon() {
850
+ return /* @__PURE__ */ jsx("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
851
+ "path",
852
+ {
853
+ d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6M15 3h6v6M10 14L21 3",
854
+ stroke: "currentColor",
855
+ strokeWidth: "2",
856
+ strokeLinecap: "round",
857
+ strokeLinejoin: "round"
858
+ }
859
+ ) });
860
+ }
861
+ function CloseIcon() {
862
+ return /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
863
+ "path",
864
+ {
865
+ d: "M18 6L6 18M6 6l12 12",
866
+ stroke: "currentColor",
867
+ strokeWidth: "2",
868
+ strokeLinecap: "round",
869
+ strokeLinejoin: "round"
870
+ }
871
+ ) });
872
+ }
873
+ function WarningIcon() {
874
+ return /* @__PURE__ */ jsx(
875
+ "svg",
876
+ {
877
+ width: "14",
878
+ height: "14",
879
+ viewBox: "0 0 24 24",
880
+ fill: "none",
881
+ style: { flexShrink: 0, marginTop: "1px" },
882
+ children: /* @__PURE__ */ jsx(
883
+ "path",
884
+ {
885
+ d: "M12 9v4M12 17h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z",
886
+ stroke: STYLES.warning,
887
+ strokeWidth: "2",
888
+ strokeLinecap: "round",
889
+ strokeLinejoin: "round"
890
+ }
891
+ )
892
+ }
893
+ );
894
+ }
895
+ function ChevronDownIcon() {
896
+ return /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
897
+ "path",
898
+ {
899
+ d: "M6 9l6 6 6-6",
900
+ stroke: "currentColor",
901
+ strokeWidth: "2",
902
+ strokeLinecap: "round",
903
+ strokeLinejoin: "round"
904
+ }
905
+ ) });
906
+ }
907
+ function ChevronUpIcon() {
908
+ return /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
909
+ "path",
910
+ {
911
+ d: "M18 15l-6-6-6 6",
912
+ stroke: "currentColor",
913
+ strokeWidth: "2",
914
+ strokeLinecap: "round",
915
+ strokeLinejoin: "round"
916
+ }
917
+ ) });
918
+ }
919
+
920
+ export {
921
+ fetchSource,
922
+ fetchSourceWithContext,
923
+ clearSourceCache,
924
+ getCachedSource,
925
+ prefetchSources,
926
+ InspectionPanel
927
+ };