@tscircuit/runframe 0.0.274 → 0.0.276

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runner.js CHANGED
@@ -9,9 +9,12 @@ import {
9
9
  DropdownMenuSubContent,
10
10
  DropdownMenuSubTrigger,
11
11
  DropdownMenuTrigger,
12
+ Tabs,
13
+ TabsList,
14
+ TabsTrigger,
12
15
  buttonVariants,
13
16
  cn
14
- } from "./chunk-XJXAIAEQ.js";
17
+ } from "./chunk-TPHHXIJB.js";
15
18
 
16
19
  // lib/components/RunFrame/RunFrame.tsx
17
20
  import { createCircuitWebWorker } from "@tscircuit/eval/worker";
@@ -745,7 +748,7 @@ function useLocalStorageState(key, initialValue) {
745
748
  }
746
749
 
747
750
  // lib/components/RunFrameForCli/LeftHeader.tsx
748
- import { useEffect as useEffect6, useMemo as useMemo4, useState as useState6 } from "react";
751
+ import { useEffect as useEffect7, useMemo as useMemo4, useState as useState7 } from "react";
749
752
 
750
753
  // lib/components/RunFrameForCli/SelectSnippetDialog.tsx
751
754
  import { useState as useState5 } from "react";
@@ -984,8 +987,334 @@ var Checkbox = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__
984
987
  ));
985
988
  Checkbox.displayName = CheckboxPrimitive.Root.displayName;
986
989
 
990
+ // lib/components/ImportComponentDialog/ImportComponentDialog.tsx
991
+ import "react";
992
+ import { useState as useState6, useEffect as useEffect6 } from "react";
993
+ import { Loader2 as Loader22, Search, ExternalLink } from "lucide-react";
994
+
995
+ // lib/components/ui/input.tsx
996
+ import * as React3 from "react";
997
+ import { jsx as jsx6 } from "react/jsx-runtime";
998
+ var Input = React3.forwardRef(
999
+ ({ className, type, ...props }, ref) => {
1000
+ return /* @__PURE__ */ jsx6(
1001
+ "input",
1002
+ {
1003
+ type,
1004
+ className: cn(
1005
+ "rf-flex rf-h-9 rf-w-full rf-rounded-md rf-border rf-border-zinc-200 rf-bg-white rf-px-3 rf-py-1 rf-text-sm rf-shadow-sm rf-transition-colors file:rf-border-0 file:rf-bg-transparent file:rf-text-sm file:rf-font-medium placeholder:rf-text-zinc-500 focus-visible:rf-outline-none focus-visible:rf-ring-1 focus-visible:rf-ring-zinc-950 disabled:rf-cursor-not-allowed disabled:rf-opacity-50 dark:rf-border-zinc-800 dark:rf-bg-zinc-950 dark:rf-placeholder-zinc-400 dark:focus-visible:rf-ring-zinc-300",
1006
+ className
1007
+ ),
1008
+ ref,
1009
+ ...props
1010
+ }
1011
+ );
1012
+ }
1013
+ );
1014
+ Input.displayName = "Input";
1015
+
1016
+ // lib/components/ImportComponentDialog/jlc-api.ts
1017
+ var searchJLCComponents = async (query, limit = 10) => {
1018
+ try {
1019
+ const encodedQuery = encodeURIComponent(query);
1020
+ const response = await fetch(
1021
+ `https://jlcsearch.tscircuit.com/api/search?limit=${limit}&q=${encodedQuery}`
1022
+ );
1023
+ if (!response.ok) {
1024
+ throw new Error(
1025
+ `JLC API error: ${response.status} ${response.statusText}`
1026
+ );
1027
+ }
1028
+ const data = await response.json();
1029
+ return data.components || [];
1030
+ } catch (error) {
1031
+ console.error("Error searching JLC components:", error);
1032
+ throw error;
1033
+ }
1034
+ };
1035
+ var mapJLCComponentToSearchResult = (jlcComponent) => {
1036
+ return {
1037
+ id: `jlc-${jlcComponent.lcsc}`,
1038
+ name: jlcComponent.mfr,
1039
+ description: jlcComponent.description,
1040
+ source: "jlcpcb",
1041
+ partNumber: `C${jlcComponent.lcsc}`,
1042
+ package: jlcComponent.package,
1043
+ price: jlcComponent.price
1044
+ };
1045
+ };
1046
+
1047
+ // lib/components/ImportComponentDialog/tscircuit-registry-api.ts
1048
+ var searchTscircuitComponents = async (query, limit = 10) => {
1049
+ try {
1050
+ const encodedQuery = encodeURIComponent(query);
1051
+ const response = await fetch(
1052
+ `https://registry-api.tscircuit.com/snippets/search?q=${encodedQuery}&limit=${limit}`
1053
+ );
1054
+ if (!response.ok) {
1055
+ throw new Error(
1056
+ `tscircuit Registry API error: ${response.status} ${response.statusText}`
1057
+ );
1058
+ }
1059
+ const data = await response.json();
1060
+ return data.snippets || [];
1061
+ } catch (error) {
1062
+ console.error("Error searching tscircuit components:", error);
1063
+ throw error;
1064
+ }
1065
+ };
1066
+ var mapTscircuitSnippetToSearchResult = (tscircuitSnippet) => {
1067
+ return {
1068
+ id: `tscircuit-${tscircuitSnippet.snippet_id}`,
1069
+ name: tscircuitSnippet.unscoped_name,
1070
+ description: tscircuitSnippet.description || `Component by ${tscircuitSnippet.owner_name}`,
1071
+ source: "tscircuit",
1072
+ partNumber: tscircuitSnippet.name,
1073
+ previewUrl: tscircuitSnippet.preview_url,
1074
+ // Additional tscircuit-specific properties
1075
+ code: tscircuitSnippet.code,
1076
+ owner: tscircuitSnippet.owner_name
1077
+ };
1078
+ };
1079
+
1080
+ // lib/components/ImportComponentDialog/ImportComponentDialog.tsx
1081
+ import { createSvgUrl as createPngUrl } from "@tscircuit/create-snippet-url";
1082
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1083
+ var ImportComponentDialog = ({
1084
+ isOpen,
1085
+ onClose,
1086
+ onImport
1087
+ }) => {
1088
+ const [searchQuery, setSearchQuery] = useState6("");
1089
+ const [searchResults, setSearchResults] = useState6(
1090
+ []
1091
+ );
1092
+ const [hasSearched, setHasSearched] = useState6(false);
1093
+ const [isLoading, setIsLoading] = useState6(false);
1094
+ const [selectedComponent, setSelectedComponent] = useState6(null);
1095
+ const [activeTab, setActiveTab] = useState6(
1096
+ "tscircuit"
1097
+ );
1098
+ const [detailsOpen, setDetailsOpen] = useState6(false);
1099
+ const [detailsComponent, setDetailsComponent] = useState6(null);
1100
+ const handleSearch = async () => {
1101
+ if (!searchQuery.trim()) return;
1102
+ setIsLoading(true);
1103
+ const isJlcPartNumber = /^C\d+/.test(searchQuery);
1104
+ if (isJlcPartNumber) {
1105
+ setActiveTab("jlcpcb");
1106
+ }
1107
+ try {
1108
+ if (activeTab === "jlcpcb") {
1109
+ const query = isJlcPartNumber ? searchQuery.substring(1) : searchQuery;
1110
+ const jlcComponents = await searchJLCComponents(query, 10);
1111
+ const mappedResults = jlcComponents.map(mapJLCComponentToSearchResult);
1112
+ setSearchResults(mappedResults);
1113
+ } else {
1114
+ const tscircuitComponents = await searchTscircuitComponents(
1115
+ searchQuery,
1116
+ 10
1117
+ );
1118
+ const mappedResults = tscircuitComponents.map(
1119
+ mapTscircuitSnippetToSearchResult
1120
+ );
1121
+ setSearchResults(mappedResults);
1122
+ }
1123
+ } catch (error) {
1124
+ console.error("Error searching components:", error);
1125
+ setSearchResults([]);
1126
+ } finally {
1127
+ setIsLoading(false);
1128
+ setHasSearched(true);
1129
+ }
1130
+ };
1131
+ const handleKeyDown = (e) => {
1132
+ if (e.key === "Enter") {
1133
+ handleSearch();
1134
+ }
1135
+ };
1136
+ useEffect6(() => {
1137
+ setSearchResults([]);
1138
+ setSelectedComponent(null);
1139
+ }, [activeTab]);
1140
+ const showDetails = (component) => {
1141
+ setDetailsComponent(component);
1142
+ setDetailsOpen(true);
1143
+ };
1144
+ return /* @__PURE__ */ jsxs5(AlertDialog, { open: isOpen, onOpenChange: () => onClose(), children: [
1145
+ /* @__PURE__ */ jsxs5(AlertDialogContent, { className: "rf-max-w-3xl rf-w-full rf-max-h-[90vh] rf-overflow-y-auto rf-flex rf-flex-col", children: [
1146
+ /* @__PURE__ */ jsxs5(AlertDialogHeader, { children: [
1147
+ /* @__PURE__ */ jsx7(AlertDialogTitle, { children: "Import Component" }),
1148
+ /* @__PURE__ */ jsx7(AlertDialogDescription, { children: "Search for components from tscircuit.com or JLCPCB parts library." })
1149
+ ] }),
1150
+ /* @__PURE__ */ jsxs5(
1151
+ Tabs,
1152
+ {
1153
+ value: activeTab,
1154
+ onValueChange: (value) => setActiveTab(value),
1155
+ children: [
1156
+ /* @__PURE__ */ jsxs5(TabsList, { className: "rf-grid rf-w-full rf-grid-cols-2", children: [
1157
+ /* @__PURE__ */ jsx7(TabsTrigger, { value: "tscircuit", children: "tscircuit.com" }),
1158
+ /* @__PURE__ */ jsx7(TabsTrigger, { value: "jlcpcb", children: "JLCPCB Parts" })
1159
+ ] }),
1160
+ /* @__PURE__ */ jsxs5("div", { className: "rf-flex rf-items-center rf-gap-2 rf-mt-4", children: [
1161
+ /* @__PURE__ */ jsxs5("div", { className: "rf-relative rf-flex-grow", children: [
1162
+ /* @__PURE__ */ jsx7(Search, { className: "rf-absolute rf-left-2 rf-top-2.5 rf-h-4 rf-w-4 rf-text-muted-foreground" }),
1163
+ /* @__PURE__ */ jsx7(
1164
+ Input,
1165
+ {
1166
+ placeholder: activeTab === "tscircuit" ? "Search components..." : "Search JLCPCB parts (e.g. C14663)...",
1167
+ className: "rf-pl-8",
1168
+ value: searchQuery,
1169
+ onChange: (e) => setSearchQuery(e.target.value),
1170
+ onKeyDown: handleKeyDown
1171
+ }
1172
+ )
1173
+ ] }),
1174
+ /* @__PURE__ */ jsx7(Button, { onClick: handleSearch, disabled: isLoading, children: isLoading ? /* @__PURE__ */ jsx7(Loader22, { className: "rf-h-4 rf-w-4 rf-animate-spin" }) : "Search" })
1175
+ ] }),
1176
+ /* @__PURE__ */ jsx7("div", { className: "rf-mt-4 rf-flex-1 rf-min-h-[200px] !rf-max-h-[40vh] !rf-overflow-y-auto rf-border rf-rounded-md", children: searchResults.length > 0 ? /* @__PURE__ */ jsx7("div", { className: "rf-divide-y", children: searchResults.map((result) => /* @__PURE__ */ jsxs5(
1177
+ "div",
1178
+ {
1179
+ className: `rf-p-3 rf-flex rf-items-center rf-justify-between rf-cursor-pointer hover:rf-bg-zinc-100 ${selectedComponent?.id === result.id ? "rf-bg-zinc-100" : ""}`,
1180
+ onClick: () => setSelectedComponent(result),
1181
+ children: [
1182
+ /* @__PURE__ */ jsxs5("div", { children: [
1183
+ /* @__PURE__ */ jsx7("div", { className: "rf-font-medium", children: result.name }),
1184
+ /* @__PURE__ */ jsxs5("div", { className: "rf-text-sm rf-text-zinc-500", children: [
1185
+ result.partNumber && /* @__PURE__ */ jsx7("span", { className: "rf-mr-2", children: result.partNumber }),
1186
+ result.description
1187
+ ] })
1188
+ ] }),
1189
+ /* @__PURE__ */ jsx7("div", { className: "rf-flex rf-gap-2", children: result.source === "tscircuit" && /* @__PURE__ */ jsx7(
1190
+ Button,
1191
+ {
1192
+ variant: "outline",
1193
+ size: "sm",
1194
+ onClick: (e) => {
1195
+ e.stopPropagation();
1196
+ showDetails(result);
1197
+ },
1198
+ children: "See Details"
1199
+ }
1200
+ ) })
1201
+ ]
1202
+ },
1203
+ result.id
1204
+ )) }) : isLoading ? /* @__PURE__ */ jsxs5("div", { className: "rf-p-8 rf-text-center rf-text-zinc-500", children: [
1205
+ /* @__PURE__ */ jsx7(Loader22, { className: "rf-h-8 rf-w-8 rf-animate-spin rf-mx-auto rf-mb-2" }),
1206
+ /* @__PURE__ */ jsx7("p", { children: "Searching..." })
1207
+ ] }) : /* @__PURE__ */ jsx7("div", { className: "rf-p-8 rf-text-center rf-text-zinc-500", children: hasSearched ? "No results found" : "Enter a search term to find components" }) })
1208
+ ]
1209
+ }
1210
+ ),
1211
+ /* @__PURE__ */ jsxs5(AlertDialogFooter, { children: [
1212
+ /* @__PURE__ */ jsx7(AlertDialogCancel, { onClick: onClose, children: "Cancel" }),
1213
+ /* @__PURE__ */ jsx7(
1214
+ Button,
1215
+ {
1216
+ onClick: () => {
1217
+ if (selectedComponent) {
1218
+ onImport(selectedComponent);
1219
+ onClose();
1220
+ }
1221
+ },
1222
+ disabled: !selectedComponent,
1223
+ children: "Import Component"
1224
+ }
1225
+ )
1226
+ ] })
1227
+ ] }),
1228
+ /* @__PURE__ */ jsx7(AlertDialog, { open: detailsOpen, onOpenChange: setDetailsOpen, children: /* @__PURE__ */ jsxs5(AlertDialogContent, { className: "!rf-max-h-[70%] !rf-overflow-y-auto rf-flex rf-flex-col !rf-max-w-[60vw] !rf-overflow-x-hidden", children: [
1229
+ /* @__PURE__ */ jsxs5(AlertDialogHeader, { children: [
1230
+ /* @__PURE__ */ jsx7(AlertDialogTitle, { children: detailsComponent?.name }),
1231
+ /* @__PURE__ */ jsx7(AlertDialogDescription, { children: "Detailed information about the selected component" }),
1232
+ /* @__PURE__ */ jsxs5("div", { className: "rf-text-sm rf-text-muted-foreground", children: [
1233
+ detailsComponent?.partNumber && /* @__PURE__ */ jsx7("div", { className: "rf-font-mono rf-text-sm rf-mb-2", children: detailsComponent.partNumber }),
1234
+ detailsComponent?.description
1235
+ ] })
1236
+ ] }),
1237
+ detailsComponent?.source === "jlcpcb" && /* @__PURE__ */ jsxs5("div", { className: "rf-my-4 rf-border rf-rounded-md rf-p-4", children: [
1238
+ /* @__PURE__ */ jsx7("div", { className: "rf-text-sm rf-font-medium rf-mb-2", children: "JLCPCB Details" }),
1239
+ /* @__PURE__ */ jsxs5("div", { className: "rf-grid rf-grid-cols-2 rf-gap-2", children: [
1240
+ detailsComponent.package && /* @__PURE__ */ jsxs5("div", { className: "rf-flex rf-flex-col", children: [
1241
+ /* @__PURE__ */ jsx7("span", { className: "rf-text-xs rf-text-zinc-500", children: "Package" }),
1242
+ /* @__PURE__ */ jsx7("span", { className: "rf-font-medium", children: detailsComponent.package })
1243
+ ] }),
1244
+ detailsComponent.price !== void 0 && /* @__PURE__ */ jsxs5("div", { className: "rf-flex rf-flex-col", children: [
1245
+ /* @__PURE__ */ jsx7("span", { className: "rf-text-xs rf-text-zinc-500", children: "Price" }),
1246
+ /* @__PURE__ */ jsxs5("span", { className: "rf-font-medium", children: [
1247
+ "$",
1248
+ detailsComponent.price.toFixed(4)
1249
+ ] })
1250
+ ] })
1251
+ ] })
1252
+ ] }),
1253
+ detailsComponent?.source === "tscircuit" && /* @__PURE__ */ jsxs5("div", { className: "rf-my-4 rf-border rf-rounded-md rf-p-4 !rf-max-w-[60vw] !rf-overflow-x-hidden", children: [
1254
+ /* @__PURE__ */ jsx7("div", { className: "rf-text-sm rf-font-medium rf-mb-2", children: "tscircuit Details" }),
1255
+ /* @__PURE__ */ jsx7("div", { className: "rf-grid rf-grid-cols-2 rf-gap-2", children: detailsComponent.owner && /* @__PURE__ */ jsxs5("div", { className: "rf-flex rf-flex-col", children: [
1256
+ /* @__PURE__ */ jsx7("span", { className: "rf-text-xs rf-text-zinc-500", children: "Owner" }),
1257
+ /* @__PURE__ */ jsx7("span", { className: "rf-font-medium", children: detailsComponent.owner })
1258
+ ] }) }),
1259
+ detailsComponent.code && /* @__PURE__ */ jsxs5("div", { className: "rf-mt-2", children: [
1260
+ /* @__PURE__ */ jsx7("div", { className: "rf-text-xs rf-text-zinc-500 rf-mb-1", children: "Code Preview" }),
1261
+ /* @__PURE__ */ jsxs5("pre", { className: "rf-bg-zinc-50 rf-p-2 rf-rounded rf-text-xs rf-font-mono rf-max-h-32 rf-overflow-y-auto", children: [
1262
+ detailsComponent.code.substring(0, 500),
1263
+ detailsComponent.code.length > 500 && "..."
1264
+ ] })
1265
+ ] })
1266
+ ] }),
1267
+ /* @__PURE__ */ jsxs5("div", { className: "rf-my-4 rf-border rf-rounded-md rf-p-4", children: [
1268
+ /* @__PURE__ */ jsx7("div", { className: "rf-text-sm rf-font-medium rf-mb-2", children: "Preview" }),
1269
+ detailsComponent?.source === "tscircuit" && detailsComponent.code ? /* @__PURE__ */ jsx7("div", { className: "rf-flex rf-justify-center", children: /* @__PURE__ */ jsx7("div", { className: "rf-border rf-rounded rf-p-4 rf-bg-zinc-50", children: /* @__PURE__ */ jsx7(
1270
+ "img",
1271
+ {
1272
+ src: createPngUrl(detailsComponent.code, "pcb"),
1273
+ alt: detailsComponent.name,
1274
+ className: "rf-w-full rf-aspect-video rf-object-contain"
1275
+ }
1276
+ ) }) }) : /* @__PURE__ */ jsx7("div", { className: "rf-text-center rf-text-zinc-500 rf-p-4", children: "No preview available" })
1277
+ ] }),
1278
+ /* @__PURE__ */ jsxs5("div", { className: "rf-flex rf-justify-between", children: [
1279
+ /* @__PURE__ */ jsxs5(
1280
+ Button,
1281
+ {
1282
+ variant: "outline",
1283
+ size: "sm",
1284
+ className: "rf-gap-1",
1285
+ onClick: () => {
1286
+ const url = detailsComponent?.source === "jlcpcb" ? `https://jlcpcb.com/partdetail/${detailsComponent.partNumber}` : `https://tscircuit.com/${detailsComponent.owner}/${detailsComponent?.name.split("/").pop()}`;
1287
+ window.open(url, "_blank");
1288
+ },
1289
+ children: [
1290
+ "View on",
1291
+ " ",
1292
+ detailsComponent?.source === "jlcpcb" ? "JLCPCB" : "tscircuit.com",
1293
+ " ",
1294
+ /* @__PURE__ */ jsx7(ExternalLink, { className: "rf-h-3 rf-w-3" })
1295
+ ]
1296
+ }
1297
+ ),
1298
+ /* @__PURE__ */ jsx7(
1299
+ Button,
1300
+ {
1301
+ onClick: () => {
1302
+ setDetailsOpen(false);
1303
+ if (detailsComponent) {
1304
+ onImport(detailsComponent);
1305
+ onClose();
1306
+ }
1307
+ },
1308
+ children: "Import Component"
1309
+ }
1310
+ )
1311
+ ] })
1312
+ ] }) })
1313
+ ] });
1314
+ };
1315
+
987
1316
  // lib/components/RunFrameForCli/LeftHeader.tsx
988
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1317
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
989
1318
  var availableExports = [
990
1319
  { extension: "json", name: "JSON" },
991
1320
  { extension: "svg", name: "SVG" },
@@ -999,23 +1328,23 @@ var availableExports = [
999
1328
  ];
1000
1329
  var RunframeCliLeftHeader = (props) => {
1001
1330
  const lastRunEvalVersion = useRunnerStore((s) => s.lastRunEvalVersion);
1002
- const [snippetName, setSnippetName] = useState6(null);
1003
- const [hasUnsavedChanges, setHasUnsavedChanges] = useState6(false);
1004
- const [hasNeverBeenSaved, setHasNeverBeenSaved] = useState6(true);
1005
- const [isSaving, setIsSaving] = useState6(false);
1006
- const [requestToSaveSentAt, setRequestToSaveSentAt] = useState6(
1331
+ const [snippetName, setSnippetName] = useState7(null);
1332
+ const [hasUnsavedChanges, setHasUnsavedChanges] = useState7(false);
1333
+ const [hasNeverBeenSaved, setHasNeverBeenSaved] = useState7(true);
1334
+ const [isSaving, setIsSaving] = useState7(false);
1335
+ const [requestToSaveSentAt, setRequestToSaveSentAt] = useState7(
1007
1336
  null
1008
1337
  );
1009
- const [availableSnippets, setAvailableSnippets] = useState6(
1338
+ const [availableSnippets, setAvailableSnippets] = useState7(
1010
1339
  null
1011
1340
  );
1012
- const [isSelectSnippetDialogOpen, setIsSelectSnippetDialogOpen] = useState6(false);
1013
- const [notificationMessage, setNotificationMessage] = useState6(
1341
+ const [isSelectSnippetDialogOpen, setIsSelectSnippetDialogOpen] = useState7(false);
1342
+ const [notificationMessage, setNotificationMessage] = useState7(
1014
1343
  null
1015
1344
  );
1016
- const [errorMessage, setErrorMessage] = useState6(null);
1017
- const [isError, setIsError] = useState6(false);
1018
- const [isExporting, setisExporting] = useState6(false);
1345
+ const [errorMessage, setErrorMessage] = useState7(null);
1346
+ const [isError, setIsError] = useState7(false);
1347
+ const [isExporting, setisExporting] = useState7(false);
1019
1348
  const pushEvent = useRunFrameStore((state) => state.pushEvent);
1020
1349
  const recentEvents = useRunFrameStore((state) => state.recentEvents);
1021
1350
  const firstRenderTime = useMemo4(() => Date.now(), []);
@@ -1043,7 +1372,7 @@ var RunframeCliLeftHeader = (props) => {
1043
1372
  setisExporting(false);
1044
1373
  }
1045
1374
  });
1046
- useEffect6(() => {
1375
+ useEffect7(() => {
1047
1376
  if (!isSaving || requestToSaveSentAt === null) return;
1048
1377
  const eventsSinceRequestToSave = recentEvents.filter(
1049
1378
  (event) => new Date(event.created_at).valueOf() > requestToSaveSentAt
@@ -1084,144 +1413,180 @@ var RunframeCliLeftHeader = (props) => {
1084
1413
  snippet_name: snippetName
1085
1414
  });
1086
1415
  };
1087
- return /* @__PURE__ */ jsxs5(DropdownMenu, { children: [
1088
- /* @__PURE__ */ jsx6(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx6("div", { className: "rf-whitespace-nowrap rf-text-xs font-medium rf-p-2 rf-mx-1 rf-cursor-pointer rf-relative", children: "File" }) }),
1089
- /* @__PURE__ */ jsxs5(DropdownMenuContent, { children: [
1090
- /* @__PURE__ */ jsx6(
1091
- DropdownMenuItem,
1092
- {
1093
- className: "rf-text-xs",
1094
- onSelect: triggerSaveSnippet,
1095
- disabled: isSaving,
1096
- children: isSaving ? "Saving..." : "Push"
1097
- }
1098
- ),
1099
- /* @__PURE__ */ jsxs5(DropdownMenuSub, { children: [
1100
- /* @__PURE__ */ jsx6(DropdownMenuSubTrigger, { className: "rf-text-xs", disabled: isExporting, children: isExporting ? "Exporting..." : "Export" }),
1101
- /* @__PURE__ */ jsx6(DropdownMenuPortal, { children: /* @__PURE__ */ jsx6(DropdownMenuSubContent, { children: availableExports.map((exp, i) => /* @__PURE__ */ jsx6(
1416
+ const [isImportDialogOpen, setIsImportDialogOpen] = useState7(false);
1417
+ return /* @__PURE__ */ jsxs6(Fragment2, { children: [
1418
+ /* @__PURE__ */ jsxs6(DropdownMenu, { children: [
1419
+ /* @__PURE__ */ jsx8(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx8("div", { className: "rf-whitespace-nowrap rf-text-xs font-medium rf-p-2 rf-mx-1 rf-cursor-pointer rf-relative", children: "File" }) }),
1420
+ /* @__PURE__ */ jsxs6(DropdownMenuContent, { children: [
1421
+ /* @__PURE__ */ jsx8(
1102
1422
  DropdownMenuItem,
1103
1423
  {
1104
- onSelect: () => {
1105
- if (!isExporting) {
1106
- pushEvent({
1107
- event_type: "REQUEST_EXPORT",
1108
- exportType: exp.extension
1109
- });
1110
- setNotificationMessage(`Export requested for ${exp.name}`);
1111
- setIsError(false);
1112
- }
1424
+ className: "rf-text-xs",
1425
+ onSelect: triggerSaveSnippet,
1426
+ disabled: isSaving,
1427
+ children: isSaving ? "Saving..." : "Push"
1428
+ }
1429
+ ),
1430
+ /* @__PURE__ */ jsx8(
1431
+ DropdownMenuItem,
1432
+ {
1433
+ className: "rf-text-xs",
1434
+ onSelect: () => setIsImportDialogOpen(true),
1435
+ disabled: isSaving,
1436
+ children: "Import"
1437
+ }
1438
+ ),
1439
+ /* @__PURE__ */ jsxs6(DropdownMenuSub, { children: [
1440
+ /* @__PURE__ */ jsx8(
1441
+ DropdownMenuSubTrigger,
1442
+ {
1443
+ className: "rf-text-xs",
1444
+ disabled: isExporting,
1445
+ children: isExporting ? "Exporting..." : "Export"
1446
+ }
1447
+ ),
1448
+ /* @__PURE__ */ jsx8(DropdownMenuPortal, { children: /* @__PURE__ */ jsx8(DropdownMenuSubContent, { children: availableExports.map((exp, i) => /* @__PURE__ */ jsx8(
1449
+ DropdownMenuItem,
1450
+ {
1451
+ onSelect: () => {
1452
+ if (!isExporting) {
1453
+ pushEvent({
1454
+ event_type: "REQUEST_EXPORT",
1455
+ exportType: exp.extension
1456
+ });
1457
+ setNotificationMessage(
1458
+ `Export requested for ${exp.name}`
1459
+ );
1460
+ setIsError(false);
1461
+ }
1462
+ },
1463
+ disabled: isExporting,
1464
+ children: /* @__PURE__ */ jsx8("span", { className: "rf-text-xs", children: exp.name })
1113
1465
  },
1114
- disabled: isExporting,
1115
- children: /* @__PURE__ */ jsx6("span", { className: "rf-text-xs", children: exp.name })
1116
- },
1117
- i
1118
- )) }) })
1119
- ] }),
1120
- /* @__PURE__ */ jsxs5(DropdownMenuSub, { children: [
1121
- /* @__PURE__ */ jsx6(DropdownMenuSubTrigger, { className: "rf-text-xs", children: "Advanced" }),
1122
- /* @__PURE__ */ jsx6(DropdownMenuPortal, { children: /* @__PURE__ */ jsxs5(DropdownMenuSubContent, { children: [
1123
- /* @__PURE__ */ jsx6(DropdownMenuItem, { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsxs5("div", { className: "rf-flex rf-items-center rf-gap-2", children: [
1124
- /* @__PURE__ */ jsx6(
1125
- Checkbox,
1126
- {
1127
- id: "load-latest-eval",
1128
- checked: props.shouldLoadLatestEval,
1129
- onCheckedChange: (checked) => {
1130
- props.onChangeShouldLoadLatestEval(checked === true);
1466
+ i
1467
+ )) }) })
1468
+ ] }),
1469
+ /* @__PURE__ */ jsxs6(DropdownMenuSub, { children: [
1470
+ /* @__PURE__ */ jsx8(DropdownMenuSubTrigger, { className: "rf-text-xs", children: "Advanced" }),
1471
+ /* @__PURE__ */ jsx8(DropdownMenuPortal, { children: /* @__PURE__ */ jsxs6(DropdownMenuSubContent, { children: [
1472
+ /* @__PURE__ */ jsx8(DropdownMenuItem, { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsxs6("div", { className: "rf-flex rf-items-center rf-gap-2", children: [
1473
+ /* @__PURE__ */ jsx8(
1474
+ Checkbox,
1475
+ {
1476
+ id: "load-latest-eval",
1477
+ checked: props.shouldLoadLatestEval,
1478
+ onCheckedChange: (checked) => {
1479
+ props.onChangeShouldLoadLatestEval(checked === true);
1480
+ }
1131
1481
  }
1132
- }
1133
- ),
1134
- /* @__PURE__ */ jsx6(
1135
- "label",
1482
+ ),
1483
+ /* @__PURE__ */ jsx8(
1484
+ "label",
1485
+ {
1486
+ htmlFor: "load-latest-eval",
1487
+ className: "rf-text-xs rf-cursor-pointer",
1488
+ children: "Force Latest @tscircuit/eval"
1489
+ }
1490
+ )
1491
+ ] }) }),
1492
+ lastRunEvalVersion && /* @__PURE__ */ jsx8(DropdownMenuItem, { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsx8("div", { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsxs6("span", { className: "rf-text-xs", children: [
1493
+ "@tscircuit/eval@",
1494
+ lastRunEvalVersion
1495
+ ] }) }) }),
1496
+ /* @__PURE__ */ jsx8(
1497
+ DropdownMenuItem,
1136
1498
  {
1137
- htmlFor: "load-latest-eval",
1138
- className: "rf-text-xs rf-cursor-pointer",
1139
- children: "Force Latest @tscircuit/eval"
1499
+ className: "rf-flex rf-items-center rf-gap-2",
1500
+ onClick: () => {
1501
+ window.open("/api/admin", "_blank");
1502
+ },
1503
+ children: /* @__PURE__ */ jsx8("div", { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsx8("span", { className: "rf-text-xs", children: "CLI Admin Panel" }) })
1140
1504
  }
1141
1505
  )
1142
- ] }) }),
1143
- lastRunEvalVersion && /* @__PURE__ */ jsx6(DropdownMenuItem, { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsx6("div", { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsxs5("span", { className: "rf-text-xs", children: [
1144
- "@tscircuit/eval@",
1145
- lastRunEvalVersion
1146
- ] }) }) }),
1147
- /* @__PURE__ */ jsx6(
1148
- DropdownMenuItem,
1149
- {
1150
- className: "rf-flex rf-items-center rf-gap-2",
1151
- onClick: () => {
1152
- window.open("/api/admin", "_blank");
1153
- },
1154
- children: /* @__PURE__ */ jsx6("div", { className: "rf-flex rf-items-center rf-gap-2", children: /* @__PURE__ */ jsx6("span", { className: "rf-text-xs", children: "CLI Admin Panel" }) })
1155
- }
1156
- )
1157
- ] }) })
1158
- ] })
1159
- ] }),
1160
- /* @__PURE__ */ jsx6("div", { className: "!rf-h-full rf-w-fit rf-grid rf-place-items-center rf-my-auto", children: /* @__PURE__ */ jsxs5("div", { className: "rf-flex rf-gap-4", children: [
1161
- hasUnsavedChanges || hasNeverBeenSaved && /* @__PURE__ */ jsx6(
1162
- "button",
1163
- {
1164
- type: "button",
1165
- disabled: isSaving,
1166
- onClick: triggerSaveSnippet,
1167
- className: "transition ease-in-out hover:scale-105 pointer-cursor rf-text-xs rf-h-fit disabled:rf-bg-blue-600/60 rf-bg-blue-600/70 rf-text-white rf-p-0.5 rf-px-1.5 rf-rounded",
1168
- children: isSaving ? "Syncing..." : "Not Synced"
1169
- }
1170
- ),
1171
- notificationMessage && /* @__PURE__ */ jsx6(
1172
- "div",
1506
+ ] }) })
1507
+ ] })
1508
+ ] }),
1509
+ /* @__PURE__ */ jsx8("div", { className: "!rf-h-full rf-w-fit rf-grid rf-place-items-center rf-my-auto", children: /* @__PURE__ */ jsxs6("div", { className: "rf-flex rf-gap-4", children: [
1510
+ hasUnsavedChanges || hasNeverBeenSaved && /* @__PURE__ */ jsx8(
1511
+ "button",
1512
+ {
1513
+ type: "button",
1514
+ disabled: isSaving,
1515
+ onClick: triggerSaveSnippet,
1516
+ className: "transition ease-in-out hover:scale-105 pointer-cursor rf-text-xs rf-h-fit disabled:rf-bg-blue-600/60 rf-bg-blue-600/70 rf-text-white rf-p-0.5 rf-px-1.5 rf-rounded",
1517
+ children: isSaving ? "Syncing..." : "Not Synced"
1518
+ }
1519
+ ),
1520
+ notificationMessage && /* @__PURE__ */ jsx8(
1521
+ "div",
1522
+ {
1523
+ className: `rf-text-xs rf-font-medium rf-mt-1 rf-flex rf-max-w-xl rf-text-blue-500 rf-break-words rf-text-center rf-h-full`,
1524
+ children: /* @__PURE__ */ jsxs6("div", { className: "rf-flex rf-items-center", children: [
1525
+ /* @__PURE__ */ jsx8(CheckCircle, { className: "rf-w-4 rf-h-4 rf-inline rf-mr-1" }),
1526
+ notificationMessage
1527
+ ] })
1528
+ }
1529
+ )
1530
+ ] }) }),
1531
+ /* @__PURE__ */ jsx8(AlertDialog, { open: isError, onOpenChange: setIsError, children: /* @__PURE__ */ jsxs6(AlertDialogContent, { children: [
1532
+ /* @__PURE__ */ jsxs6(AlertDialogHeader, { children: [
1533
+ /* @__PURE__ */ jsx8(AlertDialogTitle, { children: "Error Saving Snippet" }),
1534
+ /* @__PURE__ */ jsx8(AlertDialogDescription, { children: errorMessage })
1535
+ ] }),
1536
+ /* @__PURE__ */ jsx8(AlertDialogFooter, { children: /* @__PURE__ */ jsx8(AlertDialogCancel, { onClick: () => setIsError(false), children: "Dismiss" }) })
1537
+ ] }) }),
1538
+ /* @__PURE__ */ jsx8(
1539
+ SelectSnippetDialog,
1173
1540
  {
1174
- className: `rf-text-xs rf-font-medium rf-mt-1 rf-flex rf-max-w-xl rf-text-blue-500 rf-break-words rf-text-center rf-h-full`,
1175
- children: /* @__PURE__ */ jsxs5("div", { className: "rf-flex rf-items-center", children: [
1176
- /* @__PURE__ */ jsx6(CheckCircle, { className: "rf-w-4 rf-h-4 rf-inline rf-mr-1" }),
1177
- notificationMessage
1178
- ] })
1541
+ snippetNames: availableSnippets ?? [],
1542
+ onSelect: async (name) => {
1543
+ setIsSaving(true);
1544
+ setRequestToSaveSentAt(Date.now());
1545
+ setSnippetName(name);
1546
+ await pushEvent({
1547
+ event_type: "REQUEST_TO_SAVE_SNIPPET",
1548
+ snippet_name: name
1549
+ });
1550
+ setIsSelectSnippetDialogOpen(false);
1551
+ },
1552
+ onCancel: () => setIsSelectSnippetDialogOpen(false),
1553
+ isOpen: isSelectSnippetDialogOpen
1179
1554
  }
1180
1555
  )
1181
- ] }) }),
1182
- /* @__PURE__ */ jsx6(AlertDialog, { open: isError, onOpenChange: setIsError, children: /* @__PURE__ */ jsxs5(AlertDialogContent, { children: [
1183
- /* @__PURE__ */ jsxs5(AlertDialogHeader, { children: [
1184
- /* @__PURE__ */ jsx6(AlertDialogTitle, { children: "Error Saving Snippet" }),
1185
- /* @__PURE__ */ jsx6(AlertDialogDescription, { children: errorMessage })
1186
- ] }),
1187
- /* @__PURE__ */ jsx6(AlertDialogFooter, { children: /* @__PURE__ */ jsx6(AlertDialogCancel, { onClick: () => setIsError(false), children: "Dismiss" }) })
1188
- ] }) }),
1189
- /* @__PURE__ */ jsx6(
1190
- SelectSnippetDialog,
1556
+ ] }),
1557
+ /* @__PURE__ */ jsx8(
1558
+ ImportComponentDialog,
1191
1559
  {
1192
- snippetNames: availableSnippets ?? [],
1193
- onSelect: async (name) => {
1194
- setIsSaving(true);
1195
- setRequestToSaveSentAt(Date.now());
1196
- setSnippetName(name);
1560
+ isOpen: isImportDialogOpen,
1561
+ onClose: () => setIsImportDialogOpen(false),
1562
+ onImport: async (component) => {
1563
+ console.log("Component imported:", component);
1564
+ setIsImportDialogOpen(false);
1197
1565
  await pushEvent({
1198
- event_type: "REQUEST_TO_SAVE_SNIPPET",
1199
- snippet_name: name
1566
+ event_type: "IMPORT_COMPONENT",
1567
+ component
1200
1568
  });
1201
- setIsSelectSnippetDialogOpen(false);
1202
- },
1203
- onCancel: () => setIsSelectSnippetDialogOpen(false),
1204
- isOpen: isSelectSnippetDialogOpen
1569
+ }
1205
1570
  }
1206
1571
  )
1207
1572
  ] });
1208
1573
  };
1209
1574
 
1210
1575
  // lib/components/RunFrameForCli/RunFrameForCli.tsx
1211
- import { jsx as jsx7 } from "react/jsx-runtime";
1576
+ import { jsx as jsx9 } from "react/jsx-runtime";
1212
1577
  var RunFrameForCli = (props) => {
1213
1578
  const [shouldLoadLatestEval, setLoadLatestEval] = useLocalStorageState(
1214
1579
  "load-latest-eval",
1215
1580
  true
1216
1581
  );
1217
- return /* @__PURE__ */ jsx7(
1582
+ return /* @__PURE__ */ jsx9(
1218
1583
  RunFrameWithApi,
1219
1584
  {
1220
1585
  debug: props.debug,
1221
1586
  forceLatestEvalVersion: shouldLoadLatestEval,
1222
1587
  defaultToFullScreen: true,
1223
1588
  showToggleFullScreen: false,
1224
- leftHeaderContent: /* @__PURE__ */ jsx7("div", { className: "rf-flex", children: /* @__PURE__ */ jsx7(
1589
+ leftHeaderContent: /* @__PURE__ */ jsx9("div", { className: "rf-flex", children: /* @__PURE__ */ jsx9(
1225
1590
  RunframeCliLeftHeader,
1226
1591
  {
1227
1592
  shouldLoadLatestEval,