@sampleapp.ai/sdk 1.0.36 → 1.0.37

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.
Files changed (82) hide show
  1. package/dist/components/sandbox/Sandbox.js +5 -0
  2. package/dist/components/sandbox/api.js +3 -2
  3. package/dist/components/sandbox/guardian/guardian-component.js +7 -38
  4. package/dist/components/sandbox/guardian/guardian-playground.js +1 -1
  5. package/dist/components/sandbox/guardian/hooks/use-sandbox-url-loader.js +12 -10
  6. package/dist/components/sandbox/guardian/index.js +1 -1
  7. package/dist/components/sandbox/guardian/right-view/right-top-down-view.js +1 -1
  8. package/dist/components/sandbox/guardian/ui/markdown.js +2 -2
  9. package/dist/components/sandbox/guardian/utils.js +0 -18
  10. package/dist/components/sandbox/index.js +1 -1
  11. package/dist/components/sandbox/sandbox-home/SandboxHome.js +5 -0
  12. package/dist/index.d.ts +8 -40
  13. package/dist/index.es.js +830 -867
  14. package/dist/index.js +1 -1
  15. package/dist/lib/api-client.js +9 -26
  16. package/package.json +1 -1
  17. package/dist/components/guardian/app-layout-no-sidebar.js +0 -8
  18. package/dist/components/guardian/ask-ai-view.js +0 -249
  19. package/dist/components/guardian/code-focus-section.d.ts +0 -41
  20. package/dist/components/guardian/code-focus-section.js +0 -174
  21. package/dist/components/guardian/context/guardian-context.js +0 -94
  22. package/dist/components/guardian/context/vm-context.js +0 -28
  23. package/dist/components/guardian/default-guide-view.js +0 -34
  24. package/dist/components/guardian/demo/guardian-demo.js +0 -35
  25. package/dist/components/guardian/demo/left-view/toggle.js +0 -28
  26. package/dist/components/guardian/demo/left-view.js +0 -49
  27. package/dist/components/guardian/guardian-component.js +0 -79
  28. package/dist/components/guardian/guardian-demo.js +0 -35
  29. package/dist/components/guardian/guardian-home.d.ts +0 -4
  30. package/dist/components/guardian/guardian-home.js +0 -61
  31. package/dist/components/guardian/guardian-playground.js +0 -45
  32. package/dist/components/guardian/guardian-style-wrapper.js +0 -29
  33. package/dist/components/guardian/guardian-upload-spec.d.ts +0 -14
  34. package/dist/components/guardian/guardian-upload-spec.js +0 -160
  35. package/dist/components/guardian/header/glassmorphic-combobox.d.ts +0 -15
  36. package/dist/components/guardian/header/glassmorphic-combobox.js +0 -30
  37. package/dist/components/guardian/header.js +0 -61
  38. package/dist/components/guardian/hooks/use-frame-messages.js +0 -65
  39. package/dist/components/guardian/hooks/use-frame-params.js +0 -44
  40. package/dist/components/guardian/hooks/use-sandbox-url-loader.js +0 -101
  41. package/dist/components/guardian/ide/browser.js +0 -538
  42. package/dist/components/guardian/index.js +0 -8
  43. package/dist/components/guardian/layout/app-layout-no-sidebar.js +0 -8
  44. package/dist/components/guardian/layout/header/glassmorphic-combobox.js +0 -48
  45. package/dist/components/guardian/layout/header.js +0 -63
  46. package/dist/components/guardian/right-view/code-view.js +0 -56
  47. package/dist/components/guardian/right-view/pill-file-selector.js +0 -233
  48. package/dist/components/guardian/right-view/preview-control-bar.js +0 -25
  49. package/dist/components/guardian/right-view/right-panel-view.js +0 -38
  50. package/dist/components/guardian/right-view/right-top-down-view.js +0 -289
  51. package/dist/components/guardian/right-view/right-view.js +0 -28
  52. package/dist/components/guardian/right-view/simplified-editor.js +0 -234
  53. package/dist/components/guardian/types/ide-types.js +0 -162
  54. package/dist/components/guardian/types.js +0 -3
  55. package/dist/components/guardian/ui/ai-loader.js +0 -48
  56. package/dist/components/guardian/ui/badge.js +0 -24
  57. package/dist/components/guardian/ui/button.js +0 -45
  58. package/dist/components/guardian/ui/command.js +0 -63
  59. package/dist/components/guardian/ui/console-with-app.js +0 -17
  60. package/dist/components/guardian/ui/dialog.js +0 -57
  61. package/dist/components/guardian/ui/dropdown-menu.js +0 -82
  62. package/dist/components/guardian/ui/markdown.js +0 -57
  63. package/dist/components/guardian/ui/popover.js +0 -25
  64. package/dist/components/guardian/ui/tooltip.js +0 -25
  65. package/dist/components/guardian/utils.js +0 -88
  66. package/dist/components/guardian/zip-to-codebase.js +0 -246
  67. package/dist/components/guardian/zip-to-filetree.js +0 -284
  68. package/dist/components/sandbox/SandboxHome.js +0 -141
  69. package/dist/components/sandbox/guardian/guardian-demo.js +0 -35
  70. package/dist/components/sandbox/guardian/guardian-home.d.ts +0 -4
  71. package/dist/components/sandbox/guardian/guardian-home.js +0 -61
  72. package/dist/components/sandbox/guardian/guardian-upload-spec.d.ts +0 -14
  73. package/dist/components/sandbox/guardian/guardian-upload-spec.js +0 -160
  74. package/dist/components/sandbox/guardian/ui/theme-color-context.d.ts +0 -6
  75. package/dist/components/sandbox/sandbox-control-bar.js +0 -91
  76. package/dist/components/sandbox/sandbox-header.js +0 -52
  77. package/dist/components/sandbox/sandbox-left-panel.js +0 -248
  78. package/dist/components/sandbox/sandbox-loading.js +0 -48
  79. package/dist/components/sandbox/sandbox-right-panel.js +0 -247
  80. package/dist/components/sandbox.js +0 -32
  81. package/dist/lib/api-client.example.js +0 -60
  82. package/dist/lib/ssr-safe-decode-entity.js +0 -16
@@ -1,538 +0,0 @@
1
- import React, { useCallback, useEffect, useRef, useState } from "react";
2
- import { useGuardianContext } from "../context/guardian-context";
3
- import { ChevronLeft, ChevronRight, RefreshCw, Lock, AlertTriangle, Maximize2, Minimize2, ExternalLink, MoreVertical, } from "lucide-react";
4
- import { cn } from "../../../lib/utils";
5
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "../ui/dropdown-menu";
6
- export default function Browser({ previewUrl, setPreviewUrl, containerEndpoint, outerContainerClassName, children, reloadSignal, useVm, isGuardian = false, }) {
7
- const { isBrowserMaximized, setIsBrowserMaximized } = useGuardianContext();
8
- const iframeRef = useRef(null);
9
- const [isLoading, setIsLoading] = useState(false);
10
- const [error, setError] = useState(null);
11
- const historyRef = useRef([]);
12
- const historyIndexRef = useRef(-1);
13
- const suppressHistoryPushRef = useRef(false);
14
- const suppressIframeSrcUpdateRef = useRef(false);
15
- const [historyIndex, setHistoryIndex] = useState(-1);
16
- const [historyLength, setHistoryLength] = useState(0);
17
- const [urlInput, setUrlInput] = useState("");
18
- const [iframeSrc, setIframeSrc] = useState("");
19
- const isIgnorableUrl = useCallback((href) => {
20
- if (!href)
21
- return true;
22
- const value = href.toString();
23
- return value === "about:blank" || value.startsWith("about:");
24
- }, []);
25
- /**
26
- * Convert displayed URL back to original format. For dev mode you
27
- * can just show the containerEndpoint if you prefer.
28
- */
29
- const getDisplayUrl = (proxyUrl) => {
30
- try {
31
- const currentUrl = new URL(proxyUrl);
32
- // Return just the pathname
33
- return currentUrl.pathname || "/";
34
- }
35
- catch (_a) {
36
- return proxyUrl;
37
- }
38
- };
39
- const normalizeUrl = useCallback((href) => {
40
- try {
41
- const u = new URL(href, window.location.href);
42
- u.searchParams.delete("_ts");
43
- return u.toString();
44
- }
45
- catch (_a) {
46
- // Best-effort removal of _ts from plain strings
47
- const withoutTs = href.replace(/([?&])_ts=\d+(&|$)/, (m, p1, p2) => p2 === "&" ? p1 : "");
48
- return withoutTs.replace(/[?&]$/, "");
49
- }
50
- }, []);
51
- const updateHistoryState = useCallback(() => {
52
- setHistoryIndex(historyIndexRef.current);
53
- setHistoryLength(historyRef.current.length);
54
- }, []);
55
- const updateUrlInput = useCallback((href) => {
56
- try {
57
- const currentUrlObj = new URL(href, window.location.href);
58
- setUrlInput(currentUrlObj.pathname || "/");
59
- }
60
- catch (_a) {
61
- setUrlInput(href);
62
- }
63
- }, []);
64
- const pushHistoryEntry = useCallback((href) => {
65
- const sliceUntil = Math.min(historyRef.current.length, historyIndexRef.current + 1);
66
- historyRef.current = [...historyRef.current.slice(0, sliceUntil), href];
67
- historyIndexRef.current = historyRef.current.length - 1;
68
- updateHistoryState();
69
- }, [updateHistoryState]);
70
- useEffect(() => {
71
- if (!previewUrl)
72
- return;
73
- // Skip iframe src update if we're syncing from a navigation message
74
- // (to prevent reloading the iframe when it has already navigated internally)
75
- if (!suppressIframeSrcUpdateRef.current) {
76
- // Keep iframe src in sync with external previewUrl when it changes meaningfully
77
- setIframeSrc((prev) => {
78
- const prevNorm = prev ? normalizeUrl(prev) : "";
79
- const nextNorm = normalizeUrl(previewUrl);
80
- return prevNorm === nextNorm ? prev || previewUrl : previewUrl;
81
- });
82
- }
83
- else {
84
- // Reset the flag after skipping the update
85
- suppressIframeSrcUpdateRef.current = false;
86
- }
87
- updateUrlInput(previewUrl);
88
- if (historyRef.current.length === 0) {
89
- historyRef.current = [previewUrl];
90
- historyIndexRef.current = 0;
91
- updateHistoryState();
92
- suppressHistoryPushRef.current = false;
93
- return;
94
- }
95
- if (suppressHistoryPushRef.current) {
96
- suppressHistoryPushRef.current = false;
97
- return;
98
- }
99
- const current = historyRef.current[historyIndexRef.current];
100
- if (normalizeUrl(current) === normalizeUrl(previewUrl))
101
- return;
102
- pushHistoryEntry(normalizeUrl(previewUrl));
103
- }, [
104
- previewUrl,
105
- updateUrlInput,
106
- pushHistoryEntry,
107
- updateHistoryState,
108
- normalizeUrl,
109
- ]);
110
- /**
111
- * Force-reload the current iframe without mutating previewUrl.
112
- * Tries same-origin reload first; falls back to cache-busting the src.
113
- */
114
- const reloadIframe = () => {
115
- var _a;
116
- if (!previewUrl)
117
- return;
118
- try {
119
- const base = ((_a = iframeRef.current) === null || _a === void 0 ? void 0 : _a.src) || iframeSrc || previewUrl;
120
- const url = new URL(base, window.location.href);
121
- url.searchParams.set("_ts", Date.now().toString());
122
- setIframeSrc(url.toString());
123
- }
124
- catch (_b) {
125
- try {
126
- const url = new URL(previewUrl, window.location.href);
127
- url.searchParams.set("_ts", Date.now().toString());
128
- setIframeSrc(url.toString());
129
- }
130
- catch (_c) {
131
- setIframeSrc(previewUrl);
132
- }
133
- }
134
- };
135
- const getFrameWindow = () => {
136
- const iframe = iframeRef.current;
137
- if (!iframe)
138
- return null;
139
- try {
140
- return iframe.contentWindow;
141
- }
142
- catch (_a) {
143
- return null;
144
- }
145
- };
146
- const getFrameHref = useCallback(() => {
147
- var _a, _b;
148
- const iframe = iframeRef.current;
149
- if (!iframe)
150
- return null;
151
- try {
152
- const href = (_b = (_a = iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.href;
153
- if (href && !isIgnorableUrl(href))
154
- return href;
155
- }
156
- catch (_c) {
157
- // Ignore cross-origin errors; fall back to iframe.src below.
158
- }
159
- try {
160
- // For cross-origin iframes, we can't read location.href, so use iframe.src
161
- // But iframe.src might not reflect client-side navigation, so we also check
162
- // if we have a more recent previewUrl
163
- const src = iframe.src;
164
- if (src && !isIgnorableUrl(src)) {
165
- // If previewUrl is more recent and different, prefer it
166
- if (previewUrl && normalizeUrl(previewUrl) !== normalizeUrl(src)) {
167
- return previewUrl;
168
- }
169
- return src;
170
- }
171
- // Fallback to previewUrl if iframe.src is not available
172
- if (previewUrl && !isIgnorableUrl(previewUrl)) {
173
- return previewUrl;
174
- }
175
- return null;
176
- }
177
- catch (_d) {
178
- // Final fallback to previewUrl
179
- if (previewUrl && !isIgnorableUrl(previewUrl)) {
180
- return previewUrl;
181
- }
182
- return null;
183
- }
184
- }, [previewUrl, normalizeUrl, isIgnorableUrl]);
185
- /**
186
- * Synchronize state from the iframe's current location (when accessible).
187
- */
188
- const syncFromIframe = useCallback(() => {
189
- const currentHref = getFrameHref();
190
- if (!currentHref || isIgnorableUrl(currentHref)) {
191
- // If we can't get the href, at least try to update from previewUrl
192
- if (previewUrl && !isIgnorableUrl(previewUrl)) {
193
- updateUrlInput(previewUrl);
194
- }
195
- return;
196
- }
197
- try {
198
- const currentUrlObj = new URL(currentHref, window.location.href);
199
- const pathOnly = currentUrlObj.pathname || "/";
200
- setUrlInput(pathOnly);
201
- }
202
- catch (_a) {
203
- // If URL parsing fails, try to extract path from the string
204
- try {
205
- const pathMatch = currentHref.match(/\/\/[^\/]+(\/.*?)(?:\?|$)/);
206
- if (pathMatch && pathMatch[1]) {
207
- setUrlInput(pathMatch[1]);
208
- }
209
- else {
210
- setUrlInput(currentHref);
211
- }
212
- }
213
- catch (_b) {
214
- setUrlInput(currentHref);
215
- }
216
- }
217
- const normalizedCurrent = normalizeUrl(currentHref);
218
- if (!suppressHistoryPushRef.current) {
219
- const currentFlowLength = historyRef.current.length;
220
- const sliceUntil = Math.min(currentFlowLength, historyIndexRef.current + 1);
221
- historyRef.current = [
222
- ...historyRef.current.slice(0, sliceUntil),
223
- normalizedCurrent,
224
- ];
225
- historyIndexRef.current = historyRef.current.length - 1;
226
- setHistoryIndex(historyIndexRef.current);
227
- setHistoryLength(historyRef.current.length);
228
- }
229
- // Only propagate meaningful navigations (ignore cache-busting changes)
230
- if (normalizeUrl(previewUrl) !== normalizedCurrent) {
231
- setPreviewUrl(normalizedCurrent);
232
- }
233
- }, [
234
- previewUrl,
235
- normalizeUrl,
236
- updateUrlInput,
237
- setPreviewUrl,
238
- getFrameHref,
239
- isIgnorableUrl,
240
- ]);
241
- /**
242
- * Install navigation listeners in the iframe (same-origin only) so SPA-style
243
- * navigations update our UI without a full reload.
244
- */
245
- const attachIframeNavigationSync = () => {
246
- const win = getFrameWindow();
247
- if (!win)
248
- return;
249
- // Same-origin guard: any property access on cross-origin windows throws.
250
- // If we can't read location.href, bail out and avoid installing listeners.
251
- try {
252
- void win.location.href;
253
- }
254
- catch (_a) {
255
- return;
256
- }
257
- const notify = () => {
258
- // Delay slightly to allow location to settle
259
- setTimeout(() => syncFromIframe(), 0);
260
- };
261
- if (win.__saNavSyncInstalled)
262
- return;
263
- win.addEventListener("hashchange", notify);
264
- win.addEventListener("popstate", notify);
265
- try {
266
- const wrapHistoryMethod = (method) => {
267
- const original = win.history[method];
268
- if (typeof original !== "function")
269
- return;
270
- win.history[method] = ((...args) => {
271
- const result = original.apply(win.history, args);
272
- win.dispatchEvent(new Event("sa-locationchange"));
273
- return result;
274
- });
275
- };
276
- wrapHistoryMethod("pushState");
277
- wrapHistoryMethod("replaceState");
278
- win.addEventListener("sa-locationchange", notify);
279
- }
280
- catch (_b) {
281
- // If we cannot patch history, rely on popstate/hashchange only
282
- }
283
- win.__saNavSyncInstalled = true;
284
- };
285
- // Trigger iframe reload when external signal changes
286
- useEffect(() => {
287
- if (typeof reloadSignal === "number") {
288
- reloadIframe();
289
- }
290
- // eslint-disable-next-line react-hooks/exhaustive-deps
291
- }, [reloadSignal]);
292
- // Listen for navigation messages from the iframe
293
- useEffect(() => {
294
- const handleMessage = (event) => {
295
- var _a, _b;
296
- // Only accept messages from the same origin or trusted origins
297
- if (event.origin !== window.location.origin &&
298
- !event.origin.endsWith("sampleapp.love")) {
299
- return;
300
- }
301
- // Handle navigation updates from the iframe
302
- if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === "NAVIGATION_UPDATE" && ((_b = event.data) === null || _b === void 0 ? void 0 : _b.url)) {
303
- const newUrl = event.data.url;
304
- const normalized = normalizeUrl(newUrl);
305
- // Update the URL display
306
- updateUrlInput(newUrl);
307
- // Update history without triggering iframe src change
308
- const current = historyRef.current[historyIndexRef.current];
309
- if (normalizeUrl(current) !== normalized) {
310
- suppressHistoryPushRef.current = true;
311
- pushHistoryEntry(normalized);
312
- }
313
- // Update previewUrl so syncFromIframe() can use the correct value
314
- // Use a flag to prevent the useEffect from updating iframe src (which would cause reload)
315
- if (normalizeUrl(previewUrl) !== normalized) {
316
- suppressIframeSrcUpdateRef.current = true;
317
- setPreviewUrl(normalized);
318
- }
319
- }
320
- };
321
- window.addEventListener("message", handleMessage);
322
- return () => {
323
- window.removeEventListener("message", handleMessage);
324
- };
325
- }, [
326
- normalizeUrl,
327
- updateUrlInput,
328
- pushHistoryEntry,
329
- previewUrl,
330
- setPreviewUrl,
331
- ]);
332
- /**
333
- * Navigation logic
334
- */
335
- const handleNavigate = (url) => {
336
- try {
337
- let processedUrl;
338
- const trimmedUrl = url.trim();
339
- // If the input is blank, navigate to root path
340
- if (trimmedUrl === "" ||
341
- trimmedUrl.includes("https://") ||
342
- trimmedUrl.includes("http://") ||
343
- trimmedUrl.includes("localhost")) {
344
- const baseUrl = containerEndpoint || "";
345
- try {
346
- const baseUrlObj = new URL(baseUrl);
347
- processedUrl = `${baseUrlObj.origin}/`;
348
- }
349
- catch (error) {
350
- console.error("Error creating URL with base:", baseUrl, error);
351
- setError(`Invalid base URL: ${baseUrl}`);
352
- setIsLoading(false);
353
- return;
354
- }
355
- }
356
- // If it starts with /api/browser, use as is
357
- else if (trimmedUrl.startsWith("/api/browser")) {
358
- processedUrl = trimmedUrl;
359
- }
360
- // If it's a relative path (starts with /)
361
- else if (trimmedUrl.startsWith("/")) {
362
- const baseUrl = containerEndpoint || "";
363
- try {
364
- const baseUrlObj = new URL(baseUrl);
365
- processedUrl = `${baseUrlObj.origin}${trimmedUrl}`;
366
- }
367
- catch (error) {
368
- console.error("Error creating URL with base:", baseUrl, error);
369
- setError(`Invalid base URL: ${baseUrl}`);
370
- setIsLoading(false);
371
- return;
372
- }
373
- }
374
- // Otherwise, treat as external URL
375
- else {
376
- const baseUrl = containerEndpoint || "";
377
- try {
378
- const baseUrlObj = new URL(baseUrl);
379
- processedUrl = `${baseUrlObj.origin}/`;
380
- }
381
- catch (error) {
382
- console.error("Error creating URL with base:", baseUrl, error);
383
- setError(`Invalid base URL: ${baseUrl}`);
384
- setIsLoading(false);
385
- return;
386
- }
387
- }
388
- setIsLoading(true);
389
- setError(null);
390
- const newHistory = historyRef.current.slice(0, historyIndex + 1);
391
- newHistory.push(processedUrl);
392
- historyRef.current = newHistory;
393
- setHistoryIndex(newHistory.length - 1);
394
- // Check if we're navigating to the same URL (ignoring cache-busting)
395
- const compareAgainst = iframeSrc || previewUrl;
396
- const isSameUrl = normalizeUrl(processedUrl) === normalizeUrl(compareAgainst);
397
- // Update the URL input display right away
398
- setUrlInput(getDisplayUrl(processedUrl));
399
- // Force a refresh if navigating to the same URL
400
- if (isSameUrl) {
401
- setIsLoading(true);
402
- setError(null);
403
- reloadIframe();
404
- }
405
- else {
406
- // Normal navigation for different URLs
407
- setPreviewUrl(processedUrl);
408
- }
409
- // Set a timeout to reset loading state if it takes too long
410
- setTimeout(() => {
411
- if (isLoading) {
412
- setIsLoading(false);
413
- }
414
- }, 10000);
415
- }
416
- catch (error) {
417
- console.error("Navigation error:", error);
418
- setError(`Invalid URL: ${error.message || "Unknown error"}`);
419
- setIsLoading(false);
420
- }
421
- };
422
- const handleBack = () => {
423
- var _a, _b;
424
- setIsLoading(true);
425
- // Try to use iframe's own history for same-origin navigations
426
- try {
427
- (_b = (_a = iframeRef.current) === null || _a === void 0 ? void 0 : _a.contentWindow) === null || _b === void 0 ? void 0 : _b.history.back();
428
- // onLoad will sync state when navigation completes
429
- return;
430
- }
431
- catch (_c) {
432
- // Fallback to our own tracked history
433
- }
434
- if (historyIndex > 0) {
435
- const newIndex = historyIndex - 1;
436
- setHistoryIndex(newIndex);
437
- const previousUrl = historyRef.current[newIndex];
438
- setPreviewUrl(previousUrl);
439
- setUrlInput(getDisplayUrl(previousUrl));
440
- }
441
- else {
442
- setIsLoading(false);
443
- }
444
- };
445
- const handleForward = () => {
446
- var _a, _b;
447
- setIsLoading(true);
448
- // Try to use iframe's own history for same-origin navigations
449
- try {
450
- (_b = (_a = iframeRef.current) === null || _a === void 0 ? void 0 : _a.contentWindow) === null || _b === void 0 ? void 0 : _b.history.forward();
451
- // onLoad will sync state when navigation completes
452
- return;
453
- }
454
- catch (_c) {
455
- // Fallback to our own tracked history
456
- }
457
- if (historyIndex < historyRef.current.length - 1) {
458
- const newIndex = historyIndex + 1;
459
- setHistoryIndex(newIndex);
460
- const nextUrl = historyRef.current[newIndex];
461
- setPreviewUrl(nextUrl);
462
- setUrlInput(getDisplayUrl(nextUrl));
463
- }
464
- else {
465
- setIsLoading(false);
466
- }
467
- };
468
- const handleRefresh = () => {
469
- if (previewUrl) {
470
- setIsLoading(true);
471
- setError(null);
472
- reloadIframe();
473
- }
474
- };
475
- const handleUrlChange = (e) => {
476
- if (e.key === "Enter") {
477
- handleNavigate(urlInput);
478
- }
479
- };
480
- // Render the iframe directly with built-in event handlers
481
- const renderIframe = () => {
482
- if (!previewUrl && !iframeSrc)
483
- return null;
484
- return (React.createElement("iframe", { ref: iframeRef, src: iframeSrc || previewUrl, className: cn("h-full w-full border-none", outerContainerClassName), sandbox: "allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-modals allow-downloads allow-top-navigation", allow: "fullscreen; payment; geolocation; microphone; camera", onLoad: () => {
485
- setIsLoading(false);
486
- setError(null);
487
- attachIframeNavigationSync();
488
- syncFromIframe();
489
- }, onError: () => {
490
- console.error("Iframe failed to load");
491
- setIsLoading(false);
492
- setError("Failed to load page");
493
- } }));
494
- };
495
- return (React.createElement("div", { className: "flex h-full w-full flex-col" },
496
- !useVm && !isGuardian && (React.createElement("div", { className: "bg-white dark:bg-black border-b border-zinc-200 dark:border-zinc-800 flex-shrink-0" },
497
- React.createElement("div", { className: "flex items-center gap-1.5 px-2 py-1.5 h-[2.38rem]" },
498
- React.createElement("div", { className: "flex gap-0.5" },
499
- React.createElement("button", { onClick: handleBack, disabled: historyIndex === 0, className: "p-1 hover:bg-zinc-100 dark:hover:bg-zinc-900 rounded disabled:opacity-30 disabled:hover:bg-transparent transition-colors", title: "Back" },
500
- React.createElement(ChevronLeft, { size: 14, className: "text-zinc-600 dark:text-zinc-400" })),
501
- React.createElement("button", { onClick: handleForward, disabled: historyIndex === historyLength - 1, className: "p-1 hover:bg-zinc-100 dark:hover:bg-zinc-900 rounded disabled:opacity-30 disabled:hover:bg-transparent transition-colors", title: "Forward" },
502
- React.createElement(ChevronRight, { size: 14, className: "text-zinc-600 dark:text-zinc-400" })),
503
- React.createElement("button", { onClick: handleRefresh, className: "p-1 hover:bg-zinc-100 dark:hover:bg-zinc-900 rounded transition-colors", title: "Refresh" },
504
- React.createElement(RefreshCw, { size: 14, className: `text-zinc-600 dark:text-zinc-400 ${isLoading ? "animate-spin" : ""}` }))),
505
- React.createElement("div", { className: "flex-1 flex items-center gap-1.5 px-2 py-1 bg-zinc-50 dark:bg-zinc-950 rounded text-zinc-600 dark:text-zinc-400 focus-within:bg-white dark:focus-within:bg-zinc-900 transition-colors" },
506
- error ? (React.createElement(AlertTriangle, { size: 12, className: "text-red-500 flex-shrink-0" })) : (React.createElement(Lock, { size: 12, className: "text-zinc-400 dark:text-zinc-600 flex-shrink-0" })),
507
- React.createElement("input", { type: "text",
508
- // value={urlInput}
509
- value: "/", onChange: (e) => setUrlInput(e.target.value), onKeyDown: handleUrlChange, className: "flex-1 text-xs border-none outline-none bg-transparent text-zinc-700 dark:text-zinc-300 placeholder:text-zinc-400 dark:placeholder:text-zinc-600", placeholder: "Enter URL" }),
510
- isGuardian && (React.createElement("button", { onClick: () => setIsBrowserMaximized(!isBrowserMaximized), className: "p-1 hover:bg-zinc-100 dark:hover:bg-zinc-900 rounded transition-colors", title: isBrowserMaximized
511
- ? "Exit fullscreen"
512
- : "Fullscreen preview" }, isBrowserMaximized ? (React.createElement(Minimize2, { size: 14, className: "text-zinc-600 dark:text-zinc-400" })) : (React.createElement(Maximize2, { size: 14, className: "text-zinc-600 dark:text-zinc-400" })))),
513
- React.createElement("button", { onClick: () => {
514
- window.open(previewUrl, "_blank", "noopener,noreferrer");
515
- }, className: "ml-1 p-1 hover:bg-zinc-100 dark:hover:bg-zinc-900 rounded transition-colors", title: "Open in new tab", disabled: !urlInput || !!error, tabIndex: -1, type: "button" },
516
- React.createElement(ExternalLink, { size: 14, className: "text-zinc-600 dark:text-zinc-400" })),
517
- React.createElement(DropdownMenu, null,
518
- React.createElement(DropdownMenuTrigger, { asChild: true },
519
- React.createElement("button", { className: "ml-1 p-1 hover:bg-zinc-100 dark:hover:bg-zinc-900 rounded transition-colors", title: "More options", type: "button" },
520
- React.createElement(MoreVertical, { size: 14, className: "text-zinc-600 dark:text-zinc-400" }))),
521
- React.createElement(DropdownMenuContent, { align: "end", className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800" },
522
- React.createElement(DropdownMenuItem, { onClick: () => {
523
- // Restart functionality - can be implemented if needed
524
- console.log("Restart app");
525
- }, className: "cursor-pointer text-zinc-700 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-zinc-800" }, "Restart App"))))))),
526
- error && (React.createElement("div", { className: "p-4 bg-red-50 border-b border-red-100 text-red-700 text-sm dark:bg-red-950 dark:border-red-800 dark:text-red-200" },
527
- React.createElement("div", { className: "flex items-center gap-2" },
528
- React.createElement(AlertTriangle, { size: 16 }),
529
- React.createElement("span", null, error)))),
530
- React.createElement("div", { className: "flex-1 min-h-0 relative" },
531
- renderIframe(),
532
- isLoading && (React.createElement("div", { className: "absolute inset-0 bg-zinc-100 dark:bg-zinc-800 bg-opacity-50 flex items-center justify-center z-10" },
533
- React.createElement("div", { className: "text-sm text-zinc-600 bg-white dark:bg-black p-3 rounded-lg shadow-md" },
534
- "Loading ",
535
- urlInput,
536
- "..."))),
537
- children)));
538
- }
@@ -1,8 +0,0 @@
1
- export { default as GuardianPlayground } from "./guardian-playground";
2
- export { default as GuardianComponent } from "./guardian-component";
3
- export { VmProvider, useVmContext } from "./context/vm-context";
4
- export { GuardianProvider, useGuardianContext } from "./context/guardian-context";
5
- export * from "./types";
6
- export { default as CodeFocusSection } from "./code-focus-section";
7
- export { buildGuardianConfig, createSandboxUrlConfigs } from "./utils";
8
- export { Framework, FrameworkLabel } from "./types";
@@ -1,8 +0,0 @@
1
- import React from "react";
2
- import { cn } from "../../../lib/utils";
3
- export default function AppLayoutNoSidebar({ header, hasBodyPadding = true, children, bodyHeight = "h-[calc(100vh-6rem)]", }) {
4
- return (React.createElement("div", null,
5
- header && (React.createElement("header", { className: "flex h-24 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12 w-full" },
6
- React.createElement("div", { className: "flex items-center gap-2 px-4 w-full" }, header))),
7
- React.createElement("div", { className: cn("flex flex-1 flex-col pt-0", hasBodyPadding && "gap-4 p-4", bodyHeight) }, children)));
8
- }
@@ -1,48 +0,0 @@
1
- "use client";
2
- import React, { useState, useRef, useEffect } from "react";
3
- import { Button } from "../../../../components/ui/button";
4
- import { cn } from "../../../../lib/utils";
5
- import { CheckIcon, ChevronsUpDown } from "lucide-react";
6
- export default function GlassmorphicCombobox({ options, value, placeholder, className, searchPlaceholder, onSelect, }) {
7
- var _a;
8
- const [open, setOpen] = useState(false);
9
- const [searchValue, setSearchValue] = useState("");
10
- const containerRef = useRef(null);
11
- const selectedLabel = (_a = options.find((o) => o.value === value)) === null || _a === void 0 ? void 0 : _a.label;
12
- // Filter options based on search
13
- const filteredOptions = options.filter((option) => option.label.toLowerCase().includes(searchValue.toLowerCase()));
14
- // Close on outside click
15
- useEffect(() => {
16
- const handleClickOutside = (event) => {
17
- if (containerRef.current &&
18
- !containerRef.current.contains(event.target)) {
19
- setOpen(false);
20
- setSearchValue("");
21
- }
22
- };
23
- if (open) {
24
- document.addEventListener("mousedown", handleClickOutside);
25
- return () => document.removeEventListener("mousedown", handleClickOutside);
26
- }
27
- }, [open]);
28
- const handleSelect = (option) => {
29
- if (option.href && typeof window !== "undefined") {
30
- window.location.href = option.href;
31
- }
32
- else if (onSelect) {
33
- onSelect(option.value);
34
- }
35
- setOpen(false);
36
- setSearchValue("");
37
- };
38
- return (React.createElement("div", { ref: containerRef, className: "relative" },
39
- React.createElement(Button, { variant: "outline", role: "combobox", "aria-expanded": open, onClick: () => setOpen(!open), className: cn("w-64 justify-between rounded-xl border-white/20 bg-white/10 backdrop-blur-md", "text-white/90 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.25)] hover:bg-white/15", "data-[state=open]:bg-white/15", className) },
40
- React.createElement("span", { className: "truncate min-w-0" }, selectedLabel !== null && selectedLabel !== void 0 ? selectedLabel : placeholder),
41
- React.createElement(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-70" })),
42
- open && (React.createElement("div", { className: cn("absolute top-full mt-1 w-64 p-0 rounded-xl border border-white/20 bg-black/40 backdrop-blur-xl", "shadow-xl z-50") },
43
- React.createElement("div", { className: "p-2" },
44
- React.createElement("input", { type: "text", placeholder: searchPlaceholder, value: searchValue, onChange: (e) => setSearchValue(e.target.value), className: "w-full px-3 py-2 rounded-md bg-transparent border border-white/20 text-white placeholder:text-white/60 focus:outline-none focus:border-white/40" })),
45
- React.createElement("div", { className: "max-h-[300px] overflow-y-auto" }, filteredOptions.length === 0 ? (React.createElement("div", { className: "px-3 py-2 text-white/80 text-sm" }, "No results found.")) : (React.createElement("div", { className: "p-1" }, filteredOptions.map((option) => (React.createElement("div", { key: option.value, onClick: () => handleSelect(option), className: cn("flex items-center px-2 py-1.5 rounded-sm cursor-pointer text-sm", "hover:bg-white/10", value === option.value && "bg-white/10") },
46
- React.createElement(CheckIcon, { className: cn("mr-2 h-4 w-4", value === option.value ? "opacity-100" : "opacity-0") }),
47
- option.label))))))))));
48
- }
@@ -1,63 +0,0 @@
1
- "use client";
2
- import React from "react";
3
- import { Badge } from "../ui/badge";
4
- import GlassmorphicCombobox from "./header/glassmorphic-combobox";
5
- export default function Header({ demoOptions, frameworkOptions, firstFrameworkByUseCase, currentFramework, playgroundLogo, currentUseCase, }) {
6
- var _a, _b, _c, _d;
7
- // Derive values directly from props (which come from the URL)
8
- // No internal state - the URL is the source of truth
9
- const selectedUseCase = currentUseCase || ((_a = demoOptions[0]) === null || _a === void 0 ? void 0 : _a.value);
10
- const selectedFramework = currentFramework || ((_b = frameworkOptions[0]) === null || _b === void 0 ? void 0 : _b.value);
11
- // Build options with hrefs
12
- const demoOptionsWithHrefs = demoOptions.map((opt) => {
13
- var _a;
14
- return (Object.assign(Object.assign({}, opt), {
15
- // Link to first available framework for this use case
16
- href: `/${opt.value}?framework=${(firstFrameworkByUseCase === null || firstFrameworkByUseCase === void 0 ? void 0 : firstFrameworkByUseCase[opt.value]) || ((_a = frameworkOptions[0]) === null || _a === void 0 ? void 0 : _a.value)}` }));
17
- });
18
- const frameworkOptionsWithHrefs = frameworkOptions.map((opt) => (Object.assign(Object.assign({}, opt), { href: `/${selectedUseCase}?framework=${opt.value}` })));
19
- // Derive environment metadata for badge styling and label
20
- const environment = ((typeof window !== "undefined" &&
21
- ((_d = (_c = window.__NEXT_DATA__) === null || _c === void 0 ? void 0 : _c.env) === null || _d === void 0 ? void 0 : _d.NEXT_PUBLIC_ENVIRONMENT)) ||
22
- process.env.NEXT_PUBLIC_ENVIRONMENT ||
23
- process.env.NODE_ENV ||
24
- "development").toLowerCase();
25
- const envMeta = {
26
- production: {
27
- label: "Production",
28
- badgeClass: "border-emerald-500/30 bg-emerald-500/10 text-emerald-200",
29
- dotClass: "bg-emerald-400 shadow-[0_0_0_3px_rgba(16,185,129,0.25)]",
30
- },
31
- staging: {
32
- label: "Staging",
33
- badgeClass: "border-amber-500/30 bg-amber-500/10 text-amber-100",
34
- dotClass: "bg-amber-400 shadow-[0_0_0_3px_rgba(245,158,11,0.25)]",
35
- },
36
- test: {
37
- label: "Test",
38
- badgeClass: "border-cyan-500/30 bg-cyan-500/10 text-cyan-100",
39
- dotClass: "bg-cyan-400 shadow-[0_0_0_3px_rgba(34,211,238,0.25)]",
40
- },
41
- preview: {
42
- label: "Preview",
43
- badgeClass: "border-sky-500/30 bg-sky-500/10 text-sky-100",
44
- dotClass: "bg-sky-400 shadow-[0_0_0_3px_rgba(56,189,248,0.25)]",
45
- },
46
- development: {
47
- label: "Demo Environment",
48
- badgeClass: "border-violet-500/30 bg-violet-500/10 text-violet-100",
49
- dotClass: "bg-violet-400 shadow-[0_0_0_3px_rgba(139,92,246,0.25)]",
50
- },
51
- };
52
- const meta = envMeta[environment] || envMeta.development;
53
- return (React.createElement("div", { className: "grid grid-cols-[1fr_auto_1fr] items-center w-full ml-6" },
54
- React.createElement("div", { className: "justify-self-start" }, playgroundLogo),
55
- React.createElement("div", { className: "justify-self-center" },
56
- React.createElement("div", { className: "flex gap-2" },
57
- React.createElement(GlassmorphicCombobox, { options: demoOptionsWithHrefs, value: selectedUseCase, placeholder: "Select use case...", searchPlaceholder: "Search use case..." }),
58
- React.createElement(GlassmorphicCombobox, { options: frameworkOptionsWithHrefs, value: selectedFramework, placeholder: "Select framework...", searchPlaceholder: "Search framework...", className: "w-32" }))),
59
- React.createElement("div", { className: "justify-self-end mr-6" },
60
- React.createElement(Badge, { className: `rounded-full px-5 py-3 flex items-center gap-2 border ${meta.badgeClass} backdrop-blur-sm shadow-[inset_0_1px_0_rgba(255,255,255,0.04)] text-sm`, "aria-label": `${meta.label} environment` },
61
- React.createElement("span", { className: `inline-block h-2 w-2 rounded-full ${meta.dotClass}` }),
62
- meta.label))));
63
- }