@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
@@ -16,6 +16,7 @@ import {
16
16
  Dialog,
17
17
  DialogContent,
18
18
  DialogDescription,
19
+ DialogFooter,
19
20
  DialogHeader,
20
21
  DialogTitle,
21
22
  } from "../ui/dialog"
@@ -217,151 +218,157 @@ export const EditPackageDetailsDialog = ({
217
218
  </DialogContent>
218
219
  </Dialog>
219
220
  <Dialog open={open !== showConfirmDelete} onOpenChange={onOpenChange}>
220
- <DialogContent className="sm:max-w-[500px] lg:h-[70vh] sm:h-[90vh] overflow-y-auto w-[95vw] p-6 gap-6 rounded-2xl shadow-lg">
221
- <DialogHeader>
222
- <DialogTitle>Edit Package Details</DialogTitle>
223
- <DialogDescription>
224
- Update your package’s description, website, visibility, or delete
225
- it.
226
- </DialogDescription>
227
- </DialogHeader>
221
+ <DialogContent className="sm:max-w-[500px] lg:h-[70vh] sm:h-[90vh] overflow-y-auto w-[95vw] h-[80vh] p-6 gap-6 rounded-2xl shadow-lg">
222
+ <div className="flex flex-col gap-10">
223
+ <DialogHeader>
224
+ <DialogTitle>Edit Package Details</DialogTitle>
225
+ <DialogDescription>
226
+ Update your package's description, website, visibility, or
227
+ delete it.
228
+ </DialogDescription>
229
+ </DialogHeader>
230
+ <div className="">
231
+ <div className="grid gap-2">
232
+ <div className="space-y-1">
233
+ <Label htmlFor="website">Website</Label>
234
+ <Input
235
+ id="website"
236
+ value={formData.website}
237
+ onChange={(e) =>
238
+ setFormData((prev) => ({
239
+ ...prev,
240
+ website: e.target.value,
241
+ }))
242
+ }
243
+ placeholder="https://example.com"
244
+ disabled={updatePackageDetailsMutation.isLoading}
245
+ className="w-full"
246
+ aria-invalid={!!websiteError}
247
+ />
248
+ {websiteError && (
249
+ <p className="text-sm text-red-500">{websiteError}</p>
250
+ )}
251
+ </div>
252
+ <div className="space-y-1">
253
+ <Label htmlFor="visibility">Visibility</Label>
254
+ <Select
255
+ value={formData.visibility}
256
+ onValueChange={(val) => {
257
+ setFormData((prev) => ({
258
+ ...prev,
259
+ visibility: val,
260
+ }))
261
+ }}
262
+ disabled={updatePackageDetailsMutation.isLoading}
263
+ >
264
+ <SelectTrigger className="w-full">
265
+ <SelectValue placeholder="Select visibility" />
266
+ </SelectTrigger>
267
+ <SelectContent className="!z-[999]">
268
+ <SelectItem value="public">public</SelectItem>
269
+ <SelectItem value="private">private</SelectItem>
270
+ </SelectContent>
271
+ </Select>
272
+ </div>
273
+ <div className="space-y-1">
274
+ <Label htmlFor="description">Description</Label>
275
+ <Textarea
276
+ id="description"
277
+ value={formData.description}
278
+ onChange={(e) =>
279
+ setFormData((prev) => ({
280
+ ...prev,
281
+ description: e.target.value,
282
+ }))
283
+ }
284
+ placeholder="Enter package description"
285
+ disabled={updatePackageDetailsMutation.isLoading}
286
+ className="w-full min-h-[80px] resize-none"
287
+ />
288
+ </div>
289
+ <div className="space-y-1">
290
+ <Label htmlFor="license">License</Label>
291
+ <Select
292
+ value={formData.license || "unset"}
293
+ onValueChange={(value) =>
294
+ setFormData((prev) => ({
295
+ ...prev,
296
+ license: value === "unset" ? null : value,
297
+ }))
298
+ }
299
+ disabled={updatePackageDetailsMutation.isLoading}
300
+ >
301
+ <SelectTrigger className="w-full">
302
+ <SelectValue placeholder="Select a license" />
303
+ </SelectTrigger>
304
+ <SelectContent className="!z-[999]">
305
+ <SelectItem value="MIT">MIT</SelectItem>
306
+ <SelectItem value="Apache-2.0">Apache-2.0</SelectItem>
307
+ <SelectItem value="BSD-3-Clause">BSD-3-Clause</SelectItem>
308
+ <SelectItem value="GPL-3.0">GPL-3.0</SelectItem>
309
+ <SelectItem value="unset">Unset</SelectItem>
310
+ </SelectContent>
311
+ </Select>
312
+ </div>
313
+ </div>
228
314
 
229
- <div className="grid gap-4">
230
- <div className="space-y-1">
231
- <Label htmlFor="website">Website</Label>
232
- <Input
233
- id="website"
234
- value={formData.website}
235
- onChange={(e) =>
236
- setFormData((prev) => ({
237
- ...prev,
238
- website: e.target.value,
239
- }))
240
- }
241
- placeholder="https://example.com"
242
- disabled={updatePackageDetailsMutation.isLoading}
243
- className="w-full"
244
- aria-invalid={!!websiteError}
245
- />
246
- {websiteError && (
247
- <p className="text-sm text-red-500">{websiteError}</p>
248
- )}
249
- </div>
250
- <div className="space-y-1">
251
- <Label htmlFor="visibility">Visibility</Label>
252
- <Select
253
- value={formData.visibility}
254
- onValueChange={(val) => {
255
- setFormData((prev) => ({
256
- ...prev,
257
- visibility: val,
258
- }))
259
- }}
260
- disabled={updatePackageDetailsMutation.isLoading}
315
+ <details
316
+ className="mt-2 rounded-md"
317
+ onToggle={(e) => setDangerOpen(e.currentTarget.open)}
261
318
  >
262
- <SelectTrigger className="w-full">
263
- <SelectValue placeholder="Select visibility" />
264
- </SelectTrigger>
265
- <SelectContent className="!z-[999]">
266
- <SelectItem value="public">public</SelectItem>
267
- <SelectItem value="private">private</SelectItem>
268
- </SelectContent>
269
- </Select>
319
+ <summary className="cursor-pointer p-2 font-medium text-sm text-black list-none flex justify-between items-center">
320
+ Danger Zone
321
+ <ChevronDown
322
+ className={`w-4 h-4 mr-1 transition-transform ${dangerOpen ? "rotate-180" : ""}`}
323
+ />
324
+ </summary>
325
+ <div className="p-2 pr-2">
326
+ <div className="flex justify-between items-center">
327
+ <div>
328
+ <p className="text-sm text-muted-foreground">
329
+ Once deleted, it cannot be recovered.
330
+ </p>
331
+ </div>
332
+ <Button
333
+ variant="destructive"
334
+ size="default"
335
+ onClick={() => setShowConfirmDelete(true)}
336
+ disabled={deleting}
337
+ className="shrink-0 lg:w-[115px] w-[70px]"
338
+ >
339
+ {deleting ? "Deleting..." : "Delete"}
340
+ </Button>
341
+ </div>
342
+ </div>
343
+ </details>
270
344
  </div>
271
- <div className="space-y-1">
272
- <Label htmlFor="description">Description</Label>
273
- <Textarea
274
- id="description"
275
- value={formData.description}
276
- onChange={(e) =>
277
- setFormData((prev) => ({
278
- ...prev,
279
- description: e.target.value,
280
- }))
281
- }
282
- placeholder="Enter package description"
345
+ </div>
346
+
347
+ <DialogFooter className="mt-auto">
348
+ <div className="lg:px-2 flex flex-col sm:flex-row justify-end gap-2">
349
+ <Button
350
+ variant="outline"
351
+ onClick={() => onOpenChange(false)}
283
352
  disabled={updatePackageDetailsMutation.isLoading}
284
- className="w-full min-h-[100px] resize-none"
285
- />
286
- </div>
287
- <div className="space-y-1">
288
- <Label htmlFor="license">License</Label>
289
- <Select
290
- value={formData.license || "unset"}
291
- onValueChange={(value) =>
292
- setFormData((prev) => ({
293
- ...prev,
294
- license: value === "unset" ? null : value,
295
- }))
353
+ className="sm:w-auto w-full"
354
+ >
355
+ Cancel
356
+ </Button>
357
+ <Button
358
+ onClick={() => updatePackageDetailsMutation.mutate()}
359
+ disabled={
360
+ updatePackageDetailsMutation.isLoading ||
361
+ !hasChanges ||
362
+ !isFormValid
296
363
  }
297
- disabled={updatePackageDetailsMutation.isLoading}
364
+ className="sm:w-auto lg:w-[115px]"
298
365
  >
299
- <SelectTrigger className="w-full">
300
- <SelectValue placeholder="Select a license" />
301
- </SelectTrigger>
302
- <SelectContent className="!z-[999]">
303
- <SelectItem value="MIT">MIT</SelectItem>
304
- <SelectItem value="Apache-2.0">Apache-2.0</SelectItem>
305
- <SelectItem value="BSD-3-Clause">BSD-3-Clause</SelectItem>
306
- <SelectItem value="GPL-3.0">GPL-3.0</SelectItem>
307
- <SelectItem value="unset">Unset</SelectItem>
308
- </SelectContent>
309
- </Select>
310
- </div>
311
- </div>
312
- <details
313
- className="mt-2 rounded-md"
314
- onToggle={(e) => setDangerOpen(e.currentTarget.open)}
315
- >
316
- <summary className="cursor-pointer p-2 font-medium text-sm text-black list-none flex justify-between items-center">
317
- Danger Zone
318
- <ChevronDown
319
- className={`w-4 h-4 mr-1 transition-transform ${dangerOpen ? "rotate-180" : ""}`}
320
- />
321
- </summary>
322
- <div className="p-2 pr-2">
323
- <div className="flex justify-between items-center">
324
- <div>
325
- <p className="text-sm text-muted-foreground">
326
- Once deleted, it cannot be recovered.
327
- </p>
328
- </div>
329
- <Button
330
- variant="destructive"
331
- size="default"
332
- onClick={() => setShowConfirmDelete(true)}
333
- disabled={deleting}
334
- className="shrink-0 lg:w-[115px] w-[70px]"
335
- >
336
- {deleting ? "Deleting..." : "Delete"}
337
- </Button>
338
- </div>
366
+ {updatePackageDetailsMutation.isLoading
367
+ ? "Updating..."
368
+ : "Save Changes"}
369
+ </Button>
339
370
  </div>
340
- </details>
341
-
342
- <div className=" lg:px-2 flex flex-col sm:flex-row justify-end gap-3">
343
- <Button
344
- variant="outline"
345
- onClick={() => onOpenChange(false)}
346
- disabled={updatePackageDetailsMutation.isLoading}
347
- className="sm:w-auto w-full"
348
- >
349
- Cancel
350
- </Button>
351
- <Button
352
- onClick={() => updatePackageDetailsMutation.mutate()}
353
- disabled={
354
- updatePackageDetailsMutation.isLoading ||
355
- !hasChanges ||
356
- !isFormValid
357
- }
358
- className="sm:w-auto lg:w-[115px]"
359
- >
360
- {updatePackageDetailsMutation.isLoading
361
- ? "Updating..."
362
- : "Save Changes"}
363
- </Button>
364
- </div>
371
+ </DialogFooter>
365
372
  </DialogContent>
366
373
  </Dialog>
367
374
  </div>
@@ -22,6 +22,8 @@ import { usePackageFilesLoader } from "@/hooks/usePackageFilesLoader"
22
22
  import { findTargetFile } from "@/lib/utils/findTargetFile"
23
23
  import { toastManualEditConflicts } from "@/lib/utils/toastManualEditConflicts"
24
24
  import { ManualEditEvent } from "@tscircuit/props"
25
+ import { isValidFileName } from "@/lib/utils/isValidFileName"
26
+ import { useFileManagement } from "@/hooks/useFileManagement"
25
27
 
26
28
  interface Props {
27
29
  pkg?: Package
@@ -32,12 +34,19 @@ export interface PackageFile {
32
34
  content: string
33
35
  }
34
36
 
35
- interface CodeAndPreviewState {
37
+ export interface CreateFileProps {
38
+ newFileName: string
39
+ setErrorMessage: (message: string) => void
40
+ onFileSelect: (fileName: string) => void
41
+ setNewFileName: (fileName: string) => void
42
+ setIsCreatingFile: (isCreatingFile: boolean) => void
43
+ }
44
+
45
+ export interface CodeAndPreviewState {
36
46
  pkgFilesWithContent: PackageFile[]
37
47
  initialFilesLoad: PackageFile[]
38
48
  showPreview: boolean
39
49
  fullScreen: boolean
40
- dts: string
41
50
  lastSavedAt: number
42
51
  circuitJson: null | any
43
52
  isPrivate: boolean
@@ -92,7 +101,6 @@ export function CodeAndPreview({ pkg }: Props) {
92
101
  initialFilesLoad: [],
93
102
  showPreview: true,
94
103
  fullScreen: false,
95
- dts: "",
96
104
  lastSavedAt: Date.now(),
97
105
  circuitJson: null,
98
106
  isPrivate: false,
@@ -148,7 +156,6 @@ export function CodeAndPreview({ pkg }: Props) {
148
156
 
149
157
  if (loadedFiles && !isLoadingFiles) {
150
158
  const processedResults = [...loadedFiles]
151
-
152
159
  setState((prev) => ({
153
160
  ...prev,
154
161
  pkgFilesWithContent: processedResults,
@@ -159,13 +166,7 @@ export function CodeAndPreview({ pkg }: Props) {
159
166
  defaultCode,
160
167
  }))
161
168
  }
162
- }, [
163
- isLoadingFiles,
164
- pkg,
165
- pkgFiles.data,
166
- state.pkgFilesWithContent.length,
167
- defaultCode,
168
- ])
169
+ }, [isLoadingFiles, pkg, pkgFiles.data, defaultCode])
169
170
 
170
171
  const createPackageMutation = useCreatePackageMutation()
171
172
  const { mutate: createRelease } = useCreatePackageReleaseMutation({
@@ -250,10 +251,21 @@ export function CodeAndPreview({ pkg }: Props) {
250
251
  setState((prev) => ({ ...prev, lastSavedAt: Date.now() }))
251
252
 
252
253
  if (pkg) {
253
- updatePackageFilesMutation.mutate({
254
- package_name_with_version: `${pkg.name}@latest`,
255
- ...pkg,
256
- })
254
+ updatePackageFilesMutation.mutate(
255
+ {
256
+ package_name_with_version: `${pkg.name}@latest`,
257
+ ...pkg,
258
+ },
259
+ {
260
+ onSuccess: () => {
261
+ setState((prev) => ({
262
+ ...prev,
263
+ initialFilesLoad: [...prev.pkgFilesWithContent],
264
+ }))
265
+ pkgFiles.refetch()
266
+ },
267
+ },
268
+ )
257
269
  }
258
270
  }
259
271
 
@@ -284,10 +296,17 @@ export function CodeAndPreview({ pkg }: Props) {
284
296
  state.pkgFilesWithContent,
285
297
  ])
286
298
  const mainComponentPath = useMemo(() => {
287
- return state.currentFile?.endsWith(".tsx") &&
299
+ const isReactComponentExported =
300
+ /export function\s+\w+/.test(currentFileCode) ||
301
+ /export const\s+\w+\s*=/.test(currentFileCode) ||
302
+ /export default\s+\w+/.test(currentFileCode) ||
303
+ /export default\s+function\s*(\w*)\s*\(/.test(currentFileCode) ||
304
+ /export default\s*\(\s*\)\s*=>/.test(currentFileCode)
305
+
306
+ return (state.currentFile?.endsWith(".tsx") ||
307
+ state.currentFile?.endsWith(".ts")) &&
288
308
  !!state.pkgFilesWithContent.some((x) => x.path == state.currentFile) &&
289
- (currentFileCode.match(/export function (\w+)/) ||
290
- currentFileCode.match(/export const (\w+) ?=/))
309
+ isReactComponentExported
291
310
  ? state.currentFile
292
311
  : state.defaultComponentFile
293
312
  }, [state.currentFile, state.pkgFilesWithContent, currentFileCode])
@@ -327,6 +346,8 @@ export function CodeAndPreview({ pkg }: Props) {
327
346
  })
328
347
  }
329
348
 
349
+ const { handleCreateFile } = useFileManagement(state, setState)
350
+
330
351
  if ((!pkg && urlParams.package_id) || pkgFiles.isLoading || isLoadingFiles) {
331
352
  return (
332
353
  <div className="flex items-center justify-center h-64">
@@ -363,6 +384,7 @@ export function CodeAndPreview({ pkg }: Props) {
363
384
  )}
364
385
  >
365
386
  <CodeEditor
387
+ handleCreateFile={handleCreateFile}
366
388
  currentFile={state.currentFile}
367
389
  setCurrentFile={(file) =>
368
390
  setState((prev) => ({ ...prev, currentFile: file }))
@@ -379,7 +401,6 @@ export function CodeAndPreview({ pkg }: Props) {
379
401
  ),
380
402
  }))
381
403
  }}
382
- onDtsChange={(dts) => setState((prev) => ({ ...prev, dts }))}
383
404
  pkgFilesLoaded={state.pkgFilesLoaded}
384
405
  />
385
406
  </div>
@@ -23,12 +23,12 @@ import {
23
23
  } from "@valtown/codemirror-ts"
24
24
  import { EditorView } from "codemirror"
25
25
  import { useEffect, useMemo, useRef, useState } from "react"
26
- import ts from "typescript"
26
+ import tsModule from "typescript"
27
27
  import CodeEditorHeader from "@/components/package-port/CodeEditorHeader"
28
28
  import { useCodeCompletionApi } from "@/hooks/use-code-completion-ai-api"
29
29
  import FileSidebar from "../FileSidebar"
30
30
  import { findTargetFile } from "@/lib/utils/findTargetFile"
31
- import type { PackageFile } from "./CodeAndPreview"
31
+ import type { CreateFileProps, PackageFile } from "./CodeAndPreview"
32
32
  import { useShikiHighlighter } from "@/hooks/use-shiki-highlighter"
33
33
 
34
34
  const defaultImports = `
@@ -39,7 +39,6 @@ import type { CommonLayoutProps } from "@tscircuit/props"
39
39
 
40
40
  export const CodeEditor = ({
41
41
  onCodeChange,
42
- onDtsChange,
43
42
  readOnly = false,
44
43
  files = [],
45
44
  isStreaming = false,
@@ -48,10 +47,11 @@ export const CodeEditor = ({
48
47
  pkgFilesLoaded,
49
48
  currentFile,
50
49
  setCurrentFile,
50
+ handleCreateFile,
51
51
  }: {
52
52
  onCodeChange: (code: string, filename?: string) => void
53
- onDtsChange?: (dts: string) => void
54
53
  files: PackageFile[]
54
+ handleCreateFile: (props: CreateFileProps) => void
55
55
  readOnly?: boolean
56
56
  isStreaming?: boolean
57
57
  pkgFilesLoaded?: boolean
@@ -67,9 +67,8 @@ export const CodeEditor = ({
67
67
  const codeCompletionApi = useCodeCompletionApi()
68
68
  const [cursorPosition, setCursorPosition] = useState<number | null>(null)
69
69
  const [code, setCode] = useState(files[0]?.content || "")
70
- const [isCodeEditorReady, setIsCodeEditorReady] = useState(false)
71
70
 
72
- const { highlighter, isLoading } = useShikiHighlighter()
71
+ const { highlighter } = useShikiHighlighter()
73
72
 
74
73
  // Get URL search params for file_path
75
74
  const urlParams = new URLSearchParams(window.location.search)
@@ -134,10 +133,10 @@ export const CodeEditor = ({
134
133
  ;(window as any).__DEBUG_CODE_EDITOR_FS_MAP = fsMap
135
134
 
136
135
  createDefaultMapFromCDN(
137
- { target: ts.ScriptTarget.ES2022 },
136
+ { target: tsModule.ScriptTarget.ES2022 },
138
137
  "5.6.3",
139
138
  true,
140
- ts,
139
+ tsModule,
141
140
  ).then((defaultFsMap) => {
142
141
  defaultFsMap.forEach((content, filename) => {
143
142
  fsMap.set(filename, content)
@@ -145,11 +144,12 @@ export const CodeEditor = ({
145
144
  })
146
145
 
147
146
  const system = createSystem(fsMap)
148
- const env = createVirtualTypeScriptEnvironment(system, [], ts, {
149
- jsx: ts.JsxEmit.ReactJSX,
147
+
148
+ const env = createVirtualTypeScriptEnvironment(system, [], tsModule, {
149
+ jsx: tsModule.JsxEmit.ReactJSX,
150
150
  declaration: true,
151
151
  allowJs: true,
152
- target: ts.ScriptTarget.ES2022,
152
+ target: tsModule.ScriptTarget.ES2022,
153
153
  resolveJsonModule: true,
154
154
  })
155
155
 
@@ -160,7 +160,7 @@ export const CodeEditor = ({
160
160
  // Initialize ATA
161
161
  const ataConfig: ATABootstrapConfig = {
162
162
  projectName: "my-project",
163
- typescript: ts,
163
+ typescript: tsModule,
164
164
  logger: console,
165
165
  fetcher: async (input: RequestInfo | URL, init?: RequestInit) => {
166
166
  const registryPrefixes = [
@@ -190,9 +190,6 @@ export const CodeEditor = ({
190
190
  return fetch(input, init)
191
191
  },
192
192
  delegate: {
193
- finished: () => {
194
- setIsCodeEditorReady(true)
195
- },
196
193
  started: () => {
197
194
  const manualEditsTypeDeclaration = `
198
195
  declare module "manual-edits.json" {
@@ -247,20 +244,6 @@ export const CodeEditor = ({
247
244
  // setCode(newContent)
248
245
  onCodeChange(newContent, currentFile)
249
246
  onFileContentChanged?.(currentFile, newContent)
250
-
251
- // Generate TypeScript declarations for TypeScript/TSX files
252
- if (currentFile.endsWith(".ts") || currentFile.endsWith(".tsx")) {
253
- const { outputFiles } = env.languageService.getEmitOutput(
254
- currentFile,
255
- true,
256
- )
257
- const dtsFile = outputFiles.find((file) =>
258
- file.name.endsWith(".d.ts"),
259
- )
260
- if (dtsFile?.text && onDtsChange) {
261
- onDtsChange(dtsFile.text)
262
- }
263
- }
264
247
  }
265
248
  if (update.selectionSet) {
266
249
  const pos = update.state.selection.main.head
@@ -336,12 +319,14 @@ export const CodeEditor = ({
336
319
 
337
320
  const start = info.textSpan.start
338
321
  const end = start + info.textSpan.length
339
- const content = ts.displayPartsToString(info.displayParts || [])
322
+ const content = tsModule?.displayPartsToString(
323
+ info.displayParts || [],
324
+ )
340
325
 
341
326
  const dom = document.createElement("div")
342
327
  if (highlighter) {
343
328
  dom.innerHTML = highlighter.codeToHtml(content, {
344
- lang: "typescript",
329
+ lang: "tsx",
345
330
  themes: {
346
331
  light: "github-light",
347
332
  dark: "github-dark",
@@ -449,14 +434,12 @@ export const CodeEditor = ({
449
434
 
450
435
  if (currentFile.endsWith(".tsx") || currentFile.endsWith(".ts")) {
451
436
  ata(`${defaultImports}${code}`)
452
- } else if (!!currentFile) {
453
- setIsCodeEditorReady(true)
454
437
  }
455
438
 
456
439
  return () => {
457
440
  view.destroy()
458
441
  }
459
- }, [!isStreaming, currentFile, code !== ""])
442
+ }, [!isStreaming, currentFile, code !== "", Boolean(highlighter)])
460
443
 
461
444
  const updateCurrentEditorContent = (newContent: string) => {
462
445
  if (viewRef.current) {
@@ -539,6 +522,7 @@ export const CodeEditor = ({
539
522
  [sidebarOpen, setSidebarOpen] as ReturnType<typeof useState<boolean>>
540
523
  }
541
524
  onFileSelect={handleFileChange}
525
+ handleCreateFile={handleCreateFile}
542
526
  />
543
527
  <div className="flex flex-col flex-1 w-full min-w-0 h-full">
544
528
  {showImportAndFormatButtons && (
@@ -557,9 +541,9 @@ export const CodeEditor = ({
557
541
  )}
558
542
  <div
559
543
  ref={editorRef}
560
- className={`flex-1 overflow-auto [&_.cm-editor]:h-full [&_.cm-scroller]:!h-full ${
561
- !isCodeEditorReady ? "opacity-50" : ""
562
- }`}
544
+ className={
545
+ "flex-1 overflow-auto [&_.cm-editor]:h-full [&_.cm-scroller]:!h-full"
546
+ }
563
547
  />
564
548
  </div>
565
549
  </div>
@@ -101,7 +101,7 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
101
101
  markdown: "markdown",
102
102
  }
103
103
 
104
- const parser = parserMap[fileExtension] || "typescript"
104
+ const parser = parserMap[fileExtension] || "tsx"
105
105
  const formattedCode = window.prettier.format(currentContent, {
106
106
  semi: false,
107
107
  parser: parser,
@@ -39,7 +39,6 @@ import { Link, useLocation } from "wouter"
39
39
  import { useAxios } from "@/hooks/use-axios"
40
40
  import { useToast } from "@/hooks/use-toast"
41
41
  import { useConfirmDeletePackageDialog } from "@/components/dialogs/confirm-delete-package-dialog"
42
- import { useCreateOrderDialog } from "@/components/dialogs/create-order-dialog"
43
42
  import { useFilesDialog } from "@/components/dialogs/files-dialog"
44
43
  import { useViewTsFilesDialog } from "@/components/dialogs/view-ts-files-dialog"
45
44
  import { DownloadButtonAndMenu } from "@/components/DownloadButtonAndMenu"
@@ -81,8 +80,6 @@ export default function EditorNav({
81
80
  } = useUpdatePackageDescriptionDialog()
82
81
  const { Dialog: DeleteDialog, openDialog: openDeleteDialog } =
83
82
  useConfirmDeletePackageDialog()
84
- const { Dialog: CreateOrderDialog, openDialog: openCreateOrderDialog } =
85
- useCreateOrderDialog()
86
83
  const { Dialog: FilesDialog, openDialog: openFilesDialog } = useFilesDialog()
87
84
  const { Dialog: ViewTsFilesDialog, openDialog: openViewTsFilesDialog } =
88
85
  useViewTsFilesDialog()
@@ -315,7 +312,7 @@ export default function EditorNav({
315
312
  <div className="flex items-center justify-end -space-x-1">
316
313
  <div className="flex mx-2 items-center space-x-1">
317
314
  {pkg && <TypeBadge type={`${packageType ?? pkg.snippet_type}`} />}
318
- <Button
315
+ {/* <Button
319
316
  variant="ghost"
320
317
  size="sm"
321
318
  disabled={hasUnsavedChanges || isSaving || !pkg}
@@ -323,7 +320,7 @@ export default function EditorNav({
323
320
  >
324
321
  <Sparkles className="mr-1 h-3 w-3" />
325
322
  Edit with AI
326
- </Button>
323
+ </Button> */}
327
324
  <DownloadButtonAndMenu
328
325
  snippetUnscopedName={pkg?.unscoped_name}
329
326
  circuitJson={circuitJson}
@@ -358,13 +355,6 @@ export default function EditorNav({
358
355
  </Button>
359
356
  </DropdownMenuTrigger>
360
357
  <DropdownMenuContent>
361
- <DropdownMenuItem
362
- className="text-xs"
363
- onClick={() => openCreateOrderDialog()}
364
- >
365
- <PackageIcon className="mr-2 h-3 w-3" />
366
- Submit Order
367
- </DropdownMenuItem>
368
358
  <DropdownMenuItem
369
359
  className="text-xs"
370
360
  onClick={() => openFilesDialog()}
@@ -519,8 +509,8 @@ export default function EditorNav({
519
509
  <DeleteDialog
520
510
  packageId={pkg?.package_id ?? ""}
521
511
  packageName={pkg?.unscoped_name ?? ""}
512
+ packageOwner={pkg?.owner_github_username ?? ""}
522
513
  />
523
- <CreateOrderDialog />
524
514
  <FilesDialog snippetId={pkg?.package_id ?? ""} />
525
515
  <ViewTsFilesDialog />
526
516
  </nav>
@@ -30,4 +30,5 @@ export const useGlobalStore = create<Store>()(
30
30
 
31
31
  useGlobalStore.subscribe((state, prevState) => {
32
32
  ;(window as any).globalStore = state
33
+ window.TSCIRCUIT_REGISTRY_TOKEN = state.session?.token ?? null
33
34
  })