@tscircuit/fake-snippets 0.0.66 → 0.0.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/bun-tests/fake-snippets-api/fixtures/get-circuit-json.ts +5 -143
  2. package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +1 -4
  3. package/bun-tests/fake-snippets-api/fixtures/start-server.ts +7 -3
  4. package/bun-tests/fake-snippets-api/routes/order_quotes/create.test.ts +20 -56
  5. package/bun-tests/fake-snippets-api/routes/package_files/create_or_update.test.ts +2 -2
  6. package/bun-tests/fake-snippets-api/routes/package_releases/update.test.ts +1 -1
  7. package/bun-tests/fake-snippets-api/routes/packages/images.test.ts +0 -11
  8. package/bun.lock +26 -75
  9. package/dist/bundle.js +32 -39
  10. package/fake-snippets-api/routes/api/order_quotes/create.ts +30 -37
  11. package/fake-snippets-api/routes/api/order_quotes/get.ts +5 -8
  12. package/package.json +4 -4
  13. package/src/App.tsx +0 -11
  14. package/src/ContextProviders.tsx +2 -0
  15. package/src/components/CmdKMenu.tsx +19 -19
  16. package/src/components/DownloadButtonAndMenu.tsx +1 -4
  17. package/src/components/FAQ.tsx +3 -1
  18. package/src/components/FileSidebar.tsx +50 -1
  19. package/src/components/Footer.tsx +5 -2
  20. package/src/components/Header2.tsx +20 -9
  21. package/src/components/HeaderLogin.tsx +37 -54
  22. package/src/components/ImageWithFallback.tsx +37 -0
  23. package/src/components/JLCPCBImportDialog.tsx +45 -29
  24. package/src/components/PackageCard.tsx +2 -2
  25. package/src/components/{SnippetLink.tsx → PackageLink.tsx} +8 -16
  26. package/src/components/PackageSearchResults.tsx +87 -0
  27. package/src/components/PackagesList.tsx +3 -3
  28. package/src/components/PageSearchComponent.tsx +9 -9
  29. package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +5 -28
  30. package/src/components/ViewPackagePage/components/important-files-view.tsx +1 -1
  31. package/src/components/ViewPackagePage/components/main-content-header.tsx +8 -8
  32. package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +24 -14
  33. package/src/components/ViewPackagePage/components/package-header.tsx +7 -2
  34. package/src/components/dialogs/confirm-delete-package-dialog.tsx +8 -0
  35. package/src/components/dialogs/edit-package-details-dialog.tsx +145 -138
  36. package/src/components/package-port/CodeAndPreview.tsx +40 -19
  37. package/src/components/package-port/CodeEditor.tsx +21 -37
  38. package/src/components/package-port/CodeEditorHeader.tsx +1 -1
  39. package/src/components/package-port/EditorNav.tsx +3 -13
  40. package/src/hooks/use-global-store.ts +1 -0
  41. package/src/hooks/use-shiki-highlighter.ts +13 -6
  42. package/src/hooks/useFileManagement.ts +59 -0
  43. package/src/lib/download-fns/download-gltf.ts +3 -10
  44. package/src/lib/handleManualEditsImport.tsx +1 -1
  45. package/src/lib/types.ts +4 -2
  46. package/src/lib/utils/isValidFileName.ts +5 -0
  47. package/src/pages/dashboard.tsx +4 -4
  48. package/src/pages/editor.tsx +20 -14
  49. package/src/pages/latest.tsx +25 -26
  50. package/src/pages/quickstart.tsx +5 -5
  51. package/src/pages/search.tsx +121 -20
  52. package/src/pages/trending.tsx +14 -58
  53. package/src/pages/user-profile.tsx +14 -8
  54. package/bun-tests/fake-snippets-api/routes/snippets/add_star.test.ts +0 -84
  55. package/bun-tests/fake-snippets-api/routes/snippets/create.test.ts +0 -53
  56. package/bun-tests/fake-snippets-api/routes/snippets/delete.test.ts +0 -82
  57. package/bun-tests/fake-snippets-api/routes/snippets/download.test.ts +0 -90
  58. package/bun-tests/fake-snippets-api/routes/snippets/generate_from_jlcpcb.test.ts +0 -16
  59. package/bun-tests/fake-snippets-api/routes/snippets/get.test.ts +0 -163
  60. package/bun-tests/fake-snippets-api/routes/snippets/get_image.test.ts +0 -117
  61. package/bun-tests/fake-snippets-api/routes/snippets/images.test.ts +0 -114
  62. package/bun-tests/fake-snippets-api/routes/snippets/list.test.ts +0 -169
  63. package/bun-tests/fake-snippets-api/routes/snippets/list_newest.test.ts +0 -50
  64. package/bun-tests/fake-snippets-api/routes/snippets/list_trending.test.ts +0 -72
  65. package/bun-tests/fake-snippets-api/routes/snippets/remove_star.test.ts +0 -80
  66. package/bun-tests/fake-snippets-api/routes/snippets/search.test.ts +0 -75
  67. package/bun-tests/fake-snippets-api/routes/snippets/star-count.test.ts +0 -51
  68. package/bun-tests/fake-snippets-api/routes/snippets/update.test.ts +0 -175
  69. package/src/components/AiChatInterface.tsx +0 -229
  70. package/src/components/CodeAndPreview.tsx +0 -289
  71. package/src/components/CodeEditor.tsx +0 -539
  72. package/src/components/CodeEditorHeader.tsx +0 -135
  73. package/src/components/EditorNav.tsx +0 -502
  74. package/src/components/OrderPreviewContent.tsx +0 -61
  75. package/src/components/PreviewContent.tsx +0 -372
  76. package/src/components/SnippetCard.tsx +0 -159
  77. package/src/components/SnippetList.tsx +0 -71
  78. package/src/components/ViewSnippetSidebar.tsx +0 -162
  79. package/src/components/dialogs/create-order-dialog.tsx +0 -146
  80. package/src/hooks/use-compiled-tsx.ts +0 -37
  81. package/src/hooks/use-run-tsx/construct-circuit.tsx +0 -62
  82. package/src/hooks/use-run-tsx/index.tsx +0 -256
  83. package/src/hooks/use-save-snippet.ts +0 -66
  84. package/src/hooks/use-typecheck.ts +0 -54
  85. package/src/lib/utils/getSyntaxError.ts +0 -13
  86. package/src/pages/ai.tsx +0 -92
  87. package/src/pages/preview.tsx +0 -44
  88. package/src/pages/view-order.tsx +0 -111
  89. package/src/pages/view-snippet.tsx +0 -166
@@ -1,162 +0,0 @@
1
- import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard"
2
- import { useCurrentSnippet } from "@/hooks/use-current-snippet"
3
- import { useToast } from "@/hooks/use-toast"
4
- import { cn } from "@/lib/utils"
5
- import { AtSign, Bot, Clock, Code, File, GitFork, Package } from "lucide-react"
6
- import { useFilesDialog } from "./dialogs/files-dialog"
7
- import { PrefetchPageLink } from "./PrefetchPageLink"
8
-
9
- export default function ViewSnippetSidebar({
10
- className,
11
- }: {
12
- className?: string
13
- }) {
14
- const { snippet } = useCurrentSnippet()
15
- const { toast } = useToast()
16
- const { Dialog: FilesDialog, openDialog: openFilesDialog } = useFilesDialog()
17
- const { copyToClipboard } = useCopyToClipboard()
18
-
19
- return (
20
- <div
21
- className={cn(
22
- "w-64 h-full bg-gray-100 text-gray-700 flex flex-col flex-shrink-0",
23
- "hidden sm:block h-screen sticky top-0",
24
- className,
25
- )}
26
- >
27
- <nav className="flex-grow overflow-y-auto">
28
- <ul className="p-2 space-y-2">
29
- {[
30
- {
31
- icon: <Code className="w-5 h-5" />,
32
- label: "Edit Code",
33
- href: `/editor?snippet_id=${snippet?.snippet_id}`,
34
- },
35
- {
36
- icon: <Bot className="w-5 h-5" />,
37
- label: "Edit with AI",
38
- badge: "AI",
39
- href: `/ai?snippet_id=${snippet?.snippet_id}`,
40
- },
41
- // {
42
- // icon: <GitHubLogoIcon className="w-5 h-5" />,
43
- // label: "Github",
44
- // },
45
- {
46
- icon: <GitFork className="w-5 h-5" />,
47
- label: "Forks",
48
- notImplemented: true,
49
- },
50
- {
51
- icon: <AtSign className="w-5 h-5" />,
52
- label: "References",
53
- notImplemented: true,
54
- },
55
- {
56
- icon: <Package className="w-5 h-5" />,
57
- label: "Dependencies",
58
- notImplemented: true,
59
- },
60
- {
61
- icon: <Clock className="w-5 h-5" />,
62
- label: "Versions",
63
- notImplemented: true,
64
- },
65
- {
66
- icon: <File className="w-5 h-5" />,
67
- label: "Files",
68
- onClick: () => {
69
- if (snippet) {
70
- openFilesDialog()
71
- }
72
- },
73
- },
74
- // { icon: <Settings className="w-5 h-5" />, label: "Settings" },
75
- ].map((item, index) => (
76
- <li key={index}>
77
- <PrefetchPageLink
78
- href={item.href ?? "#"}
79
- onClick={
80
- item.notImplemented
81
- ? () => {
82
- toast({
83
- title: "Not Implemented!",
84
- description: (
85
- <div>
86
- The {item.label} selection is not implemented yet.
87
- Help us out!{" "}
88
- <a
89
- className="text-blue-500 hover:underline font-semibold"
90
- href="https://github.com/tscircuit/tscircuit.com"
91
- >
92
- Check out our Github
93
- </a>
94
- </div>
95
- ),
96
- })
97
- }
98
- : item.onClick
99
- }
100
- className="flex items-center gap-3 px-2 py-1.5 hover:bg-gray-200 rounded-md"
101
- >
102
- {item.icon}
103
- <span className="text-sm">{item.label}</span>
104
- {item.badge && (
105
- <span className="ml-auto bg-blue-500 text-white text-xs px-1.5 py-0.5 rounded">
106
- {item.badge}
107
- </span>
108
- )}
109
- </PrefetchPageLink>
110
- </li>
111
- ))}
112
- </ul>
113
- </nav>
114
- <div className="p-4 border-t border-gray-200 space-y-4">
115
- <div className="space-y-1">
116
- <div className="text-xs font-medium">Copy embed code</div>
117
- <div
118
- className="text-[0.5em] p-2 rounded-sm bg-blue-50 border border-blue-200 cursor-pointer font-mono whitespace-nowrap overflow-hidden text-ellipsis"
119
- onClick={() => {
120
- const embedCode = `<iframe src="${window.location.origin}/preview?snippet_id=${snippet?.snippet_id}" width="100%" height="500" frameborder="0"></iframe>`
121
- navigator.clipboard.writeText(embedCode)
122
- toast({
123
- title: "Copied!",
124
- description: "Embed code copied to clipboard",
125
- })
126
- }}
127
- >
128
- {`<iframe src="${window.location.origin}/preview?snippet_id=${snippet?.snippet_id}" width="100%" height="500" frameborder="0"></iframe>`}
129
- </div>
130
- </div>
131
- <div className="space-y-1">
132
- <div className="text-xs font-medium">Copy import code</div>
133
- <div
134
- className="text-[0.5em] p-2 rounded-sm bg-blue-50 border border-blue-200 cursor-pointer font-mono whitespace-nowrap overflow-hidden text-ellipsis"
135
- onClick={() =>
136
- copyToClipboard(
137
- `import CircuitModule from "@tsci/${snippet?.owner_name}.${snippet?.unscoped_name}"`,
138
- )
139
- }
140
- >
141
- import CircuitModule from "@tsci/{snippet?.owner_name}.
142
- {snippet?.unscoped_name}"
143
- </div>
144
- </div>
145
- <div className="space-y-1">
146
- <div className="text-xs font-medium">Copy install command</div>
147
- <div
148
- className="text-[0.5em] p-2 rounded-sm bg-blue-50 border border-blue-200 cursor-pointer font-mono whitespace-nowrap overflow-hidden text-ellipsis"
149
- onClick={() =>
150
- copyToClipboard(
151
- `tsci add @tsci/${snippet?.owner_name}.${snippet?.unscoped_name}`,
152
- )
153
- }
154
- >
155
- tsci add @tsci/{snippet?.owner_name}.{snippet?.unscoped_name}
156
- </div>
157
- </div>
158
- </div>
159
- {snippet && <FilesDialog snippetId={snippet.snippet_id} />}
160
- </div>
161
- )
162
- }
@@ -1,146 +0,0 @@
1
- import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog"
2
- import { Button } from "../ui/button"
3
- import { Checkbox } from "../ui/checkbox"
4
- import { useState, useEffect } from "react"
5
- import { createUseDialog } from "./create-use-dialog"
6
- import { useAxios } from "@/hooks/use-axios"
7
- import { useToast } from "@/hooks/use-toast"
8
- import { useQueryClient } from "react-query"
9
-
10
- export const CreateOrderDialog = ({
11
- open,
12
- onOpenChange,
13
- }: {
14
- open: boolean
15
- onOpenChange: (open: boolean) => void
16
- }) => {
17
- const axios = useAxios()
18
- const { toast } = useToast()
19
- const qc = useQueryClient()
20
- const [pending, setPending] = useState(false)
21
- const [checkpoints, setCheckpoints] = useState({
22
- shipping: false,
23
- errors: false,
24
- parts: false,
25
- })
26
-
27
- useEffect(() => {
28
- if (open) {
29
- validateCheckpoints()
30
- }
31
- }, [open])
32
-
33
- const validateCheckpoints = async () => {
34
- try {
35
- // Placeholder: Check if shipping information is in profile
36
- const hasShippingInfo = await checkShippingInfo()
37
-
38
- // Placeholder: Check if PCB has no errors
39
- const hasNoErrors = await checkPCBErrors()
40
-
41
- // Placeholder: Check if all parts are available at PCB fab
42
- const allPartsAvailable = await checkPartsAvailability()
43
-
44
- setCheckpoints({
45
- shipping: hasShippingInfo,
46
- errors: hasNoErrors,
47
- parts: allPartsAvailable,
48
- })
49
- } catch (error) {
50
- console.error("Error validating checkpoints:", error)
51
- }
52
- }
53
-
54
- const checkShippingInfo = async () => {
55
- // Placeholder: Implement actual check for shipping info
56
- return true
57
- }
58
-
59
- const checkPCBErrors = async () => {
60
- // Placeholder: Implement actual check for PCB errors
61
- return true
62
- }
63
-
64
- const checkPartsAvailability = async () => {
65
- // Placeholder: Implement actual check for parts availability
66
- return true
67
- }
68
-
69
- const handleSubmit = async () => {
70
- try {
71
- setPending(true)
72
- // TODO: Implement order submission logic
73
- onOpenChange(false)
74
- setPending(false)
75
- toast({
76
- title: "Order submitted",
77
- description: "Your order has been successfully submitted.",
78
- })
79
- qc.invalidateQueries({ queryKey: ["orders"] })
80
- } catch (error) {
81
- console.error("Error submitting order:", error)
82
- toast({
83
- title: "Error",
84
- description: "Failed to submit the order. Please try again.",
85
- variant: "destructive",
86
- })
87
- } finally {
88
- setPending(false)
89
- }
90
- }
91
-
92
- return (
93
- <Dialog open={open} onOpenChange={onOpenChange}>
94
- <DialogContent>
95
- <DialogHeader>
96
- <DialogTitle>Create Order</DialogTitle>
97
- </DialogHeader>
98
- <p className="text-sm text-gray-500 mb-4">
99
- Order the circuit board fully assembled from a PCB fabricator
100
- </p>
101
- <div className="space-y-4">
102
- <div className="flex items-center space-x-2">
103
- <Checkbox id="shipping" checked={checkpoints.shipping} />
104
- <label
105
- htmlFor="shipping"
106
- className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
107
- >
108
- Shipping Information in Profile
109
- </label>
110
- </div>
111
- <div className="flex items-center space-x-2">
112
- <Checkbox id="errors" checked={checkpoints.errors} />
113
- <label
114
- htmlFor="errors"
115
- className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
116
- >
117
- PCB Has No Errors
118
- </label>
119
- </div>
120
- <div className="flex items-center space-x-2">
121
- <Checkbox id="parts" checked={checkpoints.parts} />
122
- <label
123
- htmlFor="parts"
124
- className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
125
- >
126
- All parts available at PCB fabricator
127
- </label>
128
- </div>
129
- </div>
130
- <div className="flex justify-end space-x-2 mt-4">
131
- <Button variant="outline" onClick={() => onOpenChange(false)}>
132
- Cancel
133
- </Button>
134
- <Button
135
- onClick={handleSubmit}
136
- disabled={pending || !Object.values(checkpoints).every(Boolean)}
137
- >
138
- {pending ? "Submitting..." : "Submit Order"}
139
- </Button>
140
- </div>
141
- </DialogContent>
142
- </Dialog>
143
- )
144
- }
145
-
146
- export const useCreateOrderDialog = createUseDialog(CreateOrderDialog)
@@ -1,37 +0,0 @@
1
- import { useMemo } from "react"
2
- import * as Babel from "@babel/standalone"
3
-
4
- export const safeCompileTsx = (
5
- code: string,
6
- ):
7
- | { success: true; compiledTsx: string; error?: undefined }
8
- | { success: false; error: Error; compiledTsx?: undefined } => {
9
- try {
10
- return {
11
- success: true,
12
- compiledTsx:
13
- Babel.transform(code, {
14
- presets: ["react", "typescript"],
15
- plugins: ["transform-modules-commonjs"],
16
- filename: "virtual.tsx",
17
- }).code || "",
18
- }
19
- } catch (error: any) {
20
- return { success: false, error }
21
- }
22
- }
23
-
24
- export const useCompiledTsx = (
25
- code?: string,
26
- { isStreaming = false }: { isStreaming?: boolean } = {},
27
- ) => {
28
- return useMemo(() => {
29
- if (!code) return ""
30
- if (isStreaming) return ""
31
- const result = safeCompileTsx(code)
32
- if (result.success) {
33
- return result.compiledTsx
34
- }
35
- return `Error: ${result.error.message}`
36
- }, [code, isStreaming])
37
- }
@@ -1,62 +0,0 @@
1
- import { Circuit } from "@tscircuit/core"
2
- import { useEffect, useMemo, useState } from "react"
3
- import * as React from "react"
4
- import { useCompiledTsx } from "../use-compiled-tsx"
5
- import { createJSCADRenderer } from "jscad-fiber"
6
- import { jscadPlanner } from "jscad-planner"
7
-
8
- export const constructCircuit = ({
9
- UserElm,
10
- type,
11
- circuitDisplayName,
12
- }: {
13
- UserElm: any
14
- type: "board" | "footprint" | "package" | "model"
15
- circuitDisplayName?: string
16
- }) => {
17
- const circuit = new Circuit()
18
-
19
- if (circuitDisplayName) {
20
- circuit.name = circuitDisplayName
21
- }
22
-
23
- if (type === "board") {
24
- circuit.add(<UserElm />)
25
- // HACK: switch to selectOne when root fixes bug with selecting board
26
- const board = circuit.root?.children[0]
27
- // const board = circuit.selectOne("board")
28
- if (board) {
29
- board.setProps({
30
- ...board.props,
31
- })
32
- }
33
- } else if (type === "package") {
34
- circuit.add(
35
- <board width="50mm" height="50mm">
36
- <UserElm name="U1" />
37
- </board>,
38
- )
39
- } else if (type === "footprint") {
40
- circuit.add(
41
- <board width="10mm" height="10mm">
42
- <chip name="U1" footprint={<UserElm />} />
43
- </board>,
44
- )
45
- } else if (type === "model") {
46
- const jscadGeoms: any[] = []
47
- const { createJSCADRoot } = createJSCADRenderer(jscadPlanner as any)
48
- const jscadRoot = createJSCADRoot(jscadGeoms)
49
- jscadRoot.render(<UserElm />)
50
- circuit.add(
51
- <board width="10mm" height="10mm">
52
- <chip
53
- name="U1"
54
- cadModel={{
55
- jscad: jscadGeoms[0],
56
- }}
57
- />
58
- </board>,
59
- )
60
- }
61
- return circuit
62
- }
@@ -1,256 +0,0 @@
1
- import * as tscircuitCore from "@tscircuit/core"
2
- import { getImportsFromCode } from "@tscircuit/prompt-benchmarks/code-runner-utils"
3
- import type { AnyCircuitElement } from "circuit-json"
4
- import * as jscadFiber from "jscad-fiber"
5
- import * as React from "react"
6
- import * as tscircuitMathUtils from "@tscircuit/math-utils"
7
- import { useEffect, useMemo, useReducer, useRef, useState } from "react"
8
- import { safeCompileTsx } from "../use-compiled-tsx"
9
- import { useSnippetsBaseApiUrl } from "../use-snippets-base-api-url"
10
- import { constructCircuit } from "./construct-circuit"
11
- import { evalCompiledJs } from "./eval-compiled-js"
12
- import { getSyntaxError } from "@/lib/utils/getSyntaxError"
13
-
14
- type RunTsxResult = {
15
- compiledModule: any
16
- message: string
17
- circuitJson: AnyCircuitElement[] | null
18
- compiledJs?: string
19
- isRunningCode: boolean
20
- }
21
-
22
- /**
23
- * @deprecated will be removed in future version, use @tscircuit/eval or
24
- * @tscircuit/runframe
25
- */
26
- export const useRunTsx = ({
27
- code,
28
- userImports,
29
- type,
30
- isStreaming = false,
31
- circuitDisplayName,
32
- }: {
33
- code?: string
34
- userImports?: Record<string, object>
35
- type?: "board" | "footprint" | "package" | "model"
36
- isStreaming?: boolean
37
- circuitDisplayName?: string
38
- } = {}): RunTsxResult & {
39
- circuitJsonKey: string
40
- triggerRunTsx: () => void
41
- tsxRunTriggerCount: number
42
- } => {
43
- type ??= "board"
44
- const [tsxRunTriggerCount, incTsxRunTriggerCount] = useReducer(
45
- (c) => c + 1,
46
- 0,
47
- )
48
- const [tsxResult, setTsxResult] = useState<RunTsxResult>({
49
- compiledModule: null,
50
- message: "",
51
- circuitJson: null,
52
- isRunningCode: false,
53
- })
54
- const apiBaseUrl = useSnippetsBaseApiUrl()
55
- const preSuppliedImportsRef = useRef<Record<string, any>>({})
56
-
57
- useEffect(() => {
58
- if (tsxRunTriggerCount === 0) return
59
- if (isStreaming) {
60
- setTsxResult({
61
- compiledModule: null,
62
- message: "",
63
- circuitJson: null,
64
- isRunningCode: false,
65
- })
66
- }
67
- if (!code) return
68
- const syntaxError = getSyntaxError(code)
69
- if (syntaxError) {
70
- setTsxResult({
71
- compiledModule: null,
72
- message: syntaxError,
73
- circuitJson: null,
74
- isRunningCode: false,
75
- })
76
- return
77
- }
78
- async function run() {
79
- setTsxResult({
80
- compiledModule: null,
81
- message: "",
82
- circuitJson: null,
83
- isRunningCode: true,
84
- })
85
-
86
- const userCodeTsciImports = getImportsFromCode(code!).filter((imp) =>
87
- imp.startsWith("@tsci/"),
88
- )
89
-
90
- const preSuppliedImports: Record<string, any> =
91
- preSuppliedImportsRef.current
92
-
93
- for (const [importName, importValue] of Object.entries(
94
- userImports ?? {},
95
- )) {
96
- preSuppliedImports[importName] = importValue
97
- }
98
-
99
- const __tscircuit_require = (name: string) => {
100
- if (
101
- name === "./manual-edits.json" &&
102
- preSuppliedImports["./manual-edits.json"] === ""
103
- ) {
104
- return preSuppliedImports["./manual-edits.json"]
105
- }
106
- if (!preSuppliedImports[name]) {
107
- throw new Error(
108
- `Import "${name}" not found (imports available: ${Object.keys(preSuppliedImports).join(",")})`,
109
- )
110
- }
111
- return preSuppliedImports[name]
112
- }
113
- ;(globalThis as any).__tscircuit_require = __tscircuit_require
114
- preSuppliedImports["@tscircuit/core"] = tscircuitCore
115
- preSuppliedImports["tscircuit"] = tscircuitCore
116
- preSuppliedImports["@tscircuit/math-utils"] = tscircuitMathUtils
117
- preSuppliedImports["react"] = React
118
- preSuppliedImports["jscad-fiber"] = jscadFiber
119
- globalThis.React = React
120
-
121
- async function addImport(importName: string, depth = 0) {
122
- if (!importName.startsWith("@tsci/")) return
123
- if (preSuppliedImports[importName]) return
124
- if (depth > 5) {
125
- console.log("Max depth for imports reached")
126
- return
127
- }
128
-
129
- const fullSnippetName = importName
130
- .replace("@tsci/", "")
131
- .replace(".", "/")
132
- const { snippet: importedSnippet, error } = await fetch(
133
- `${apiBaseUrl}/snippets/get?name=${fullSnippetName}`,
134
- )
135
- .then((res) => res.json())
136
- .catch((e) => ({ error: e }))
137
-
138
- if (error) {
139
- console.error("Error fetching import", importName, error)
140
- return
141
- }
142
-
143
- const { compiled_js, code } = importedSnippet
144
-
145
- const importNames = getImportsFromCode(code!)
146
-
147
- for (const importName of importNames) {
148
- if (!preSuppliedImports[importName]) {
149
- await addImport(importName, depth + 1)
150
- }
151
- }
152
-
153
- try {
154
- preSuppliedImports[importName] = evalCompiledJs(compiled_js).exports
155
- } catch (e) {
156
- console.error("Error importing snippet", e)
157
- }
158
- }
159
-
160
- for (const userCodeTsciImport of userCodeTsciImports) {
161
- await addImport(userCodeTsciImport)
162
- }
163
-
164
- const { success, compiledTsx: compiledJs, error } = safeCompileTsx(code!)
165
-
166
- if (!success) {
167
- setTsxResult({
168
- compiledModule: null,
169
- message: `Compile Error: ${error.message}`,
170
- circuitJson: null,
171
- isRunningCode: false,
172
- })
173
- }
174
-
175
- try {
176
- const module = evalCompiledJs(compiledJs!)
177
-
178
- const componentExportKeys = Object.keys(module.exports).filter(
179
- (key) => !key.startsWith("use"),
180
- )
181
-
182
- if (componentExportKeys.length > 1) {
183
- throw new Error(
184
- `Too many exports, only export one component. You exported: ${JSON.stringify(Object.keys(module.exports))}`,
185
- )
186
- }
187
-
188
- const primaryKey = componentExportKeys[0]
189
-
190
- const UserElm = (props: any) =>
191
- React.createElement(module.exports[primaryKey], props)
192
-
193
- try {
194
- const circuit = constructCircuit({
195
- UserElm,
196
- type: type as any,
197
- circuitDisplayName,
198
- })
199
- const renderPromise = circuit.renderUntilSettled()
200
-
201
- // wait one tick to allow a single render pass
202
- await new Promise((resolve) => setTimeout(resolve, 1))
203
-
204
- let circuitJson = circuit.getCircuitJson()
205
- setTsxResult({
206
- compiledModule: module,
207
- compiledJs,
208
- message: "",
209
- circuitJson: circuitJson as AnyCircuitElement[],
210
- isRunningCode: true,
211
- })
212
-
213
- await renderPromise
214
-
215
- circuitJson = circuit.getCircuitJson()
216
- setTsxResult({
217
- compiledModule: module,
218
- compiledJs,
219
- message: "",
220
- circuitJson: circuitJson as AnyCircuitElement[],
221
- isRunningCode: false,
222
- })
223
- } catch (error: any) {
224
- console.error("Evaluation error:", error)
225
- setTsxResult({
226
- compiledModule: module,
227
- message: `Render Error: ${error.message}`,
228
- circuitJson: null,
229
- isRunningCode: false,
230
- })
231
- }
232
- } catch (error: any) {
233
- console.error("Evaluation error:", error)
234
- setTsxResult({
235
- compiledModule: null,
236
- message: `Eval Error: ${error.message}\n\n${error.stack}`,
237
- circuitJson: null,
238
- isRunningCode: false,
239
- })
240
- }
241
- }
242
- run()
243
- }, [tsxRunTriggerCount])
244
-
245
- const circuitJsonKey: string = useMemo(() => {
246
- if (!tsxResult.circuitJson) return ""
247
- return `cj-${Math.random().toString(36).substring(2, 15)}`
248
- }, [tsxResult.circuitJson, tsxResult.circuitJson?.length])
249
-
250
- return {
251
- ...tsxResult,
252
- circuitJsonKey: circuitJsonKey,
253
- triggerRunTsx: incTsxRunTriggerCount,
254
- tsxRunTriggerCount,
255
- }
256
- }