@hanzo/ui 5.3.28 → 5.3.30

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 (229) hide show
  1. package/dist/3d/button.js +298 -0
  2. package/dist/3d/button.mjs +273 -0
  3. package/dist/3d/card.js +234 -0
  4. package/dist/3d/card.mjs +207 -0
  5. package/dist/3d/carousel.js +371 -0
  6. package/dist/3d/carousel.mjs +344 -0
  7. package/dist/3d/grid.js +362 -0
  8. package/dist/3d/grid.mjs +337 -0
  9. package/dist/3d/index.js +1518 -0
  10. package/dist/3d/index.mjs +1472 -0
  11. package/dist/3d/marquee.js +352 -0
  12. package/dist/3d/marquee.mjs +327 -0
  13. package/dist/3d/pin.js +46 -0
  14. package/dist/3d/pin.mjs +24 -0
  15. package/dist/accordion.js +80 -0
  16. package/dist/accordion.mjs +55 -0
  17. package/dist/alert-dialog.js +220 -0
  18. package/dist/alert-dialog.mjs +187 -0
  19. package/dist/alert.js +68 -0
  20. package/dist/alert.mjs +64 -0
  21. package/dist/animation/animated-background.js +424 -0
  22. package/dist/animation/animated-background.mjs +418 -0
  23. package/dist/animation/animated-beam.js +119 -0
  24. package/dist/animation/animated-beam.mjs +97 -0
  25. package/dist/animation/animated-cursor.js +275 -0
  26. package/dist/animation/animated-cursor.mjs +270 -0
  27. package/dist/animation/animated-icon.js +357 -0
  28. package/dist/animation/animated-icon.mjs +351 -0
  29. package/dist/animation/animated-list.js +339 -0
  30. package/dist/animation/animated-list.mjs +333 -0
  31. package/dist/animation/animated-number.js +283 -0
  32. package/dist/animation/animated-number.mjs +277 -0
  33. package/dist/animation/animated-testimonials.js +97 -0
  34. package/dist/animation/animated-testimonials.mjs +75 -0
  35. package/dist/animation/animated-tooltip.js +67 -0
  36. package/dist/animation/animated-tooltip.mjs +45 -0
  37. package/dist/animation/apple-cards-carousel.js +308 -0
  38. package/dist/animation/apple-cards-carousel.mjs +285 -0
  39. package/dist/animation/apple-hello-effect.js +60 -0
  40. package/dist/animation/apple-hello-effect.mjs +38 -0
  41. package/dist/animation/index.js +1952 -0
  42. package/dist/animation/index.mjs +1921 -0
  43. package/dist/avatar.js +71 -0
  44. package/dist/avatar.mjs +47 -0
  45. package/dist/badge.js +66 -0
  46. package/dist/badge.mjs +40 -0
  47. package/dist/blocks/index.js +1665 -0
  48. package/dist/blocks/index.mjs +1626 -0
  49. package/dist/breadcrumb.js +107 -0
  50. package/dist/breadcrumb.mjs +99 -0
  51. package/dist/calendar.js +189 -0
  52. package/dist/calendar.mjs +164 -0
  53. package/dist/carousel.js +278 -0
  54. package/dist/carousel.mjs +249 -0
  55. package/dist/checkbox.js +60 -0
  56. package/dist/checkbox.mjs +35 -0
  57. package/dist/code/block.js +226 -0
  58. package/dist/code/block.mjs +203 -0
  59. package/dist/code/compare.js +446 -0
  60. package/dist/code/compare.mjs +423 -0
  61. package/dist/code/diff.js +430 -0
  62. package/dist/code/diff.mjs +407 -0
  63. package/dist/code/editor.js +243 -0
  64. package/dist/code/editor.mjs +218 -0
  65. package/dist/code/explorer.js +291 -0
  66. package/dist/code/explorer.mjs +268 -0
  67. package/dist/code/index.js +2551 -0
  68. package/dist/code/index.mjs +2510 -0
  69. package/dist/code/preview.js +400 -0
  70. package/dist/code/preview.mjs +377 -0
  71. package/dist/code/snippet.js +274 -0
  72. package/dist/code/snippet.mjs +250 -0
  73. package/dist/code/tabs.js +75 -0
  74. package/dist/code/tabs.mjs +53 -0
  75. package/dist/code/terminal.js +437 -0
  76. package/dist/code/terminal.mjs +414 -0
  77. package/dist/collapsible.js +33 -0
  78. package/dist/collapsible.mjs +9 -0
  79. package/dist/command.js +262 -0
  80. package/dist/command.mjs +232 -0
  81. package/dist/context-menu.js +207 -0
  82. package/dist/context-menu.mjs +171 -0
  83. package/dist/device/index.js +3 -0
  84. package/dist/device/index.mjs +2 -0
  85. package/dist/dialog.js +151 -0
  86. package/dist/dialog.mjs +121 -0
  87. package/dist/dock/basic.js +174 -0
  88. package/dist/dock/basic.mjs +151 -0
  89. package/dist/dock/index.js +628 -0
  90. package/dist/dock/index.mjs +601 -0
  91. package/dist/dock/limelight-nav.js +295 -0
  92. package/dist/dock/limelight-nav.mjs +274 -0
  93. package/dist/dock/macos.js +141 -0
  94. package/dist/dock/macos.mjs +118 -0
  95. package/dist/dock/menu.js +70 -0
  96. package/dist/dock/menu.mjs +48 -0
  97. package/dist/dock/message.js +144 -0
  98. package/dist/dock/message.mjs +122 -0
  99. package/dist/drawer.js +115 -0
  100. package/dist/drawer.mjs +103 -0
  101. package/dist/dropdown-menu.js +202 -0
  102. package/dist/dropdown-menu.mjs +166 -0
  103. package/dist/finance/AdvancedChart.js +48 -0
  104. package/dist/finance/AdvancedChart.mjs +46 -0
  105. package/dist/finance/CompanyProfile.js +48 -0
  106. package/dist/finance/CompanyProfile.mjs +46 -0
  107. package/dist/finance/CryptoScreener.js +45 -0
  108. package/dist/finance/CryptoScreener.mjs +43 -0
  109. package/dist/finance/Financials.js +52 -0
  110. package/dist/finance/Financials.mjs +50 -0
  111. package/dist/finance/ForexScreener.js +46 -0
  112. package/dist/finance/ForexScreener.mjs +44 -0
  113. package/dist/finance/MarketOverview.js +104 -0
  114. package/dist/finance/MarketOverview.mjs +102 -0
  115. package/dist/finance/NewsTimeline.js +44 -0
  116. package/dist/finance/NewsTimeline.mjs +42 -0
  117. package/dist/finance/OrderEntry.js +131 -0
  118. package/dist/finance/OrderEntry.mjs +129 -0
  119. package/dist/finance/OrdersHistory.js +64 -0
  120. package/dist/finance/OrdersHistory.mjs +62 -0
  121. package/dist/finance/PositionsList.js +80 -0
  122. package/dist/finance/PositionsList.mjs +78 -0
  123. package/dist/finance/StockScreener.js +46 -0
  124. package/dist/finance/StockScreener.mjs +44 -0
  125. package/dist/finance/SymbolInfo.js +46 -0
  126. package/dist/finance/SymbolInfo.mjs +44 -0
  127. package/dist/finance/TechnicalAnalysis.js +54 -0
  128. package/dist/finance/TechnicalAnalysis.mjs +52 -0
  129. package/dist/finance/TickerTape.js +56 -0
  130. package/dist/finance/TickerTape.mjs +54 -0
  131. package/dist/finance/TradingPanel.js +191 -0
  132. package/dist/finance/TradingPanel.mjs +189 -0
  133. package/dist/finance/index.js +930 -0
  134. package/dist/finance/index.mjs +914 -0
  135. package/dist/form/index.js +155 -0
  136. package/dist/form/index.mjs +125 -0
  137. package/dist/form.js +172 -0
  138. package/dist/form.mjs +142 -0
  139. package/dist/hover-card.js +58 -0
  140. package/dist/hover-card.mjs +34 -0
  141. package/dist/index.js +8467 -0
  142. package/dist/index.mjs +8087 -0
  143. package/dist/input-otp.js +79 -0
  144. package/dist/input-otp.mjs +54 -0
  145. package/dist/lib/utils.js +28 -0
  146. package/dist/lib/utils.mjs +24 -0
  147. package/dist/navigation/index.js +98 -0
  148. package/dist/navigation/index.mjs +79 -0
  149. package/dist/navigation-menu.js +149 -0
  150. package/dist/navigation-menu.mjs +116 -0
  151. package/dist/pattern/grid-pattern.js +333 -0
  152. package/dist/pattern/grid-pattern.mjs +310 -0
  153. package/dist/pattern/index.js +333 -0
  154. package/dist/pattern/index.mjs +310 -0
  155. package/dist/popover.js +63 -0
  156. package/dist/popover.mjs +37 -0
  157. package/dist/primitives/index.js +8467 -0
  158. package/dist/primitives/index.mjs +8087 -0
  159. package/dist/primitives-export.js +8467 -0
  160. package/dist/primitives-export.mjs +8087 -0
  161. package/dist/progress.js +62 -0
  162. package/dist/progress.mjs +37 -0
  163. package/dist/project/gantt.js +65 -0
  164. package/dist/project/gantt.mjs +43 -0
  165. package/dist/project/index.js +636 -0
  166. package/dist/project/index.mjs +611 -0
  167. package/dist/project/kanban.js +597 -0
  168. package/dist/project/kanban.mjs +572 -0
  169. package/dist/project/list.js +35 -0
  170. package/dist/project/list.mjs +12 -0
  171. package/dist/radio-group.js +68 -0
  172. package/dist/radio-group.mjs +45 -0
  173. package/dist/resizable.js +72 -0
  174. package/dist/resizable.mjs +48 -0
  175. package/dist/scroll-area.js +89 -0
  176. package/dist/scroll-area.mjs +66 -0
  177. package/dist/select.js +140 -0
  178. package/dist/select.mjs +111 -0
  179. package/dist/separator.js +59 -0
  180. package/dist/separator.mjs +34 -0
  181. package/dist/sheet.js +148 -0
  182. package/dist/sheet.mjs +117 -0
  183. package/dist/skeleton.js +32 -0
  184. package/dist/skeleton.mjs +27 -0
  185. package/dist/slider.js +99 -0
  186. package/dist/slider.mjs +73 -0
  187. package/dist/sonner.js +34 -0
  188. package/dist/sonner.mjs +29 -0
  189. package/dist/switch.js +62 -0
  190. package/dist/switch.mjs +37 -0
  191. package/dist/table.js +110 -0
  192. package/dist/table.mjs +101 -0
  193. package/dist/tabs.js +82 -0
  194. package/dist/tabs.mjs +57 -0
  195. package/dist/tailwind/index.js +2023 -0
  196. package/dist/tailwind/index.mjs +2011 -0
  197. package/dist/textarea.js +78 -0
  198. package/dist/textarea.mjs +56 -0
  199. package/dist/toggle-group.js +118 -0
  200. package/dist/toggle-group.mjs +93 -0
  201. package/dist/toggle.js +71 -0
  202. package/dist/toggle.mjs +48 -0
  203. package/dist/tooltip.js +67 -0
  204. package/dist/tooltip.mjs +40 -0
  205. package/dist/types/index.js +57 -0
  206. package/dist/types/index.mjs +51 -0
  207. package/dist/ui/announcement.js +129 -0
  208. package/dist/ui/announcement.mjs +107 -0
  209. package/dist/ui/avatar-group.js +88 -0
  210. package/dist/ui/avatar-group.mjs +65 -0
  211. package/dist/ui/banner.js +85 -0
  212. package/dist/ui/banner.mjs +62 -0
  213. package/dist/ui/cursor.js +78 -0
  214. package/dist/ui/cursor.mjs +56 -0
  215. package/dist/ui/index.js +475 -0
  216. package/dist/ui/index.mjs +442 -0
  217. package/dist/ui/marquee.js +74 -0
  218. package/dist/ui/marquee.mjs +52 -0
  219. package/dist/ui/pill.js +85 -0
  220. package/dist/ui/pill.mjs +62 -0
  221. package/dist/ui/spinner.js +28 -0
  222. package/dist/ui/spinner.mjs +26 -0
  223. package/dist/ui/tags.js +101 -0
  224. package/dist/ui/tags.mjs +79 -0
  225. package/dist/ui/ticker.js +73 -0
  226. package/dist/ui/ticker.mjs +51 -0
  227. package/dist/util/index.js +463 -0
  228. package/dist/util/index.mjs +404 -0
  229. package/package.json +1 -1
@@ -0,0 +1,377 @@
1
+ "use client";
2
+ import * as React from 'react';
3
+ import { cva } from 'class-variance-authority';
4
+ import { Check, Copy, Eye, EyeOff, Terminal, RefreshCw, Play, Square, Settings, AlertTriangle, X } from 'lucide-react';
5
+ import { cn } from '@hanzo/ui/lib/utils';
6
+ import { Badge } from '@hanzo/ui/badge';
7
+ import { Button } from '@hanzo/ui/button';
8
+ import { CodeSnippet } from '@hanzo/ui/code/snippet';
9
+ import { Separator } from '@hanzo/ui/separator';
10
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from '@hanzo/ui/tabs';
11
+ import { Toggle } from '@hanzo/ui/toggle';
12
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
13
+
14
+ var __defProp = Object.defineProperty;
15
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
16
+ var codePreviewVariants = cva(
17
+ "relative overflow-hidden rounded-lg border bg-background",
18
+ {
19
+ variants: {
20
+ size: {
21
+ sm: "text-xs",
22
+ default: "text-sm",
23
+ lg: "text-base"
24
+ }
25
+ },
26
+ defaultVariants: {
27
+ size: "default"
28
+ }
29
+ }
30
+ );
31
+ var runHTMLCode = /* @__PURE__ */ __name((files) => {
32
+ const htmlFile = files.find((f) => f.type === "html");
33
+ const cssFiles = files.filter((f) => f.type === "css");
34
+ const jsFiles = files.filter((f) => f.type === "js");
35
+ let html = htmlFile?.content || "<div>No HTML file provided</div>";
36
+ if (cssFiles.length > 0) {
37
+ const cssContent = cssFiles.map((f) => f.content).join("\n");
38
+ html = `<style>${cssContent}</style>
39
+ ${html}`;
40
+ }
41
+ if (jsFiles.length > 0) {
42
+ const jsContent = jsFiles.map((f) => f.content).join("\n");
43
+ html = `${html}
44
+ <script>${jsContent}</script>`;
45
+ }
46
+ return html;
47
+ }, "runHTMLCode");
48
+ var consoleScript = `
49
+ <script>
50
+ const originalConsole = window.console;
51
+ const logs = [];
52
+
53
+ ['log', 'warn', 'error', 'info'].forEach(method => {
54
+ window.console[method] = function(...args) {
55
+ logs.push({
56
+ type: method,
57
+ content: args.map(arg =>
58
+ typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
59
+ ).join(' '),
60
+ timestamp: Date.now()
61
+ });
62
+
63
+ // Also call original console method
64
+ originalConsole[method].apply(originalConsole, arguments);
65
+
66
+ // Send to parent
67
+ window.parent.postMessage({
68
+ type: 'console',
69
+ data: logs[logs.length - 1]
70
+ }, '*');
71
+ };
72
+ });
73
+
74
+ window.addEventListener('error', (e) => {
75
+ window.parent.postMessage({
76
+ type: 'error',
77
+ data: {
78
+ type: 'error',
79
+ content: e.message + ' at ' + e.filename + ':' + e.lineno,
80
+ timestamp: Date.now()
81
+ }
82
+ }, '*');
83
+ });
84
+ </script>
85
+ `;
86
+ var CodePreview = React.forwardRef(
87
+ ({
88
+ className,
89
+ size,
90
+ files,
91
+ defaultFile,
92
+ showPreview = true,
93
+ showConsole = true,
94
+ autoRun = false,
95
+ maxHeight = "600px",
96
+ previewHeight = "300px",
97
+ consoleHeight = "150px",
98
+ allowFullscreen = true,
99
+ customRunner,
100
+ ...props
101
+ }, ref) => {
102
+ const [activeFile, setActiveFile] = React.useState(
103
+ defaultFile || files[0]?.filename || ""
104
+ );
105
+ const [previewContent, setPreviewContent] = React.useState("");
106
+ const [isRunning, setIsRunning] = React.useState(false);
107
+ const [results, setResults] = React.useState([]);
108
+ const [isPreviewVisible, setIsPreviewVisible] = React.useState(showPreview);
109
+ const [isConsoleVisible, setIsConsoleVisible] = React.useState(showConsole);
110
+ const [isFullscreen, setIsFullscreen] = React.useState(false);
111
+ const [copied, setCopied] = React.useState({});
112
+ const iframeRef = React.useRef(null);
113
+ files.find((f) => f.filename === activeFile) || files[0];
114
+ React.useEffect(() => {
115
+ const handleMessage = /* @__PURE__ */ __name((event) => {
116
+ if (event.data?.type === "console" || event.data?.type === "error") {
117
+ setResults((prev) => [...prev, event.data.data]);
118
+ }
119
+ }, "handleMessage");
120
+ window.addEventListener("message", handleMessage);
121
+ return () => window.removeEventListener("message", handleMessage);
122
+ }, []);
123
+ const runCode = React.useCallback(async () => {
124
+ setIsRunning(true);
125
+ setResults([]);
126
+ try {
127
+ let output;
128
+ if (customRunner) {
129
+ output = await customRunner(files);
130
+ } else {
131
+ output = runHTMLCode(files);
132
+ }
133
+ output = consoleScript + output;
134
+ setPreviewContent(output);
135
+ if (iframeRef.current) {
136
+ const doc = iframeRef.current.contentDocument;
137
+ if (doc) {
138
+ doc.open();
139
+ doc.write(output);
140
+ doc.close();
141
+ }
142
+ }
143
+ } catch (error) {
144
+ setResults([
145
+ {
146
+ type: "error",
147
+ content: error instanceof Error ? error.message : String(error),
148
+ timestamp: Date.now()
149
+ }
150
+ ]);
151
+ } finally {
152
+ setIsRunning(false);
153
+ }
154
+ }, [files, customRunner]);
155
+ React.useEffect(() => {
156
+ if (autoRun) {
157
+ const timer = setTimeout(runCode, 1e3);
158
+ return () => clearTimeout(timer);
159
+ }
160
+ }, [files, autoRun, runCode]);
161
+ const copyFileContent = React.useCallback(
162
+ async (filename) => {
163
+ const file = files.find((f) => f.filename === filename);
164
+ if (!file) return;
165
+ try {
166
+ await navigator.clipboard.writeText(file.content);
167
+ setCopied((prev) => ({ ...prev, [filename]: true }));
168
+ setTimeout(() => {
169
+ setCopied((prev) => ({ ...prev, [filename]: false }));
170
+ }, 2e3);
171
+ } catch (error) {
172
+ console.error("Failed to copy code:", error);
173
+ }
174
+ },
175
+ [files]
176
+ );
177
+ const clearConsole = /* @__PURE__ */ __name(() => {
178
+ setResults([]);
179
+ }, "clearConsole");
180
+ const renderConsole = /* @__PURE__ */ __name(() => /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
181
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b px-4 py-2 bg-muted/30", children: [
182
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
183
+ /* @__PURE__ */ jsx(Terminal, { className: "h-4 w-4" }),
184
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Console" }),
185
+ results.length > 0 && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs", children: results.length })
186
+ ] }),
187
+ /* @__PURE__ */ jsx(
188
+ Button,
189
+ {
190
+ variant: "ghost",
191
+ size: "sm",
192
+ onClick: clearConsole,
193
+ className: "h-8 w-8 p-0",
194
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
195
+ }
196
+ )
197
+ ] }),
198
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto p-2 space-y-1 font-mono text-xs", children: results.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground italic", children: "No output" }) : results.map((result, index) => /* @__PURE__ */ jsxs(
199
+ "div",
200
+ {
201
+ className: cn(
202
+ "flex items-start gap-2 p-2 rounded",
203
+ result.type === "error" && "bg-red-500/10 text-red-600 dark:text-red-400",
204
+ result.type === "log" && "bg-blue-500/10 text-blue-600 dark:text-blue-400",
205
+ result.type === "output" && "bg-green-500/10 text-green-600 dark:text-green-400"
206
+ ),
207
+ children: [
208
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: new Date(result.timestamp).toLocaleTimeString() }),
209
+ /* @__PURE__ */ jsx("pre", { className: "flex-1 whitespace-pre-wrap break-words", children: result.content })
210
+ ]
211
+ },
212
+ index
213
+ )) })
214
+ ] }), "renderConsole");
215
+ const layout = isFullscreen ? "fixed inset-0 z-50 bg-background" : "";
216
+ return /* @__PURE__ */ jsxs(
217
+ "div",
218
+ {
219
+ ref,
220
+ className: cn(codePreviewVariants({ size }), layout, className),
221
+ style: { maxHeight: isFullscreen ? "100vh" : maxHeight },
222
+ ...props,
223
+ children: [
224
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b px-4 py-2", children: [
225
+ /* @__PURE__ */ jsx(
226
+ Tabs,
227
+ {
228
+ value: activeFile,
229
+ onValueChange: setActiveFile,
230
+ className: "flex-1",
231
+ children: /* @__PURE__ */ jsx(TabsList, { className: "h-auto p-0 bg-transparent", children: files.map((file) => /* @__PURE__ */ jsxs(
232
+ TabsTrigger,
233
+ {
234
+ value: file.filename,
235
+ className: "relative flex items-center gap-2 data-[state=active]:bg-muted",
236
+ children: [
237
+ /* @__PURE__ */ jsx("span", { children: file.filename }),
238
+ /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "text-xs", children: file.language }),
239
+ /* @__PURE__ */ jsx(
240
+ Button,
241
+ {
242
+ variant: "ghost",
243
+ size: "sm",
244
+ onClick: (e) => {
245
+ e.stopPropagation();
246
+ copyFileContent(file.filename);
247
+ },
248
+ className: "h-6 w-6 p-0 opacity-0 group-hover:opacity-100",
249
+ children: copied[file.filename] ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 text-green-500" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3" })
250
+ }
251
+ )
252
+ ]
253
+ },
254
+ file.filename
255
+ )) })
256
+ }
257
+ ),
258
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
259
+ /* @__PURE__ */ jsx(
260
+ Toggle,
261
+ {
262
+ pressed: isPreviewVisible,
263
+ onPressedChange: setIsPreviewVisible,
264
+ "aria-label": "Toggle preview",
265
+ size: "sm",
266
+ children: isPreviewVisible ? /* @__PURE__ */ jsx(Eye, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(EyeOff, { className: "h-4 w-4" })
267
+ }
268
+ ),
269
+ /* @__PURE__ */ jsx(
270
+ Toggle,
271
+ {
272
+ pressed: isConsoleVisible,
273
+ onPressedChange: setIsConsoleVisible,
274
+ "aria-label": "Toggle console",
275
+ size: "sm",
276
+ children: /* @__PURE__ */ jsx(Terminal, { className: "h-4 w-4" })
277
+ }
278
+ ),
279
+ /* @__PURE__ */ jsxs(
280
+ Button,
281
+ {
282
+ variant: "outline",
283
+ size: "sm",
284
+ onClick: runCode,
285
+ disabled: isRunning,
286
+ className: "gap-2",
287
+ children: [
288
+ isRunning ? /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Play, { className: "h-4 w-4" }),
289
+ "Run"
290
+ ]
291
+ }
292
+ ),
293
+ allowFullscreen && /* @__PURE__ */ jsx(
294
+ Button,
295
+ {
296
+ variant: "ghost",
297
+ size: "sm",
298
+ onClick: () => setIsFullscreen(!isFullscreen),
299
+ className: "h-8 w-8 p-0",
300
+ children: isFullscreen ? /* @__PURE__ */ jsx(Square, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" })
301
+ }
302
+ )
303
+ ] })
304
+ ] }),
305
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
306
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsx(Tabs, { value: activeFile, onValueChange: setActiveFile, children: files.map((file) => /* @__PURE__ */ jsx(
307
+ TabsContent,
308
+ {
309
+ value: file.filename,
310
+ className: "m-0 h-full",
311
+ children: /* @__PURE__ */ jsx(
312
+ CodeSnippet,
313
+ {
314
+ code: file.content,
315
+ language: file.language,
316
+ showLineNumbers: true,
317
+ showCopyButton: false,
318
+ showHeader: false,
319
+ maxHeight: "100%",
320
+ className: "border-0 rounded-none"
321
+ }
322
+ )
323
+ },
324
+ file.filename
325
+ )) }) }),
326
+ (isPreviewVisible || isConsoleVisible) && /* @__PURE__ */ jsxs(Fragment, { children: [
327
+ /* @__PURE__ */ jsx(Separator, {}),
328
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col lg:flex-row min-h-0", children: [
329
+ isPreviewVisible && /* @__PURE__ */ jsxs(
330
+ "div",
331
+ {
332
+ className: "flex-1 min-h-0 border-r last:border-r-0",
333
+ style: { height: previewHeight },
334
+ children: [
335
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b px-4 py-2 bg-muted/30", children: [
336
+ /* @__PURE__ */ jsx(Eye, { className: "h-4 w-4" }),
337
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Preview" }),
338
+ results.filter((r) => r.type === "error").length > 0 && /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 text-red-500" })
339
+ ] }),
340
+ /* @__PURE__ */ jsx(
341
+ "iframe",
342
+ {
343
+ ref: iframeRef,
344
+ className: "w-full h-full bg-white",
345
+ sandbox: "allow-scripts allow-same-origin",
346
+ srcDoc: previewContent
347
+ }
348
+ )
349
+ ]
350
+ }
351
+ ),
352
+ isConsoleVisible && /* @__PURE__ */ jsx(
353
+ "div",
354
+ {
355
+ className: "flex-1 min-h-0",
356
+ style: { height: consoleHeight },
357
+ children: renderConsole()
358
+ }
359
+ )
360
+ ] })
361
+ ] })
362
+ ] }),
363
+ isFullscreen && /* @__PURE__ */ jsx(
364
+ "div",
365
+ {
366
+ className: "absolute inset-0 bg-black/50",
367
+ onClick: () => setIsFullscreen(false)
368
+ }
369
+ )
370
+ ]
371
+ }
372
+ );
373
+ }
374
+ );
375
+ CodePreview.displayName = "CodePreview";
376
+
377
+ export { CodePreview, codePreviewVariants };
@@ -0,0 +1,274 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var React = require('react');
5
+ var classVarianceAuthority = require('class-variance-authority');
6
+ var lucideReact = require('lucide-react');
7
+ var shiki = require('shiki');
8
+ var utils = require('@hanzo/ui/lib/utils');
9
+ var badge = require('@hanzo/ui/badge');
10
+ var button = require('@hanzo/ui/button');
11
+ var skeleton = require('@hanzo/ui/skeleton');
12
+ var jsxRuntime = require('react/jsx-runtime');
13
+
14
+ function _interopNamespace(e) {
15
+ if (e && e.__esModule) return e;
16
+ var n = Object.create(null);
17
+ if (e) {
18
+ Object.keys(e).forEach(function (k) {
19
+ if (k !== 'default') {
20
+ var d = Object.getOwnPropertyDescriptor(e, k);
21
+ Object.defineProperty(n, k, d.get ? d : {
22
+ enumerable: true,
23
+ get: function () { return e[k]; }
24
+ });
25
+ }
26
+ });
27
+ }
28
+ n.default = e;
29
+ return Object.freeze(n);
30
+ }
31
+
32
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
33
+
34
+ var __defProp = Object.defineProperty;
35
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
36
+ var codeSnippetVariants = classVarianceAuthority.cva("relative group", {
37
+ variants: {
38
+ variant: {
39
+ default: "rounded-lg border bg-muted/50",
40
+ inline: "inline-block rounded-md bg-muted px-2 py-1",
41
+ minimal: "bg-transparent"
42
+ },
43
+ theme: {
44
+ dark: "bg-slate-950 border-slate-800",
45
+ light: "bg-slate-50 border-slate-200",
46
+ github: "bg-white border-slate-200",
47
+ "github-dark": "bg-slate-900 border-slate-700",
48
+ terminal: "bg-black border-green-500/30 text-green-400",
49
+ retro: "bg-amber-50 border-amber-200 text-amber-900"
50
+ },
51
+ size: {
52
+ xs: "text-xs",
53
+ sm: "text-sm",
54
+ default: "text-sm",
55
+ lg: "text-base"
56
+ }
57
+ },
58
+ defaultVariants: {
59
+ variant: "default",
60
+ theme: "dark",
61
+ size: "default"
62
+ }
63
+ });
64
+ var CodeSnippet = React__namespace.forwardRef(
65
+ ({
66
+ className,
67
+ variant,
68
+ theme,
69
+ size,
70
+ code,
71
+ language = "text",
72
+ filename,
73
+ showLineNumbers = false,
74
+ highlightLines = [],
75
+ showCopyButton = true,
76
+ showLanguageBadge = true,
77
+ showHeader = true,
78
+ maxHeight,
79
+ expandable = false,
80
+ collapsedHeight = "200px",
81
+ wrapLines = false,
82
+ startLineNumber = 1,
83
+ ...props
84
+ }, ref) => {
85
+ const [highlightedCode, setHighlightedCode] = React__namespace.useState("");
86
+ const [copied, setCopied] = React__namespace.useState(false);
87
+ const [isLoading, setIsLoading] = React__namespace.useState(true);
88
+ const [isExpanded, setIsExpanded] = React__namespace.useState(!expandable);
89
+ const themeMap = {
90
+ dark: "github-dark",
91
+ light: "github-light",
92
+ github: "github-light",
93
+ "github-dark": "github-dark",
94
+ terminal: "github-dark",
95
+ retro: "github-light"
96
+ };
97
+ React__namespace.useEffect(() => {
98
+ const highlightCode = /* @__PURE__ */ __name(async () => {
99
+ setIsLoading(true);
100
+ try {
101
+ const supportedLang = Object.keys(shiki.bundledLanguages).includes(language);
102
+ const highlighted = await shiki.codeToHtml(code, {
103
+ lang: supportedLang ? language : "text",
104
+ theme: themeMap[theme || "dark"]
105
+ });
106
+ const tempDiv = document.createElement("div");
107
+ tempDiv.innerHTML = highlighted;
108
+ const codeElement = tempDiv.querySelector("code");
109
+ setHighlightedCode(codeElement?.innerHTML || highlighted);
110
+ } catch (error) {
111
+ console.error("Failed to highlight code:", error);
112
+ const escaped = code.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
113
+ setHighlightedCode(escaped);
114
+ } finally {
115
+ setIsLoading(false);
116
+ }
117
+ }, "highlightCode");
118
+ highlightCode();
119
+ }, [code, language, theme]);
120
+ const copyToClipboard = React__namespace.useCallback(async () => {
121
+ try {
122
+ await navigator.clipboard.writeText(code);
123
+ setCopied(true);
124
+ setTimeout(() => setCopied(false), 2e3);
125
+ } catch (error) {
126
+ console.error("Failed to copy code:", error);
127
+ }
128
+ }, [code]);
129
+ const lines = highlightedCode.split("\n").filter((line, index, array) => {
130
+ return line.trim() !== "" || index < array.length - 1;
131
+ });
132
+ const renderInline = /* @__PURE__ */ __name(() => /* @__PURE__ */ jsxRuntime.jsx(
133
+ "code",
134
+ {
135
+ className: utils.cn(
136
+ codeSnippetVariants({ variant, theme, size }),
137
+ "font-mono",
138
+ className
139
+ ),
140
+ dangerouslySetInnerHTML: { __html: highlightedCode }
141
+ }
142
+ ), "renderInline");
143
+ const renderBlock = /* @__PURE__ */ __name(() => /* @__PURE__ */ jsxRuntime.jsxs(
144
+ "div",
145
+ {
146
+ ref,
147
+ className: utils.cn(
148
+ codeSnippetVariants({ variant, theme, size }),
149
+ "overflow-hidden",
150
+ className
151
+ ),
152
+ ...props,
153
+ children: [
154
+ showHeader && (filename || language || showCopyButton || expandable) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b px-4 py-2 bg-muted/30", children: [
155
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
156
+ filename && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
157
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "h-3.5 w-3.5 text-muted-foreground" }),
158
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: filename })
159
+ ] }),
160
+ showLanguageBadge && language && /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "secondary", className: "text-xs", children: language })
161
+ ] }),
162
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
163
+ expandable && /* @__PURE__ */ jsxRuntime.jsxs(
164
+ button.Button,
165
+ {
166
+ variant: "ghost",
167
+ size: "sm",
168
+ onClick: () => setIsExpanded(!isExpanded),
169
+ className: "h-8 w-8 p-0",
170
+ children: [
171
+ isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minimize2, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "h-3.5 w-3.5" }),
172
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: isExpanded ? "Collapse" : "Expand" })
173
+ ]
174
+ }
175
+ ),
176
+ showCopyButton && /* @__PURE__ */ jsxRuntime.jsxs(
177
+ button.Button,
178
+ {
179
+ variant: "ghost",
180
+ size: "sm",
181
+ onClick: copyToClipboard,
182
+ className: "h-8 w-8 p-0 opacity-0 group-hover:opacity-100 transition-opacity",
183
+ children: [
184
+ copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5 text-green-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" }),
185
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: copied ? "Copied" : "Copy code" })
186
+ ]
187
+ }
188
+ )
189
+ ] })
190
+ ] }),
191
+ /* @__PURE__ */ jsxRuntime.jsx(
192
+ "div",
193
+ {
194
+ className: utils.cn("overflow-auto", !wrapLines && "overflow-x-auto"),
195
+ style: {
196
+ maxHeight: isExpanded ? maxHeight : collapsedHeight
197
+ },
198
+ children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 space-y-2", children: Array.from({ length: Math.min(lines.length || 5, 10) }).map(
199
+ (_, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
200
+ showLineNumbers && /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-8" }),
201
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 flex-1" })
202
+ ] }, i)
203
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-mono", children: lines.map((line, index) => {
204
+ const lineNumber = index + startLineNumber;
205
+ const isHighlighted = highlightLines.includes(lineNumber);
206
+ return /* @__PURE__ */ jsxRuntime.jsxs(
207
+ "div",
208
+ {
209
+ className: utils.cn(
210
+ "group relative flex min-h-[1.5rem] items-center px-4 py-0.5",
211
+ isHighlighted && "bg-blue-500/10 border-l-2 border-l-blue-500",
212
+ !wrapLines && "whitespace-nowrap"
213
+ ),
214
+ children: [
215
+ showLineNumbers && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-4 inline-block w-8 select-none text-right text-xs text-muted-foreground", children: lineNumber }),
216
+ /* @__PURE__ */ jsxRuntime.jsx(
217
+ "div",
218
+ {
219
+ className: utils.cn(
220
+ "flex-1",
221
+ wrapLines ? "whitespace-pre-wrap break-words" : "overflow-x-auto"
222
+ ),
223
+ dangerouslySetInnerHTML: { __html: line }
224
+ }
225
+ )
226
+ ]
227
+ },
228
+ index
229
+ );
230
+ }) })
231
+ }
232
+ ),
233
+ expandable && !isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-8 bg-gradient-to-t from-background to-transparent pointer-events-none" }),
234
+ variant === "minimal" && showCopyButton && /* @__PURE__ */ jsxRuntime.jsx(
235
+ button.Button,
236
+ {
237
+ variant: "ghost",
238
+ size: "sm",
239
+ onClick: copyToClipboard,
240
+ className: "absolute top-2 right-2 h-8 w-8 p-0 opacity-0 group-hover:opacity-100 transition-opacity",
241
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5 text-green-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" })
242
+ }
243
+ )
244
+ ]
245
+ }
246
+ ), "renderBlock");
247
+ if (variant === "inline") {
248
+ return renderInline();
249
+ }
250
+ return renderBlock();
251
+ }
252
+ );
253
+ CodeSnippet.displayName = "CodeSnippet";
254
+ var InlineCode = React__namespace.forwardRef(({ children, language, className, ...props }, ref) => {
255
+ return /* @__PURE__ */ jsxRuntime.jsx(
256
+ CodeSnippet,
257
+ {
258
+ ref,
259
+ code: children,
260
+ language,
261
+ variant: "inline",
262
+ showCopyButton: false,
263
+ showLanguageBadge: false,
264
+ showHeader: false,
265
+ className,
266
+ ...props
267
+ }
268
+ );
269
+ });
270
+ InlineCode.displayName = "InlineCode";
271
+
272
+ exports.CodeSnippet = CodeSnippet;
273
+ exports.InlineCode = InlineCode;
274
+ exports.codeSnippetVariants = codeSnippetVariants;