@tscircuit/runframe 0.0.5 → 0.0.7
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/bun.lockb +0 -0
- package/dist/chunk-YW33LMDL.js +956 -0
- package/dist/preview.d.ts +30 -0
- package/dist/preview.js +6 -0
- package/dist/runner.d.ts +36 -0
- package/dist/runner.js +40 -0
- package/package.json +6 -3
- package/vite.config.ts +11 -1
package/bun.lockb
CHANGED
|
Binary file
|
|
@@ -0,0 +1,956 @@
|
|
|
1
|
+
// lib/components/ui/tabs.tsx
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
4
|
+
|
|
5
|
+
// lib/utils/index.ts
|
|
6
|
+
import { clsx } from "clsx";
|
|
7
|
+
import { twMerge } from "tailwind-merge";
|
|
8
|
+
function cn(...inputs) {
|
|
9
|
+
return twMerge(clsx(inputs));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// lib/components/ui/tabs.tsx
|
|
13
|
+
import { jsx } from "react/jsx-runtime";
|
|
14
|
+
var Tabs = TabsPrimitive.Root;
|
|
15
|
+
var TabsList = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
16
|
+
TabsPrimitive.List,
|
|
17
|
+
{
|
|
18
|
+
ref,
|
|
19
|
+
className: cn(
|
|
20
|
+
"inline-flex h-9 items-center justify-center rounded-lg bg-slate-100 p-1 text-slate-500 dark:bg-slate-800 dark:text-slate-400",
|
|
21
|
+
className
|
|
22
|
+
),
|
|
23
|
+
...props
|
|
24
|
+
}
|
|
25
|
+
));
|
|
26
|
+
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
27
|
+
var TabsTrigger = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
28
|
+
TabsPrimitive.Trigger,
|
|
29
|
+
{
|
|
30
|
+
ref,
|
|
31
|
+
className: cn(
|
|
32
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-white transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-slate-950 data-[state=active]:shadow dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300 dark:data-[state=active]:bg-slate-950 dark:data-[state=active]:text-slate-50",
|
|
33
|
+
className
|
|
34
|
+
),
|
|
35
|
+
...props
|
|
36
|
+
}
|
|
37
|
+
));
|
|
38
|
+
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
|
39
|
+
var TabsContent = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
40
|
+
TabsPrimitive.Content,
|
|
41
|
+
{
|
|
42
|
+
ref,
|
|
43
|
+
className: cn(
|
|
44
|
+
"mt-2 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300",
|
|
45
|
+
className
|
|
46
|
+
),
|
|
47
|
+
...props
|
|
48
|
+
}
|
|
49
|
+
));
|
|
50
|
+
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
51
|
+
|
|
52
|
+
// lib/utils/pcbManualEditEventHandler.ts
|
|
53
|
+
import { getManualTraceHintFromEvent } from "@tscircuit/layout";
|
|
54
|
+
|
|
55
|
+
// lib/components/CircuitJsonPreview.tsx
|
|
56
|
+
import { CadViewer } from "@tscircuit/3d-viewer";
|
|
57
|
+
import "@tscircuit/pcb-viewer";
|
|
58
|
+
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
59
|
+
|
|
60
|
+
// lib/components/ErrorFallback.tsx
|
|
61
|
+
import "react";
|
|
62
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
63
|
+
var ErrorFallback = ({ error }) => {
|
|
64
|
+
return /* @__PURE__ */ jsx2(
|
|
65
|
+
"div",
|
|
66
|
+
{
|
|
67
|
+
"data-testid": "error-container",
|
|
68
|
+
className: "error-container mt-4 bg-red-50 rounded-md border border-red-200",
|
|
69
|
+
children: /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
|
|
70
|
+
/* @__PURE__ */ jsx2("h2", { className: "text-lg font-semibold text-red-800 mb-3", children: "Error Loading 3D Viewer" }),
|
|
71
|
+
/* @__PURE__ */ jsx2("p", { className: "text-xs font-mono whitespace-pre-wrap text-red-700", children: error.message }),
|
|
72
|
+
/* @__PURE__ */ jsx2(
|
|
73
|
+
"details",
|
|
74
|
+
{
|
|
75
|
+
style: { whiteSpace: "pre-wrap" },
|
|
76
|
+
className: "text-xs font-mono text-red-600 mt-2",
|
|
77
|
+
children: error.stack
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
] })
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// lib/components/CircuitJsonPreview.tsx
|
|
86
|
+
import { ErrorBoundary } from "react-error-boundary";
|
|
87
|
+
|
|
88
|
+
// lib/components/ErrorTabContent.tsx
|
|
89
|
+
import { GitHubLogoIcon } from "@radix-ui/react-icons";
|
|
90
|
+
import { ClipboardIcon } from "lucide-react";
|
|
91
|
+
|
|
92
|
+
// lib/components/ui/button.tsx
|
|
93
|
+
import * as React3 from "react";
|
|
94
|
+
import { cva } from "class-variance-authority";
|
|
95
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
96
|
+
var buttonVariants = cva(
|
|
97
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:pointer-events-none disabled:opacity-50 dark:focus-visible:ring-slate-300",
|
|
98
|
+
{
|
|
99
|
+
variants: {
|
|
100
|
+
variant: {
|
|
101
|
+
default: "bg-slate-900 text-slate-50 shadow hover:bg-slate-900/90 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/90",
|
|
102
|
+
destructive: "bg-red-500 text-slate-50 shadow-sm hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90",
|
|
103
|
+
outline: "border border-slate-200 bg-white shadow-sm hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50",
|
|
104
|
+
secondary: "bg-slate-100 text-slate-900 shadow-sm hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80",
|
|
105
|
+
ghost: "hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50",
|
|
106
|
+
link: "text-slate-900 underline-offset-4 hover:underline dark:text-slate-50"
|
|
107
|
+
},
|
|
108
|
+
size: {
|
|
109
|
+
default: "h-9 px-4 py-2",
|
|
110
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
111
|
+
lg: "h-10 rounded-md px-8",
|
|
112
|
+
icon: "h-9 w-9"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
defaultVariants: {
|
|
116
|
+
variant: "default",
|
|
117
|
+
size: "default"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
var Button = React3.forwardRef(
|
|
122
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
123
|
+
const Comp = "button";
|
|
124
|
+
return /* @__PURE__ */ jsx3(
|
|
125
|
+
Comp,
|
|
126
|
+
{
|
|
127
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
128
|
+
ref,
|
|
129
|
+
...props
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
Button.displayName = "Button";
|
|
135
|
+
|
|
136
|
+
// lib/components/ErrorTabContent.tsx
|
|
137
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
138
|
+
var ErrorTabContent = ({
|
|
139
|
+
code,
|
|
140
|
+
isStreaming,
|
|
141
|
+
errorMessage
|
|
142
|
+
}) => {
|
|
143
|
+
if (!errorMessage) {
|
|
144
|
+
return /* @__PURE__ */ jsx4("div", { className: "mt-4 bg-green-50 rounded-md border border-green-200", children: /* @__PURE__ */ jsxs2("div", { className: "p-4", children: [
|
|
145
|
+
/* @__PURE__ */ jsx4("h3", { className: "text-lg font-semibold text-green-800 mb-3", children: "No Errors \u{1F44C}" }),
|
|
146
|
+
/* @__PURE__ */ jsx4("p", { className: "text-sm text-green-700", children: "Your code is running without any errors." })
|
|
147
|
+
] }) });
|
|
148
|
+
}
|
|
149
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
150
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-4 bg-red-50 rounded-md border border-red-200 max-h-[500px] overflow-y-auto", children: /* @__PURE__ */ jsxs2("div", { className: "p-4", children: [
|
|
151
|
+
/* @__PURE__ */ jsx4("h3", { className: "text-lg font-semibold text-red-800 mb-3", children: "Error" }),
|
|
152
|
+
/* @__PURE__ */ jsx4("p", { className: "text-xs font-mono whitespace-pre-wrap text-red-600 mt-2", children: errorMessage })
|
|
153
|
+
] }) }),
|
|
154
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex gap-2 mt-4 justify-end", children: [
|
|
155
|
+
/* @__PURE__ */ jsxs2(
|
|
156
|
+
Button,
|
|
157
|
+
{
|
|
158
|
+
variant: "outline",
|
|
159
|
+
onClick: () => {
|
|
160
|
+
if (!errorMessage) return;
|
|
161
|
+
navigator.clipboard.writeText(errorMessage);
|
|
162
|
+
alert("Error copied to clipboard!");
|
|
163
|
+
},
|
|
164
|
+
children: [
|
|
165
|
+
/* @__PURE__ */ jsx4(ClipboardIcon, { className: "w-4 h-4 mr-2" }),
|
|
166
|
+
"Copy Error"
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
),
|
|
170
|
+
/* @__PURE__ */ jsxs2(
|
|
171
|
+
Button,
|
|
172
|
+
{
|
|
173
|
+
variant: "outline",
|
|
174
|
+
onClick: () => {
|
|
175
|
+
window.alert(
|
|
176
|
+
"Not supported yet! Please report/upvote an issue on github.com/tscircuit/tscircuit"
|
|
177
|
+
);
|
|
178
|
+
},
|
|
179
|
+
children: [
|
|
180
|
+
/* @__PURE__ */ jsx4(GitHubLogoIcon, { className: "w-4 h-4 mr-2" }),
|
|
181
|
+
"Report Issue"
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
] })
|
|
186
|
+
] });
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// lib/components/CircuitJsonPreview.tsx
|
|
190
|
+
import { SchematicViewer } from "@tscircuit/schematic-viewer";
|
|
191
|
+
|
|
192
|
+
// lib/components/PreviewEmptyState.tsx
|
|
193
|
+
import { PlayIcon } from "lucide-react";
|
|
194
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
195
|
+
var PreviewEmptyState = ({ onRunClicked }) => /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3 bg-gray-100 text-center justify-center py-10", children: [
|
|
196
|
+
"No circuit json loaded",
|
|
197
|
+
/* @__PURE__ */ jsxs3(Button, { className: "bg-blue-600 hover:bg-blue-500", onClick: onRunClicked, children: [
|
|
198
|
+
"Run Code",
|
|
199
|
+
/* @__PURE__ */ jsx5(PlayIcon, { className: "w-3 h-3 ml-2" })
|
|
200
|
+
] })
|
|
201
|
+
] });
|
|
202
|
+
var PreviewEmptyState_default = PreviewEmptyState;
|
|
203
|
+
|
|
204
|
+
// lib/components/CircuitJsonTableViewer/CircuitJsonTableViewer.tsx
|
|
205
|
+
import { useReducer, useState } from "react";
|
|
206
|
+
|
|
207
|
+
// lib/components/CircuitJsonTableViewer/ClickableText.tsx
|
|
208
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
209
|
+
var ClickableText = ({
|
|
210
|
+
text,
|
|
211
|
+
onClick
|
|
212
|
+
}) => {
|
|
213
|
+
return /* @__PURE__ */ jsx6(
|
|
214
|
+
"span",
|
|
215
|
+
{
|
|
216
|
+
className: "cursor-pointer underline text-blue-300 mx-2",
|
|
217
|
+
onClick,
|
|
218
|
+
children: text
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// lib/components/CircuitJsonTableViewer/HeaderCell.tsx
|
|
224
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
225
|
+
var HeaderCell = (p) => {
|
|
226
|
+
return /* @__PURE__ */ jsxs4("div", { className: "leading-5", children: [
|
|
227
|
+
/* @__PURE__ */ jsx7("div", { className: "py-2 font-bold", children: p.column.name }),
|
|
228
|
+
/* @__PURE__ */ jsx7("div", { children: p.field?.() ?? /* @__PURE__ */ jsx7(
|
|
229
|
+
"input",
|
|
230
|
+
{
|
|
231
|
+
type: "text",
|
|
232
|
+
className: "border rounded p-1 w-full",
|
|
233
|
+
onChange: (e) => {
|
|
234
|
+
p.onTextChange?.(e.target.value);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
) })
|
|
238
|
+
] });
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// lib/components/CircuitJsonTableViewer/Modal.tsx
|
|
242
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
243
|
+
var Modal = ({ open, children, title, onClose }) => {
|
|
244
|
+
if (!open) return null;
|
|
245
|
+
return /* @__PURE__ */ jsx8(
|
|
246
|
+
"div",
|
|
247
|
+
{
|
|
248
|
+
className: "fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center z-50",
|
|
249
|
+
onClick: onClose,
|
|
250
|
+
children: /* @__PURE__ */ jsxs5(
|
|
251
|
+
"div",
|
|
252
|
+
{
|
|
253
|
+
className: "bg-white p-5 rounded-lg relative w-11/12 max-w-2xl",
|
|
254
|
+
onClick: (e) => {
|
|
255
|
+
e.preventDefault();
|
|
256
|
+
e.stopPropagation();
|
|
257
|
+
},
|
|
258
|
+
children: [
|
|
259
|
+
/* @__PURE__ */ jsx8("h2", { className: "mt-0 text-xl", children: title }),
|
|
260
|
+
/* @__PURE__ */ jsx8(
|
|
261
|
+
"button",
|
|
262
|
+
{
|
|
263
|
+
className: "absolute top-4 right-4 text-2xl font-bold",
|
|
264
|
+
onClick: onClose,
|
|
265
|
+
children: "\xD7"
|
|
266
|
+
}
|
|
267
|
+
),
|
|
268
|
+
children
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
};
|
|
275
|
+
var Modal_default = Modal;
|
|
276
|
+
|
|
277
|
+
// lib/components/CircuitJsonTableViewer/CircuitJsonTableViewer.tsx
|
|
278
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
279
|
+
var CircuitJsonTableViewer = ({
|
|
280
|
+
elements
|
|
281
|
+
}) => {
|
|
282
|
+
const [modal, setModal] = useState({ open: false });
|
|
283
|
+
const [filters, setFilter] = useReducer(
|
|
284
|
+
(s, a) => ({
|
|
285
|
+
...s,
|
|
286
|
+
...a
|
|
287
|
+
}),
|
|
288
|
+
{}
|
|
289
|
+
);
|
|
290
|
+
const element_types = [...new Set(elements.map((e) => e.type))];
|
|
291
|
+
const elements2 = elements.map((e) => {
|
|
292
|
+
const primary_id = e[`${e.type}_id`];
|
|
293
|
+
const other_ids = Object.fromEntries(
|
|
294
|
+
Object.entries(e).filter(([k]) => {
|
|
295
|
+
if (k === `${e.type}_id`) return false;
|
|
296
|
+
if (!k.endsWith("_id")) return false;
|
|
297
|
+
return true;
|
|
298
|
+
})
|
|
299
|
+
);
|
|
300
|
+
const other_props = Object.fromEntries(
|
|
301
|
+
Object.entries(e).filter(([k]) => !k.endsWith("_id"))
|
|
302
|
+
);
|
|
303
|
+
return {
|
|
304
|
+
primary_id,
|
|
305
|
+
other_ids,
|
|
306
|
+
...other_props,
|
|
307
|
+
_og_elm: e
|
|
308
|
+
};
|
|
309
|
+
});
|
|
310
|
+
const elements3 = elements2.map((e) => {
|
|
311
|
+
let selector_path = "";
|
|
312
|
+
const getSelectorPath = (e2) => {
|
|
313
|
+
const parent_key = Object.keys(e2.other_ids).find(
|
|
314
|
+
(k) => k.startsWith("source_")
|
|
315
|
+
);
|
|
316
|
+
if (!parent_key) return `.${e2.name}`;
|
|
317
|
+
const parent_type = parent_key.slice(0, -3);
|
|
318
|
+
const parent = elements2.find(
|
|
319
|
+
(p) => p.type === parent_type && p.primary_id === e2.other_ids[parent_key]
|
|
320
|
+
);
|
|
321
|
+
if (!parent) return `??? > .${e2.name}`;
|
|
322
|
+
if (!("name" in parent)) return `#${parent.primary_id} > .${e2.name}`;
|
|
323
|
+
return `${getSelectorPath(parent)} > .${e2.name}`;
|
|
324
|
+
};
|
|
325
|
+
if ("name" in e) {
|
|
326
|
+
selector_path = getSelectorPath(e);
|
|
327
|
+
}
|
|
328
|
+
return {
|
|
329
|
+
...e,
|
|
330
|
+
selector_path
|
|
331
|
+
};
|
|
332
|
+
});
|
|
333
|
+
const columns = [
|
|
334
|
+
{
|
|
335
|
+
key: "primary_id",
|
|
336
|
+
name: "primary_id",
|
|
337
|
+
renderCell: (row) => /* @__PURE__ */ jsxs6("div", { className: "flex items-center", children: [
|
|
338
|
+
/* @__PURE__ */ jsx9(
|
|
339
|
+
ClickableText,
|
|
340
|
+
{
|
|
341
|
+
text: row.primary_id,
|
|
342
|
+
onClick: () => setFilter({
|
|
343
|
+
focused_id: row.primary_id,
|
|
344
|
+
id_search: void 0,
|
|
345
|
+
selector_search: void 0
|
|
346
|
+
})
|
|
347
|
+
}
|
|
348
|
+
),
|
|
349
|
+
/* @__PURE__ */ jsx9("span", { className: "flex-grow" }),
|
|
350
|
+
/* @__PURE__ */ jsx9(
|
|
351
|
+
ClickableText,
|
|
352
|
+
{
|
|
353
|
+
text: "(JSON)",
|
|
354
|
+
onClick: () => setModal({
|
|
355
|
+
open: true,
|
|
356
|
+
element: row._og_elm,
|
|
357
|
+
title: row.primary_id
|
|
358
|
+
})
|
|
359
|
+
}
|
|
360
|
+
)
|
|
361
|
+
] }),
|
|
362
|
+
renderHeaderCell: (col) => /* @__PURE__ */ jsx9(
|
|
363
|
+
HeaderCell,
|
|
364
|
+
{
|
|
365
|
+
column: col,
|
|
366
|
+
onTextChange: (v) => setFilter({ id_search: v }),
|
|
367
|
+
field: !filters.focused_id ? void 0 : () => /* @__PURE__ */ jsxs6("div", { children: [
|
|
368
|
+
"Focus:",
|
|
369
|
+
" ",
|
|
370
|
+
/* @__PURE__ */ jsx9("span", { className: "underline", children: filters.focused_id }),
|
|
371
|
+
/* @__PURE__ */ jsx9(
|
|
372
|
+
ClickableText,
|
|
373
|
+
{
|
|
374
|
+
text: "(unfocus)",
|
|
375
|
+
onClick: () => setFilter({ focused_id: void 0 })
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
] })
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
key: "type",
|
|
384
|
+
name: "type",
|
|
385
|
+
renderHeaderCell: (col) => /* @__PURE__ */ jsx9(
|
|
386
|
+
HeaderCell,
|
|
387
|
+
{
|
|
388
|
+
column: col,
|
|
389
|
+
field: () => /* @__PURE__ */ jsxs6(
|
|
390
|
+
"select",
|
|
391
|
+
{
|
|
392
|
+
onChange: (e) => setFilter({ component_type_filter: e.target.value }),
|
|
393
|
+
className: "border rounded p-1 w-full",
|
|
394
|
+
children: [
|
|
395
|
+
/* @__PURE__ */ jsx9("option", { value: "any", children: "any" }, "any"),
|
|
396
|
+
/* @__PURE__ */ jsx9("option", { value: "source", children: "source" }, "source"),
|
|
397
|
+
/* @__PURE__ */ jsx9("option", { value: "source/pcb", children: "source/pcb" }, "source/pcb"),
|
|
398
|
+
/* @__PURE__ */ jsx9("option", { value: "source/schematic", children: "source/schematic" }, "source/schematic"),
|
|
399
|
+
element_types.map((type) => /* @__PURE__ */ jsx9("option", { value: type, children: type }, type))
|
|
400
|
+
]
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
}
|
|
404
|
+
)
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
key: "name",
|
|
408
|
+
name: "name",
|
|
409
|
+
renderHeaderCell: (col) => /* @__PURE__ */ jsx9(
|
|
410
|
+
HeaderCell,
|
|
411
|
+
{
|
|
412
|
+
column: col,
|
|
413
|
+
onTextChange: (t) => setFilter({ name_search: t })
|
|
414
|
+
}
|
|
415
|
+
)
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
key: "selector_path",
|
|
419
|
+
name: "selector_path",
|
|
420
|
+
renderHeaderCell: (col) => /* @__PURE__ */ jsx9(
|
|
421
|
+
HeaderCell,
|
|
422
|
+
{
|
|
423
|
+
column: col,
|
|
424
|
+
onTextChange: (t) => setFilter({ selector_search: t })
|
|
425
|
+
}
|
|
426
|
+
)
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
key: "other_ids",
|
|
430
|
+
name: "other_ids",
|
|
431
|
+
renderCell: (row) => /* @__PURE__ */ jsx9("div", { className: "space-x-2", children: Object.entries(row.other_ids).map(([other_id, v]) => /* @__PURE__ */ jsx9(
|
|
432
|
+
ClickableText,
|
|
433
|
+
{
|
|
434
|
+
text: v,
|
|
435
|
+
onClick: () => setFilter({ focused_id: v })
|
|
436
|
+
},
|
|
437
|
+
v
|
|
438
|
+
)) })
|
|
439
|
+
}
|
|
440
|
+
];
|
|
441
|
+
const elements4 = elements3.filter((e) => {
|
|
442
|
+
if (!filters.name_search) return true;
|
|
443
|
+
return e.name?.toLowerCase()?.includes(filters.name_search.toLowerCase());
|
|
444
|
+
}).filter((e) => {
|
|
445
|
+
if (!filters.component_type_filter) return true;
|
|
446
|
+
if (filters.component_type_filter === "any") return true;
|
|
447
|
+
if (filters.component_type_filter === "source") {
|
|
448
|
+
return e.type.startsWith("source_");
|
|
449
|
+
}
|
|
450
|
+
if (filters.component_type_filter === "source/pcb") {
|
|
451
|
+
return e.type.startsWith("source_") || e.type.startsWith("pcb_");
|
|
452
|
+
}
|
|
453
|
+
if (filters.component_type_filter === "source/schematic") {
|
|
454
|
+
return e.type.startsWith("source_") || e.type.startsWith("schematic_");
|
|
455
|
+
}
|
|
456
|
+
return e.type?.includes(filters.component_type_filter);
|
|
457
|
+
}).filter((e) => {
|
|
458
|
+
if (!filters.selector_search) return true;
|
|
459
|
+
const parts = filters.selector_search.split(" ").filter((p) => p.length > 0);
|
|
460
|
+
return parts.every((part) => e.selector_path?.includes(part));
|
|
461
|
+
}).filter((e) => {
|
|
462
|
+
if (!filters.id_search) return true;
|
|
463
|
+
return e.primary_id?.includes(filters.id_search);
|
|
464
|
+
}).filter((e) => {
|
|
465
|
+
if (!filters.focused_id) return true;
|
|
466
|
+
if (e.primary_id === filters.focused_id) return true;
|
|
467
|
+
if (Object.values(e.other_ids).includes(filters.focused_id)) return true;
|
|
468
|
+
return false;
|
|
469
|
+
});
|
|
470
|
+
return /* @__PURE__ */ jsxs6("div", { className: "font-mono text-xs", children: [
|
|
471
|
+
/* @__PURE__ */ jsx9("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs6("table", { className: "table-auto w-full text-left", children: [
|
|
472
|
+
/* @__PURE__ */ jsx9("thead", { children: /* @__PURE__ */ jsx9("tr", { children: columns.map((col) => /* @__PURE__ */ jsx9("th", { className: "px-4 py-2 border-b", children: col.renderHeaderCell ? col.renderHeaderCell(col) : col.name }, col.key)) }) }),
|
|
473
|
+
/* @__PURE__ */ jsx9("tbody", { children: elements4.map((row, rowIndex) => /* @__PURE__ */ jsx9("tr", { className: "hover:bg-gray-100", children: columns.map((col) => /* @__PURE__ */ jsx9("td", { className: "px-4 py-2 border-b", children: col.renderCell ? col.renderCell(row) : row[col.key] }, col.key)) }, rowIndex)) })
|
|
474
|
+
] }) }),
|
|
475
|
+
/* @__PURE__ */ jsx9(
|
|
476
|
+
Modal_default,
|
|
477
|
+
{
|
|
478
|
+
open: modal.open,
|
|
479
|
+
onClose: () => setModal({ open: false }),
|
|
480
|
+
title: modal.open ? modal.title : "",
|
|
481
|
+
children: /* @__PURE__ */ jsx9("div", { className: "bg-gray-800 p-3 text-white rounded", children: /* @__PURE__ */ jsx9("pre", { className: "whitespace-pre-wrap", children: modal.open ? JSON.stringify(modal.element, null, 2) : "" }) })
|
|
482
|
+
}
|
|
483
|
+
)
|
|
484
|
+
] });
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// lib/components/BomTable.tsx
|
|
488
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
489
|
+
var linkify = (supplier, partNumber) => {
|
|
490
|
+
if (supplier === "jlcpcb") {
|
|
491
|
+
return /* @__PURE__ */ jsx10(
|
|
492
|
+
"a",
|
|
493
|
+
{
|
|
494
|
+
className: "underline text-blue-500",
|
|
495
|
+
target: "_blank",
|
|
496
|
+
rel: "noreferrer",
|
|
497
|
+
href: `https://jlcpcb.com/partdetail/${partNumber}`,
|
|
498
|
+
children: partNumber
|
|
499
|
+
}
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
return partNumber;
|
|
503
|
+
};
|
|
504
|
+
var BomTable = ({ circuitJson }) => {
|
|
505
|
+
const sourceComponents = circuitJson.filter(
|
|
506
|
+
(el) => el.type === "source_component"
|
|
507
|
+
);
|
|
508
|
+
const supplierColumns = /* @__PURE__ */ new Set();
|
|
509
|
+
for (const comp of sourceComponents) {
|
|
510
|
+
if (comp.supplier_part_numbers) {
|
|
511
|
+
for (const supplier of Object.keys(comp.supplier_part_numbers)) {
|
|
512
|
+
supplierColumns.add(supplier);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return /* @__PURE__ */ jsx10("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs7("table", { className: "w-full text-left text-sm", children: [
|
|
517
|
+
/* @__PURE__ */ jsx10("thead", { children: /* @__PURE__ */ jsxs7("tr", { className: "border-b", children: [
|
|
518
|
+
/* @__PURE__ */ jsx10("th", { className: "p-2", children: "Name" }),
|
|
519
|
+
Array.from(supplierColumns).map((supplier) => /* @__PURE__ */ jsx10("th", { className: "p-2 capitalize", children: supplier }, supplier))
|
|
520
|
+
] }) }),
|
|
521
|
+
/* @__PURE__ */ jsx10("tbody", { children: sourceComponents.map((comp) => /* @__PURE__ */ jsxs7("tr", { className: "border-b", children: [
|
|
522
|
+
/* @__PURE__ */ jsx10("td", { className: "p-2", children: comp.name }),
|
|
523
|
+
Array.from(supplierColumns).map((supplier) => /* @__PURE__ */ jsx10("td", { className: "p-2", children: linkify(
|
|
524
|
+
supplier,
|
|
525
|
+
comp.supplier_part_numbers?.[supplier]?.[0] || ""
|
|
526
|
+
) }, supplier))
|
|
527
|
+
] }, comp.source_component_id)) })
|
|
528
|
+
] }) });
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
// lib/components/CircuitJsonPreview.tsx
|
|
532
|
+
import {
|
|
533
|
+
CheckIcon as CheckIcon2,
|
|
534
|
+
EllipsisIcon,
|
|
535
|
+
FullscreenIcon,
|
|
536
|
+
MinimizeIcon
|
|
537
|
+
} from "lucide-react";
|
|
538
|
+
|
|
539
|
+
// lib/components/ui/dropdown-menu.tsx
|
|
540
|
+
import * as React4 from "react";
|
|
541
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
542
|
+
import {
|
|
543
|
+
CheckIcon,
|
|
544
|
+
ChevronRightIcon,
|
|
545
|
+
DotFilledIcon
|
|
546
|
+
} from "@radix-ui/react-icons";
|
|
547
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
548
|
+
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
549
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
550
|
+
var DropdownMenuSubTrigger = React4.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs8(
|
|
551
|
+
DropdownMenuPrimitive.SubTrigger,
|
|
552
|
+
{
|
|
553
|
+
ref,
|
|
554
|
+
className: cn(
|
|
555
|
+
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-slate-100 data-[state=open]:bg-slate-100 dark:focus:bg-slate-800 dark:data-[state=open]:bg-slate-800",
|
|
556
|
+
inset && "pl-8",
|
|
557
|
+
className
|
|
558
|
+
),
|
|
559
|
+
...props,
|
|
560
|
+
children: [
|
|
561
|
+
children,
|
|
562
|
+
/* @__PURE__ */ jsx11(ChevronRightIcon, { className: "ml-auto h-4 w-4" })
|
|
563
|
+
]
|
|
564
|
+
}
|
|
565
|
+
));
|
|
566
|
+
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
567
|
+
var DropdownMenuSubContent = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
|
|
568
|
+
DropdownMenuPrimitive.SubContent,
|
|
569
|
+
{
|
|
570
|
+
ref,
|
|
571
|
+
className: cn(
|
|
572
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-200 bg-white p-1 text-slate-950 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",
|
|
573
|
+
className
|
|
574
|
+
),
|
|
575
|
+
...props
|
|
576
|
+
}
|
|
577
|
+
));
|
|
578
|
+
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
579
|
+
var DropdownMenuContent = React4.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx11(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx11(
|
|
580
|
+
DropdownMenuPrimitive.Content,
|
|
581
|
+
{
|
|
582
|
+
ref,
|
|
583
|
+
sideOffset,
|
|
584
|
+
className: cn(
|
|
585
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-200 bg-white p-1 text-slate-950 shadow-md dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",
|
|
586
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
587
|
+
className
|
|
588
|
+
),
|
|
589
|
+
...props
|
|
590
|
+
}
|
|
591
|
+
) }));
|
|
592
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
593
|
+
var DropdownMenuItem = React4.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx11(
|
|
594
|
+
DropdownMenuPrimitive.Item,
|
|
595
|
+
{
|
|
596
|
+
ref,
|
|
597
|
+
className: cn(
|
|
598
|
+
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",
|
|
599
|
+
inset && "pl-8",
|
|
600
|
+
className
|
|
601
|
+
),
|
|
602
|
+
...props
|
|
603
|
+
}
|
|
604
|
+
));
|
|
605
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
606
|
+
var DropdownMenuCheckboxItem = React4.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs8(
|
|
607
|
+
DropdownMenuPrimitive.CheckboxItem,
|
|
608
|
+
{
|
|
609
|
+
ref,
|
|
610
|
+
className: cn(
|
|
611
|
+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",
|
|
612
|
+
className
|
|
613
|
+
),
|
|
614
|
+
checked,
|
|
615
|
+
...props,
|
|
616
|
+
children: [
|
|
617
|
+
/* @__PURE__ */ jsx11("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx11(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx11(CheckIcon, { className: "h-4 w-4" }) }) }),
|
|
618
|
+
children
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
));
|
|
622
|
+
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
623
|
+
var DropdownMenuRadioItem = React4.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs8(
|
|
624
|
+
DropdownMenuPrimitive.RadioItem,
|
|
625
|
+
{
|
|
626
|
+
ref,
|
|
627
|
+
className: cn(
|
|
628
|
+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",
|
|
629
|
+
className
|
|
630
|
+
),
|
|
631
|
+
...props,
|
|
632
|
+
children: [
|
|
633
|
+
/* @__PURE__ */ jsx11("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx11(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx11(DotFilledIcon, { className: "h-4 w-4 fill-current" }) }) }),
|
|
634
|
+
children
|
|
635
|
+
]
|
|
636
|
+
}
|
|
637
|
+
));
|
|
638
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
639
|
+
var DropdownMenuLabel = React4.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx11(
|
|
640
|
+
DropdownMenuPrimitive.Label,
|
|
641
|
+
{
|
|
642
|
+
ref,
|
|
643
|
+
className: cn(
|
|
644
|
+
"px-2 py-1.5 text-sm font-semibold",
|
|
645
|
+
inset && "pl-8",
|
|
646
|
+
className
|
|
647
|
+
),
|
|
648
|
+
...props
|
|
649
|
+
}
|
|
650
|
+
));
|
|
651
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
652
|
+
var DropdownMenuSeparator = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx11(
|
|
653
|
+
DropdownMenuPrimitive.Separator,
|
|
654
|
+
{
|
|
655
|
+
ref,
|
|
656
|
+
className: cn("-mx-1 my-1 h-px bg-slate-100 dark:bg-slate-800", className),
|
|
657
|
+
...props
|
|
658
|
+
}
|
|
659
|
+
));
|
|
660
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
661
|
+
var DropdownMenuShortcut = ({
|
|
662
|
+
className,
|
|
663
|
+
...props
|
|
664
|
+
}) => {
|
|
665
|
+
return /* @__PURE__ */ jsx11(
|
|
666
|
+
"span",
|
|
667
|
+
{
|
|
668
|
+
className: cn("ml-auto text-xs tracking-widest opacity-60", className),
|
|
669
|
+
...props
|
|
670
|
+
}
|
|
671
|
+
);
|
|
672
|
+
};
|
|
673
|
+
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|
674
|
+
|
|
675
|
+
// lib/components/PcbViewerWithContainerHeight.tsx
|
|
676
|
+
import { useRef, useState as useState2, useLayoutEffect } from "react";
|
|
677
|
+
import { PCBViewer } from "@tscircuit/pcb-viewer";
|
|
678
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
679
|
+
var PcbViewerWithContainerHeight = ({
|
|
680
|
+
containerClassName,
|
|
681
|
+
...props
|
|
682
|
+
}) => {
|
|
683
|
+
const containerRef = useRef(null);
|
|
684
|
+
const [computedHeight, setComputedHeight] = useState2(620);
|
|
685
|
+
useLayoutEffect(() => {
|
|
686
|
+
const updateHeight = () => {
|
|
687
|
+
if (containerRef.current) {
|
|
688
|
+
const containerHeight = containerRef.current.clientHeight;
|
|
689
|
+
const screenHeight = window.innerHeight;
|
|
690
|
+
setComputedHeight(
|
|
691
|
+
Math.min(Math.max(containerHeight, 620), screenHeight)
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
updateHeight();
|
|
696
|
+
const resizeObserver = new ResizeObserver(updateHeight);
|
|
697
|
+
if (containerRef.current) {
|
|
698
|
+
resizeObserver.observe(containerRef.current);
|
|
699
|
+
}
|
|
700
|
+
window.addEventListener("resize", updateHeight);
|
|
701
|
+
return () => {
|
|
702
|
+
resizeObserver.disconnect();
|
|
703
|
+
window.removeEventListener("resize", updateHeight);
|
|
704
|
+
};
|
|
705
|
+
}, []);
|
|
706
|
+
return /* @__PURE__ */ jsx12("div", { ref: containerRef, className: containerClassName || "w-full h-full", children: /* @__PURE__ */ jsx12(PCBViewer, { ...props, height: computedHeight }) });
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
// lib/hooks/use-styles.ts
|
|
710
|
+
import { useEffect } from "react";
|
|
711
|
+
|
|
712
|
+
// lib/hooks/styles.generated.ts
|
|
713
|
+
var styles_generated_default = `.invisible{visibility:hidden}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.left-2{left:.5rem}.right-4{right:1rem}.right-\\[4px\\]{right:4px}.top-4{top:1rem}.top-\\[6px\\]{top:6px}.z-50{z-index:50}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-1{margin-bottom:.25rem;margin-top:.25rem}.mb-3{margin-bottom:.75rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-0{margin-top:0}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.contents{display:contents}.h-1{height:.25rem}.h-10{height:2.5rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\\.5{height:.875rem}.h-4{height:1rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\\[620px\\]{height:620px}.h-\\[calc\\(100vh-96px\\)\\]{height:calc(100vh - 96px)}.h-full{height:100%}.h-px{height:1px}.max-h-\\[500px\\]{max-height:500px}.min-h-\\[620px\\]{min-height:620px}.min-h-\\[calc\\(100vh-240px\\)\\]{min-height:calc(100vh - 240px)}.w-1{width:.25rem}.w-11\\/12{width:91.666667%}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\\.5{width:.875rem}.w-4{width:1rem}.w-9{width:2.25rem}.w-full{width:100%}.min-w-\\[8rem\\]{min-width:8rem}.max-w-2xl{max-width:42rem}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-slate-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity,1))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-slate-900{--tw-bg-opacity:1;background-color:rgb(15 23 42/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-opacity-50{--tw-bg-opacity:0.5}.fill-current{fill:currentColor}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\\.5{padding-bottom:.375rem;padding-top:.375rem}.py-10{padding-bottom:2.5rem;padding-top:2.5rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.pl-8{padding-left:2rem}.pr-2{padding-right:.5rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\\[8px\\]{font-size:8px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.capitalize{text-transform:capitalize}.leading-5{line-height:1.25rem}.tracking-widest{letter-spacing:.1em}.text-blue-300{--tw-text-opacity:1;color:rgb(147 197 253/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61/var(--tw-text-opacity,1))}.text-green-800{--tw-text-opacity:1;color:rgb(22 101 52/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.text-slate-50{--tw-text-opacity:1;color:rgb(248 250 252/var(--tw-text-opacity,1))}.text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.text-slate-950{--tw-text-opacity:1;color:rgb(2 6 23/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.opacity-60{opacity:.6}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-offset-white{--tw-ring-offset-color:#fff}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.\\*\\:text-xs>*{font-size:.75rem;line-height:1rem}.hover\\:bg-blue-500:hover{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.hover\\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.hover\\:bg-red-500\\/90:hover{background-color:rgba(239,68,68,.9)}.hover\\:bg-slate-100:hover{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.hover\\:bg-slate-100\\/80:hover{background-color:rgba(241,245,249,.8)}.hover\\:bg-slate-900\\/90:hover{background-color:rgba(15,23,42,.9)}.hover\\:text-slate-900:hover{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.hover\\:underline:hover{text-decoration-line:underline}.focus\\:bg-slate-100:focus{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.focus\\:text-slate-900:focus{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.focus-visible\\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:ring-1:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\\:ring-slate-950:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(2 6 23/var(--tw-ring-opacity,1))}.focus-visible\\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:opacity-50:disabled{opacity:.5}.data-\\[disabled\\]\\:pointer-events-none[data-disabled]{pointer-events:none}.data-\\[state\\=active\\]\\:bg-white[data-state=active]{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.data-\\[state\\=open\\]\\:bg-slate-100[data-state=open]{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.data-\\[state\\=active\\]\\:text-slate-950[data-state=active]{--tw-text-opacity:1;color:rgb(2 6 23/var(--tw-text-opacity,1))}.data-\\[disabled\\]\\:opacity-50[data-disabled]{opacity:.5}.data-\\[state\\=active\\]\\:shadow[data-state=active]{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}@media (min-width:768px){.md\\:sticky{position:sticky}.md\\:top-2{top:.5rem}}@media (prefers-color-scheme:dark){.dark\\:border-slate-800{--tw-border-opacity:1;border-color:rgb(30 41 59/var(--tw-border-opacity,1))}.dark\\:bg-red-900{--tw-bg-opacity:1;background-color:rgb(127 29 29/var(--tw-bg-opacity,1))}.dark\\:bg-slate-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.dark\\:bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity,1))}.dark\\:bg-slate-950{--tw-bg-opacity:1;background-color:rgb(2 6 23/var(--tw-bg-opacity,1))}.dark\\:text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.dark\\:text-slate-50{--tw-text-opacity:1;color:rgb(248 250 252/var(--tw-text-opacity,1))}.dark\\:text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.dark\\:ring-offset-slate-950{--tw-ring-offset-color:#020617}.dark\\:hover\\:bg-red-900\\/90:hover{background-color:rgba(127,29,29,.9)}.dark\\:hover\\:bg-slate-50\\/90:hover{background-color:rgba(248,250,252,.9)}.dark\\:hover\\:bg-slate-800:hover{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity,1))}.dark\\:hover\\:bg-slate-800\\/80:hover{background-color:rgba(30,41,59,.8)}.dark\\:hover\\:text-slate-50:hover{--tw-text-opacity:1;color:rgb(248 250 252/var(--tw-text-opacity,1))}.dark\\:focus\\:bg-slate-800:focus{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity,1))}.dark\\:focus\\:text-slate-50:focus{--tw-text-opacity:1;color:rgb(248 250 252/var(--tw-text-opacity,1))}.dark\\:focus-visible\\:ring-slate-300:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(203 213 225/var(--tw-ring-opacity,1))}.dark\\:data-\\[state\\=active\\]\\:bg-slate-950[data-state=active]{--tw-bg-opacity:1;background-color:rgb(2 6 23/var(--tw-bg-opacity,1))}.dark\\:data-\\[state\\=open\\]\\:bg-slate-800[data-state=open]{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity,1))}.dark\\:data-\\[state\\=active\\]\\:text-slate-50[data-state=active]{--tw-text-opacity:1;color:rgb(248 250 252/var(--tw-text-opacity,1))}}`;
|
|
714
|
+
|
|
715
|
+
// lib/hooks/use-styles.ts
|
|
716
|
+
var useStyles = () => {
|
|
717
|
+
useEffect(() => {
|
|
718
|
+
const existingStyle = document.querySelector(
|
|
719
|
+
'style[data-styles="tscircuit-runframe"]'
|
|
720
|
+
);
|
|
721
|
+
if (existingStyle) return;
|
|
722
|
+
const styleElement = document.createElement("style");
|
|
723
|
+
styleElement.setAttribute("data-styles", "tscircuit-runframe");
|
|
724
|
+
styleElement.textContent = styles_generated_default;
|
|
725
|
+
document.head.appendChild(styleElement);
|
|
726
|
+
}, []);
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
// lib/components/CircuitJsonPreview.tsx
|
|
730
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
731
|
+
var CircuitJsonPreview = ({
|
|
732
|
+
code,
|
|
733
|
+
onRunClicked = () => {
|
|
734
|
+
},
|
|
735
|
+
tsxRunTriggerCount,
|
|
736
|
+
errorMessage,
|
|
737
|
+
circuitJsonKey = "",
|
|
738
|
+
circuitJson,
|
|
739
|
+
showCodeTab = false,
|
|
740
|
+
codeTabContent,
|
|
741
|
+
showJsonTab = true,
|
|
742
|
+
showImportAndFormatButtons = true,
|
|
743
|
+
className,
|
|
744
|
+
headerClassName,
|
|
745
|
+
leftHeaderContent,
|
|
746
|
+
readOnly,
|
|
747
|
+
isStreaming,
|
|
748
|
+
onToggleFullScreen,
|
|
749
|
+
isFullScreen,
|
|
750
|
+
isRunningCode,
|
|
751
|
+
hasCodeChangedSinceLastRun,
|
|
752
|
+
onCodeChange,
|
|
753
|
+
onDtsChange,
|
|
754
|
+
manualEditsFileContent,
|
|
755
|
+
onManualEditsFileContentChange
|
|
756
|
+
}) => {
|
|
757
|
+
useStyles();
|
|
758
|
+
const [activeTab, setActiveTab] = useState3(showCodeTab ? "code" : "pcb");
|
|
759
|
+
useEffect2(() => {
|
|
760
|
+
if (errorMessage) {
|
|
761
|
+
setActiveTab("error");
|
|
762
|
+
}
|
|
763
|
+
}, [errorMessage]);
|
|
764
|
+
useEffect2(() => {
|
|
765
|
+
if (activeTab === "code" && circuitJson && !errorMessage) {
|
|
766
|
+
setActiveTab("pcb");
|
|
767
|
+
}
|
|
768
|
+
}, [circuitJson]);
|
|
769
|
+
return /* @__PURE__ */ jsx13("div", { className: cn("flex flex-col relative", className), children: /* @__PURE__ */ jsx13("div", { className: "md:sticky md:top-2", children: /* @__PURE__ */ jsxs9(
|
|
770
|
+
Tabs,
|
|
771
|
+
{
|
|
772
|
+
value: activeTab,
|
|
773
|
+
onValueChange: setActiveTab,
|
|
774
|
+
className: "flex-grow flex flex-col p-2",
|
|
775
|
+
children: [
|
|
776
|
+
/* @__PURE__ */ jsxs9("div", { className: cn("flex items-center gap-2", headerClassName), children: [
|
|
777
|
+
leftHeaderContent,
|
|
778
|
+
leftHeaderContent && /* @__PURE__ */ jsx13("div", { className: "flex-grow" }),
|
|
779
|
+
!leftHeaderContent && /* @__PURE__ */ jsx13("div", { className: "flex-grow" }),
|
|
780
|
+
/* @__PURE__ */ jsxs9(TabsList, { children: [
|
|
781
|
+
showCodeTab && /* @__PURE__ */ jsx13(TabsTrigger, { value: "code", children: "Code" }),
|
|
782
|
+
/* @__PURE__ */ jsxs9(TabsTrigger, { value: "pcb", className: "whitespace-nowrap", children: [
|
|
783
|
+
circuitJson && /* @__PURE__ */ jsx13(
|
|
784
|
+
"span",
|
|
785
|
+
{
|
|
786
|
+
className: cn(
|
|
787
|
+
"inline-flex items-center justify-center w-2 h-2 mr-1 text-xs font-bold text-white rounded-full",
|
|
788
|
+
!hasCodeChangedSinceLastRun ? "bg-blue-500" : "bg-gray-500"
|
|
789
|
+
)
|
|
790
|
+
}
|
|
791
|
+
),
|
|
792
|
+
"PCB"
|
|
793
|
+
] }),
|
|
794
|
+
/* @__PURE__ */ jsxs9(TabsTrigger, { value: "schematic", className: "whitespace-nowrap", children: [
|
|
795
|
+
circuitJson && /* @__PURE__ */ jsx13(
|
|
796
|
+
"span",
|
|
797
|
+
{
|
|
798
|
+
className: cn(
|
|
799
|
+
"inline-flex items-center justify-center w-2 h-2 mr-1 text-xs font-bold text-white rounded-full",
|
|
800
|
+
!hasCodeChangedSinceLastRun ? "bg-blue-500" : "bg-gray-500"
|
|
801
|
+
)
|
|
802
|
+
}
|
|
803
|
+
),
|
|
804
|
+
"Schematic"
|
|
805
|
+
] }),
|
|
806
|
+
/* @__PURE__ */ jsxs9(TabsTrigger, { value: "cad", children: [
|
|
807
|
+
circuitJson && /* @__PURE__ */ jsx13(
|
|
808
|
+
"span",
|
|
809
|
+
{
|
|
810
|
+
className: cn(
|
|
811
|
+
"inline-flex items-center justify-center w-2 h-2 mr-1 text-xs font-bold text-white rounded-full",
|
|
812
|
+
!hasCodeChangedSinceLastRun ? "bg-blue-500" : "bg-gray-500"
|
|
813
|
+
)
|
|
814
|
+
}
|
|
815
|
+
),
|
|
816
|
+
"3D"
|
|
817
|
+
] }),
|
|
818
|
+
/* @__PURE__ */ jsxs9(DropdownMenu, { children: [
|
|
819
|
+
/* @__PURE__ */ jsx13(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs9("div", { className: "whitespace-nowrap p-2 mr-1 cursor-pointer relative", children: [
|
|
820
|
+
/* @__PURE__ */ jsx13(EllipsisIcon, { className: "w-4 h-4" }),
|
|
821
|
+
errorMessage && /* @__PURE__ */ jsx13("span", { className: "inline-flex absolute top-[6px] right-[4px] items-center justify-center w-1 h-1 ml-2 text-[8px] font-bold text-white bg-red-500 rounded-full" })
|
|
822
|
+
] }) }),
|
|
823
|
+
/* @__PURE__ */ jsxs9(DropdownMenuContent, { className: "*:text-xs", children: [
|
|
824
|
+
/* @__PURE__ */ jsxs9(
|
|
825
|
+
DropdownMenuItem,
|
|
826
|
+
{
|
|
827
|
+
onSelect: () => setActiveTab("error"),
|
|
828
|
+
className: "flex",
|
|
829
|
+
children: [
|
|
830
|
+
/* @__PURE__ */ jsx13(
|
|
831
|
+
CheckIcon2,
|
|
832
|
+
{
|
|
833
|
+
className: cn(
|
|
834
|
+
"w-3 h-3 mr-2",
|
|
835
|
+
activeTab !== "error" && "invisible"
|
|
836
|
+
)
|
|
837
|
+
}
|
|
838
|
+
),
|
|
839
|
+
/* @__PURE__ */ jsx13("div", { className: "flex-grow", children: "Errors" }),
|
|
840
|
+
errorMessage && /* @__PURE__ */ jsx13("span", { className: "inline-flex items-center justify-center w-3 h-3 ml-2 text-[8px] font-bold text-white bg-red-500 rounded-full", children: "1" })
|
|
841
|
+
]
|
|
842
|
+
}
|
|
843
|
+
),
|
|
844
|
+
/* @__PURE__ */ jsxs9(DropdownMenuItem, { onSelect: () => setActiveTab("bom"), children: [
|
|
845
|
+
/* @__PURE__ */ jsx13(
|
|
846
|
+
CheckIcon2,
|
|
847
|
+
{
|
|
848
|
+
className: cn(
|
|
849
|
+
"w-3 h-3 mr-2",
|
|
850
|
+
activeTab !== "bom" && "invisible"
|
|
851
|
+
)
|
|
852
|
+
}
|
|
853
|
+
),
|
|
854
|
+
"Bill of Materials"
|
|
855
|
+
] }),
|
|
856
|
+
/* @__PURE__ */ jsxs9(
|
|
857
|
+
DropdownMenuItem,
|
|
858
|
+
{
|
|
859
|
+
onSelect: () => setActiveTab("circuitjson"),
|
|
860
|
+
children: [
|
|
861
|
+
/* @__PURE__ */ jsx13(
|
|
862
|
+
CheckIcon2,
|
|
863
|
+
{
|
|
864
|
+
className: cn(
|
|
865
|
+
"w-3 h-3 mr-2",
|
|
866
|
+
activeTab !== "circuitjson" && "invisible"
|
|
867
|
+
)
|
|
868
|
+
}
|
|
869
|
+
),
|
|
870
|
+
"JSON"
|
|
871
|
+
]
|
|
872
|
+
}
|
|
873
|
+
)
|
|
874
|
+
] })
|
|
875
|
+
] })
|
|
876
|
+
] }),
|
|
877
|
+
onToggleFullScreen && /* @__PURE__ */ jsx13(Button, { onClick: onToggleFullScreen, variant: "ghost", children: isFullScreen ? /* @__PURE__ */ jsx13(MinimizeIcon, { size: 16 }) : /* @__PURE__ */ jsx13(FullscreenIcon, { size: 16 }) })
|
|
878
|
+
] }),
|
|
879
|
+
showCodeTab && /* @__PURE__ */ jsx13(TabsContent, { value: "code", className: "flex-grow overflow-hidden", children: /* @__PURE__ */ jsx13("div", { className: "h-full", children: codeTabContent }) }),
|
|
880
|
+
/* @__PURE__ */ jsx13(TabsContent, { value: "pcb", children: /* @__PURE__ */ jsx13(
|
|
881
|
+
"div",
|
|
882
|
+
{
|
|
883
|
+
className: cn(
|
|
884
|
+
"overflow-hidden",
|
|
885
|
+
isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]"
|
|
886
|
+
),
|
|
887
|
+
children: /* @__PURE__ */ jsx13(ErrorBoundary, { fallback: /* @__PURE__ */ jsx13("div", { children: "Error loading PCB viewer" }), children: circuitJson ? /* @__PURE__ */ jsx13(
|
|
888
|
+
PcbViewerWithContainerHeight,
|
|
889
|
+
{
|
|
890
|
+
soup: circuitJson,
|
|
891
|
+
containerClassName: cn(
|
|
892
|
+
"h-full w-full",
|
|
893
|
+
isFullScreen ? "min-h-[calc(100vh-240px)]" : "min-h-[620px]"
|
|
894
|
+
)
|
|
895
|
+
},
|
|
896
|
+
circuitJsonKey
|
|
897
|
+
) : /* @__PURE__ */ jsx13(PreviewEmptyState_default, { onRunClicked }) })
|
|
898
|
+
}
|
|
899
|
+
) }),
|
|
900
|
+
/* @__PURE__ */ jsx13(TabsContent, { value: "schematic", children: /* @__PURE__ */ jsx13(
|
|
901
|
+
"div",
|
|
902
|
+
{
|
|
903
|
+
className: cn(
|
|
904
|
+
"overflow-auto",
|
|
905
|
+
isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]"
|
|
906
|
+
),
|
|
907
|
+
children: /* @__PURE__ */ jsx13(ErrorBoundary, { fallback: /* @__PURE__ */ jsx13("div", { children: "Error loading Schematic" }), children: circuitJson ? /* @__PURE__ */ jsx13(
|
|
908
|
+
SchematicViewer,
|
|
909
|
+
{
|
|
910
|
+
circuitJson,
|
|
911
|
+
containerStyle: {
|
|
912
|
+
height: "100%"
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
) : /* @__PURE__ */ jsx13(PreviewEmptyState_default, { onRunClicked }) })
|
|
916
|
+
}
|
|
917
|
+
) }),
|
|
918
|
+
/* @__PURE__ */ jsx13(TabsContent, { value: "cad", children: /* @__PURE__ */ jsx13(
|
|
919
|
+
"div",
|
|
920
|
+
{
|
|
921
|
+
className: cn(
|
|
922
|
+
"overflow-auto",
|
|
923
|
+
isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]"
|
|
924
|
+
),
|
|
925
|
+
children: /* @__PURE__ */ jsx13(ErrorBoundary, { FallbackComponent: ErrorFallback, children: circuitJson ? /* @__PURE__ */ jsx13(CadViewer, { soup: circuitJson }) : /* @__PURE__ */ jsx13(PreviewEmptyState_default, { onRunClicked }) })
|
|
926
|
+
}
|
|
927
|
+
) }),
|
|
928
|
+
/* @__PURE__ */ jsx13(TabsContent, { value: "bom", children: /* @__PURE__ */ jsx13(
|
|
929
|
+
"div",
|
|
930
|
+
{
|
|
931
|
+
className: cn(
|
|
932
|
+
"overflow-auto",
|
|
933
|
+
isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]"
|
|
934
|
+
),
|
|
935
|
+
children: /* @__PURE__ */ jsx13(ErrorBoundary, { fallback: /* @__PURE__ */ jsx13("div", { children: "Error loading BOM" }), children: circuitJson ? /* @__PURE__ */ jsx13(BomTable, { circuitJson }) : /* @__PURE__ */ jsx13(PreviewEmptyState_default, { onRunClicked }) })
|
|
936
|
+
}
|
|
937
|
+
) }),
|
|
938
|
+
/* @__PURE__ */ jsx13(TabsContent, { value: "circuitjson", children: /* @__PURE__ */ jsx13(
|
|
939
|
+
"div",
|
|
940
|
+
{
|
|
941
|
+
className: cn(
|
|
942
|
+
"overflow-auto",
|
|
943
|
+
isFullScreen ? "h-[calc(100vh-96px)]" : "h-[620px]"
|
|
944
|
+
),
|
|
945
|
+
children: /* @__PURE__ */ jsx13(ErrorBoundary, { fallback: /* @__PURE__ */ jsx13("div", { children: "Error loading JSON viewer" }), children: circuitJson ? /* @__PURE__ */ jsx13(CircuitJsonTableViewer, { elements: circuitJson }) : /* @__PURE__ */ jsx13(PreviewEmptyState_default, { onRunClicked }) })
|
|
946
|
+
}
|
|
947
|
+
) }),
|
|
948
|
+
/* @__PURE__ */ jsx13(TabsContent, { value: "error", children: circuitJson || errorMessage ? /* @__PURE__ */ jsx13(ErrorTabContent, { code, errorMessage }) : /* @__PURE__ */ jsx13(PreviewEmptyState_default, { onRunClicked }) })
|
|
949
|
+
]
|
|
950
|
+
}
|
|
951
|
+
) }) });
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
export {
|
|
955
|
+
CircuitJsonPreview
|
|
956
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface PreviewContentProps {
|
|
4
|
+
code?: string;
|
|
5
|
+
readOnly?: boolean;
|
|
6
|
+
onRunClicked?: () => void;
|
|
7
|
+
tsxRunTriggerCount?: number;
|
|
8
|
+
errorMessage?: string | null;
|
|
9
|
+
circuitJson: any;
|
|
10
|
+
circuitJsonKey?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
showCodeTab?: boolean;
|
|
13
|
+
codeTabContent?: React.ReactNode;
|
|
14
|
+
showJsonTab?: boolean;
|
|
15
|
+
showImportAndFormatButtons?: boolean;
|
|
16
|
+
headerClassName?: string;
|
|
17
|
+
leftHeaderContent?: React.ReactNode;
|
|
18
|
+
isRunningCode?: boolean;
|
|
19
|
+
isStreaming?: boolean;
|
|
20
|
+
onToggleFullScreen?: () => void;
|
|
21
|
+
isFullScreen?: boolean;
|
|
22
|
+
onCodeChange?: (code: string) => void;
|
|
23
|
+
onDtsChange?: (dts: string) => void;
|
|
24
|
+
manualEditsFileContent?: string;
|
|
25
|
+
hasCodeChangedSinceLastRun?: boolean;
|
|
26
|
+
onManualEditsFileContentChange?: (newmanualEditsFileContent: string) => void;
|
|
27
|
+
}
|
|
28
|
+
declare const CircuitJsonPreview: ({ code, onRunClicked, tsxRunTriggerCount, errorMessage, circuitJsonKey, circuitJson, showCodeTab, codeTabContent, showJsonTab, showImportAndFormatButtons, className, headerClassName, leftHeaderContent, readOnly, isStreaming, onToggleFullScreen, isFullScreen, isRunningCode, hasCodeChangedSinceLastRun, onCodeChange, onDtsChange, manualEditsFileContent, onManualEditsFileContentChange, }: PreviewContentProps) => react_jsx_runtime.JSX.Element;
|
|
29
|
+
|
|
30
|
+
export { CircuitJsonPreview, type PreviewContentProps };
|
package/dist/preview.js
ADDED
package/dist/runner.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export { CircuitJsonPreview, PreviewContentProps } from './preview.js';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
/**
|
|
6
|
+
* Map of filenames to file contents that will be available in the worker
|
|
7
|
+
*/
|
|
8
|
+
fsMap: {
|
|
9
|
+
[filename: string]: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* The entry point file that will be executed first
|
|
13
|
+
*/
|
|
14
|
+
entrypoint: string;
|
|
15
|
+
/**
|
|
16
|
+
* Called when the circuit JSON changes
|
|
17
|
+
*/
|
|
18
|
+
onCircuitJsonChange?: (circuitJson: any) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Called when rendering is finished
|
|
21
|
+
*/
|
|
22
|
+
onRenderingFinished?: (params: {
|
|
23
|
+
circuitJson: any;
|
|
24
|
+
}) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Called for each render event
|
|
27
|
+
*/
|
|
28
|
+
onRenderEvent?: (event: any) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Called when an error occurs
|
|
31
|
+
*/
|
|
32
|
+
onError?: (error: Error) => void;
|
|
33
|
+
}
|
|
34
|
+
declare const RunFrame: (props: Props) => react_jsx_runtime.JSX.Element;
|
|
35
|
+
|
|
36
|
+
export { RunFrame };
|
package/dist/runner.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CircuitJsonPreview
|
|
3
|
+
} from "./chunk-YW33LMDL.js";
|
|
4
|
+
|
|
5
|
+
// lib/components/RunFrame.tsx
|
|
6
|
+
import { createCircuitWebWorker } from "@tscircuit/eval-webworker";
|
|
7
|
+
import { useEffect, useState } from "react";
|
|
8
|
+
import evalWebWorkerBlobUrl from "@tscircuit/eval-webworker/blob-url";
|
|
9
|
+
import { jsx } from "react/jsx-runtime";
|
|
10
|
+
var RunFrame = (props) => {
|
|
11
|
+
const [circuitJson, setCircuitJson] = useState(null);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
async function runWorker() {
|
|
14
|
+
const worker = await createCircuitWebWorker({
|
|
15
|
+
webWorkerUrl: evalWebWorkerBlobUrl,
|
|
16
|
+
verbose: true
|
|
17
|
+
});
|
|
18
|
+
const $finished = worker.executeWithFsMap({
|
|
19
|
+
entrypoint: props.entrypoint,
|
|
20
|
+
fsMap: props.fsMap
|
|
21
|
+
});
|
|
22
|
+
console.log("waiting for execution to finish...");
|
|
23
|
+
await $finished;
|
|
24
|
+
console.log("waiting for initial circuit json...");
|
|
25
|
+
setCircuitJson(await worker.getCircuitJson());
|
|
26
|
+
console.log("got initial circuit json");
|
|
27
|
+
await $finished.catch((e) => {
|
|
28
|
+
console.error(e);
|
|
29
|
+
});
|
|
30
|
+
setCircuitJson(await worker.getCircuitJson());
|
|
31
|
+
}
|
|
32
|
+
runWorker();
|
|
33
|
+
}, [props.fsMap]);
|
|
34
|
+
console.log({ circuitJson });
|
|
35
|
+
return /* @__PURE__ */ jsx(CircuitJsonPreview, { circuitJson });
|
|
36
|
+
};
|
|
37
|
+
export {
|
|
38
|
+
CircuitJsonPreview,
|
|
39
|
+
RunFrame
|
|
40
|
+
};
|
package/package.json
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
"name": "@tscircuit/runframe",
|
|
3
3
|
"main": "dist/index.js",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.7",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"start": "cosmos",
|
|
8
|
-
"build": "bun run build:lib",
|
|
9
|
-
"build:lib": "
|
|
8
|
+
"build": "bun run build:css && bun run build:standalone && bun run build:lib",
|
|
9
|
+
"build:lib": "tsup-node lib/preview.ts lib/runner.ts --platform browser --format esm --dts",
|
|
10
10
|
"build:css": "bun run scripts/build-css.ts",
|
|
11
11
|
"build:site": "cosmos-export",
|
|
12
12
|
"build:standalone": "STANDALONE=1 vite build",
|
|
13
|
+
"analyze": "source-map-explorer 'dist/standalone.min.js'",
|
|
13
14
|
"format:check": "biome format .",
|
|
14
15
|
"format": "biome format --write .",
|
|
15
16
|
"vercel-build": "bun run build:css && cosmos-export"
|
|
@@ -25,6 +26,8 @@
|
|
|
25
26
|
"react": "18",
|
|
26
27
|
"react-cosmos": "^6.2.1",
|
|
27
28
|
"react-dom": "18",
|
|
29
|
+
"rollup-plugin-visualizer": "^5.12.0",
|
|
30
|
+
"source-map-explorer": "^2.5.3",
|
|
28
31
|
"tailwindcss": "^3.4.16",
|
|
29
32
|
"tsup": "^8.3.5",
|
|
30
33
|
"vite": "^6.0.3"
|
package/vite.config.ts
CHANGED
|
@@ -3,6 +3,7 @@ import react from "@vitejs/plugin-react"
|
|
|
3
3
|
import { resolve } from "node:path"
|
|
4
4
|
import winterspecBundle from "@tscircuit/file-server/dist/bundle"
|
|
5
5
|
import { getNodeHandler } from "winterspec/adapters/node"
|
|
6
|
+
import { visualizer } from "rollup-plugin-visualizer"
|
|
6
7
|
|
|
7
8
|
const fakeHandler = getNodeHandler(winterspecBundle as any, {})
|
|
8
9
|
|
|
@@ -24,13 +25,21 @@ function apiServerPlugin(): Plugin {
|
|
|
24
25
|
|
|
25
26
|
const plugins: any[] = [react()]
|
|
26
27
|
|
|
27
|
-
if (!process.env.VERCEL) {
|
|
28
|
+
if (!process.env.VERCEL && !process.env.STANDALONE) {
|
|
28
29
|
plugins.push(apiServerPlugin())
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
let build: any = undefined
|
|
32
33
|
|
|
33
34
|
if (process.env.STANDALONE) {
|
|
35
|
+
// plugins.push(
|
|
36
|
+
// visualizer({
|
|
37
|
+
// filename: "stats.html",
|
|
38
|
+
// open: true, // Will open the stats.html file after build
|
|
39
|
+
// gzipSize: true,
|
|
40
|
+
// brotliSize: true,
|
|
41
|
+
// }),
|
|
42
|
+
// )
|
|
34
43
|
build = {
|
|
35
44
|
lib: {
|
|
36
45
|
entry: resolve(__dirname, "src/main.tsx"),
|
|
@@ -39,6 +48,7 @@ if (process.env.STANDALONE) {
|
|
|
39
48
|
formats: ["umd"],
|
|
40
49
|
},
|
|
41
50
|
minify: true,
|
|
51
|
+
// reportCompressedSize: true,
|
|
42
52
|
}
|
|
43
53
|
}
|
|
44
54
|
|