@tscircuit/fake-snippets 0.0.71 → 0.0.72

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.
@@ -28,7 +28,7 @@ const routeSpec = {
28
28
  }, "Cannot specify both package_release_id and package_name_with_version")
29
29
  .refine((v) => {
30
30
  if (v.content_base64 && v.content_text) return false
31
- if (!v.content_base64 && !v.content_text) return false
31
+ if (!v.content_base64 && v.content_text === undefined) return false
32
32
  return true
33
33
  }, "Either content_base64 or content_text is required"),
34
34
  jsonResponse: z.object({
@@ -136,7 +136,7 @@ export default withRouteSpec(routeSpec)(async (req, ctx) => {
136
136
  exisitingFile.package_file_id,
137
137
  {
138
138
  content_text:
139
- content_text ||
139
+ content_text ??
140
140
  (content_base64
141
141
  ? Buffer.from(content_base64, "base64").toString()
142
142
  : null),
@@ -167,7 +167,7 @@ export default withRouteSpec(routeSpec)(async (req, ctx) => {
167
167
  package_release_id: packageReleaseId,
168
168
  file_path,
169
169
  content_text:
170
- content_text ||
170
+ content_text ??
171
171
  (content_base64
172
172
  ? Buffer.from(content_base64, "base64").toString()
173
173
  : null),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/fake-snippets",
3
- "version": "0.0.71",
3
+ "version": "0.0.72",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -71,11 +71,11 @@
71
71
  "@radix-ui/react-toggle-group": "^1.1.0",
72
72
  "@radix-ui/react-tooltip": "^1.1.2",
73
73
  "@tscircuit/eval": "^0.0.198",
74
- "@tscircuit/footprinter": "^0.0.124",
74
+ "@tscircuit/footprinter": "^0.0.169",
75
75
  "@tscircuit/layout": "^0.0.29",
76
76
  "@tscircuit/math-utils": "^0.0.10",
77
77
  "@tscircuit/mm": "^0.0.8",
78
- "@tscircuit/props": "^0.0.186",
78
+ "@tscircuit/props": "^0.0.194",
79
79
  "@types/file-saver": "^2.0.7",
80
80
  "@types/ms": "^0.7.34",
81
81
  "@typescript/ata": "^0.9.7",
@@ -83,7 +83,7 @@
83
83
  "@valtown/codemirror-ts": "^2.2.0",
84
84
  "@vercel/analytics": "^1.4.1",
85
85
  "change-case": "^5.4.4",
86
- "circuit-json": "^0.0.164",
86
+ "circuit-json": "^0.0.190",
87
87
  "circuit-json-to-bom-csv": "^0.0.6",
88
88
  "circuit-json-to-gerber": "^0.0.21",
89
89
  "circuit-json-to-pnp-csv": "^0.0.6",
@@ -145,9 +145,9 @@
145
145
  "@biomejs/biome": "^1.9.2",
146
146
  "@playwright/test": "^1.48.0",
147
147
  "@tailwindcss/typography": "^0.5.16",
148
- "@tscircuit/core": "^0.0.384",
148
+ "@tscircuit/core": "^0.0.428",
149
149
  "@tscircuit/prompt-benchmarks": "^0.0.28",
150
- "@tscircuit/runframe": "^0.0.494",
150
+ "@tscircuit/runframe": "^0.0.507",
151
151
  "@types/babel__standalone": "^7.1.7",
152
152
  "@types/bun": "^1.1.10",
153
153
  "@types/country-list": "^2.1.4",
@@ -161,7 +161,7 @@
161
161
  "@typescript/vfs": "^1.6.0",
162
162
  "@vitejs/plugin-react": "^4.3.1",
163
163
  "autoprefixer": "^10.4.20",
164
- "circuit-to-svg": "^0.0.101",
164
+ "circuit-to-svg": "^0.0.131",
165
165
  "get-port": "^7.1.0",
166
166
  "globals": "^15.9.0",
167
167
  "he": "^1.2.0",
@@ -1,20 +1,33 @@
1
1
  import React, { useState } from "react"
2
2
  import { cn } from "@/lib/utils"
3
- import { File, Folder, PanelRightOpen, Plus } from "lucide-react"
3
+ import { File, Folder, MoreVertical, PanelRightOpen, Plus } from "lucide-react"
4
4
  import { TreeView, TreeDataItem } from "@/components/ui/tree-view"
5
5
  import { isHiddenFile } from "./ViewPackagePage/utils/is-hidden-file"
6
6
  import { Input } from "@/components/ui/input"
7
- import { CreateFileProps } from "./package-port/CodeAndPreview"
8
-
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuContent,
10
+ DropdownMenuGroup,
11
+ DropdownMenuItem,
12
+ DropdownMenuTrigger,
13
+ } from "./ui/dropdown-menu"
14
+ import type {
15
+ ICreateFileProps,
16
+ ICreateFileResult,
17
+ IDeleteFileProps,
18
+ IDeleteFileResult,
19
+ } from "@/hooks/useFileManagement"
20
+ import { useToast } from "@/hooks/use-toast"
9
21
  type FileName = string
10
22
 
11
23
  interface FileSidebarProps {
12
24
  files: Record<FileName, string>
13
- currentFile: FileName
25
+ currentFile: FileName | null
14
26
  onFileSelect: (filename: FileName) => void
15
27
  className?: string
16
28
  fileSidebarState: ReturnType<typeof useState<boolean>>
17
- handleCreateFile: (props: CreateFileProps) => void
29
+ handleCreateFile: (props: ICreateFileProps) => ICreateFileResult
30
+ handleDeleteFile: (props: IDeleteFileProps) => IDeleteFileResult
18
31
  }
19
32
 
20
33
  const FileSidebar: React.FC<FileSidebarProps> = ({
@@ -24,11 +37,13 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
24
37
  className,
25
38
  fileSidebarState,
26
39
  handleCreateFile,
40
+ handleDeleteFile,
27
41
  }) => {
28
42
  const [sidebarOpen, setSidebarOpen] = fileSidebarState
29
43
  const [newFileName, setNewFileName] = useState("")
30
44
  const [isCreatingFile, setIsCreatingFile] = useState(false)
31
45
  const [errorMessage, setErrorMessage] = useState("")
46
+ const { toast } = useToast()
32
47
 
33
48
  const transformFilesToTreeData = (
34
49
  files: Record<FileName, string>,
@@ -38,38 +53,85 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
38
53
  }
39
54
  const root: Record<string, TreeNode> = {}
40
55
 
41
- Object.keys(files).forEach((path) => {
42
- const startsWithSlash = path.startsWith("/")
43
- const parts = (startsWithSlash ? path.slice(1) : path).trim().split("/")
44
- let current = root
56
+ Object.keys(files).forEach((filePath) => {
57
+ const hasLeadingSlash = filePath.startsWith("/")
58
+ const pathSegments = (hasLeadingSlash ? filePath.slice(1) : filePath)
59
+ .trim()
60
+ .split("/")
61
+ let currentNode: Record<string, TreeNode> = root
45
62
 
46
- parts.forEach((part, index) => {
47
- const isFile = index === parts.length - 1
48
- const parentPath = parts.slice(0, index).join("/")
49
- const currentPath = parentPath ? `${parentPath}/${part}` : part
50
- const evaluatedFilePath = startsWithSlash
51
- ? `/${currentPath}`
52
- : currentPath
63
+ pathSegments.forEach((segment, segmentIndex) => {
64
+ const isLeafNode = segmentIndex === pathSegments.length - 1
65
+ const ancestorPath = pathSegments.slice(0, segmentIndex).join("/")
66
+ const relativePath = ancestorPath
67
+ ? `${ancestorPath}/${segment}`
68
+ : segment
69
+ const absolutePath = hasLeadingSlash ? `/${relativePath}` : relativePath
70
+ const itemId = absolutePath
53
71
  if (
54
- !current[part] &&
55
- (!isHiddenFile(currentPath) ||
72
+ !currentNode[segment] &&
73
+ (!isHiddenFile(relativePath) ||
56
74
  isHiddenFile(
57
- currentFile.startsWith("/") ? currentFile.slice(1) : currentFile,
75
+ currentFile?.startsWith("/")
76
+ ? currentFile.slice(1)
77
+ : currentFile || "",
58
78
  ))
59
79
  ) {
60
- current[part] = {
61
- id: currentPath,
62
- name: isFile ? part : part,
63
- icon: isFile ? File : Folder,
64
- onClick: isFile ? () => onFileSelect(evaluatedFilePath) : undefined,
65
- draggable: isFile,
66
- droppable: !isFile,
67
- children: isFile ? undefined : {},
80
+ currentNode[segment] = {
81
+ id: itemId,
82
+ name: isLeafNode ? segment : segment,
83
+ icon: isLeafNode ? File : Folder,
84
+ onClick: isLeafNode ? () => onFileSelect(absolutePath) : undefined,
85
+ draggable: false,
86
+ droppable: !isLeafNode,
87
+ children: isLeafNode ? undefined : {},
88
+ actions: (
89
+ <>
90
+ <DropdownMenu key={itemId}>
91
+ <DropdownMenuTrigger asChild>
92
+ <MoreVertical className="w-4 h-4 text-gray-500 hover:text-gray-700" />
93
+ </DropdownMenuTrigger>
94
+ <DropdownMenuContent
95
+ className="w-48 bg-white shadow-lg rounded-md border-4 z-[100] border-white"
96
+ style={{
97
+ position: "absolute",
98
+ top: "100%",
99
+ left: "0",
100
+ marginTop: "0.5rem",
101
+ width: "8rem",
102
+ padding: "0.01rem",
103
+ }}
104
+ >
105
+ <DropdownMenuGroup>
106
+ <DropdownMenuItem
107
+ onClick={() => {
108
+ const { fileDeleted } = handleDeleteFile({
109
+ filename: relativePath,
110
+ onError: (error) => {
111
+ toast({
112
+ title: `Error deleting file ${relativePath}`,
113
+ description: error.message,
114
+ })
115
+ },
116
+ })
117
+ if (fileDeleted) {
118
+ setErrorMessage("")
119
+ }
120
+ }}
121
+ className="flex items-center px-4 py-1 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer"
122
+ >
123
+ Delete
124
+ </DropdownMenuItem>
125
+ </DropdownMenuGroup>
126
+ </DropdownMenuContent>
127
+ </DropdownMenu>
128
+ </>
129
+ ),
68
130
  }
69
131
  }
70
132
 
71
- if (!isFile && current[part].children) {
72
- current = current[part].children
133
+ if (!isLeafNode && currentNode[segment].children) {
134
+ currentNode = currentNode[segment].children
73
135
  }
74
136
  })
75
137
  })
@@ -90,15 +152,26 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
90
152
  }
91
153
 
92
154
  const treeData = transformFilesToTreeData(files)
93
-
155
+ // console.log("treeData", files)
94
156
  const handleCreateFileInline = () => {
95
- handleCreateFile({
157
+ const { newFileCreated } = handleCreateFile({
96
158
  newFileName,
97
- setErrorMessage,
98
- onFileSelect,
99
- setNewFileName,
100
- setIsCreatingFile,
159
+ onError: (error) => {
160
+ setErrorMessage(error.message)
161
+ },
101
162
  })
163
+ if (newFileCreated) {
164
+ setIsCreatingFile(false)
165
+ setNewFileName("")
166
+ setErrorMessage("")
167
+ }
168
+ }
169
+
170
+ const toggleSidebar = () => {
171
+ setSidebarOpen(!sidebarOpen)
172
+ setErrorMessage("")
173
+ setIsCreatingFile(false)
174
+ setNewFileName("")
102
175
  }
103
176
 
104
177
  return (
@@ -110,7 +183,7 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
110
183
  )}
111
184
  >
112
185
  <button
113
- onClick={() => setSidebarOpen(!sidebarOpen)}
186
+ onClick={toggleSidebar}
114
187
  className={`z-[99] mt-2 ml-2 text-gray-400 scale-90 transition-opacity duration-200 ${
115
188
  !sidebarOpen ? "opacity-0 pointer-events-none" : "opacity-100"
116
189
  }`}
@@ -129,6 +202,7 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
129
202
  <Input
130
203
  autoFocus
131
204
  value={newFileName}
205
+ spellCheck={false}
132
206
  onChange={(e) => setNewFileName(e.target.value)}
133
207
  onBlur={handleCreateFileInline}
134
208
  onKeyDown={(e) => {
@@ -149,7 +223,7 @@ const FileSidebar: React.FC<FileSidebarProps> = ({
149
223
  )}
150
224
  <TreeView
151
225
  data={treeData}
152
- initialSelectedItemId={currentFile}
226
+ initialSelectedItemId={currentFile || ""}
153
227
  onSelectChange={(item) => {
154
228
  if (item?.onClick) {
155
229
  item.onClick()