ai-design-system 0.1.62 → 0.1.63

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.
@@ -16,6 +16,11 @@ export type FileTreeNode = {
16
16
  children?: FileTreeNode[]
17
17
  }
18
18
 
19
+ export interface FileDownloadResult {
20
+ blob: Blob
21
+ filename: string
22
+ }
23
+
19
24
  export interface FileTreeExplorerProps {
20
25
  tree: FileTreeNode[]
21
26
  defaultExpanded?: Set<string>
@@ -24,7 +29,7 @@ export interface FileTreeExplorerProps {
24
29
  searchPlaceholder?: string
25
30
  onCreateClick?: () => void
26
31
  createButtonLabel?: string
27
- onDownloadClick?: () => void
32
+ onDownload?: () => Promise<FileDownloadResult | undefined>
28
33
  headerClassName?: string
29
34
  className?: string
30
35
  }
@@ -85,13 +90,28 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
85
90
  searchPlaceholder = "Filter files...",
86
91
  onCreateClick,
87
92
  createButtonLabel,
88
- onDownloadClick,
93
+ onDownload,
89
94
  headerClassName,
90
95
  className,
91
96
  }) => {
97
+ const downloadRef = React.useRef<HTMLAnchorElement>(null)
92
98
  const [searchQuery, setSearchQuery] = React.useState("")
93
99
  const [userExpanded, setUserExpanded] = React.useState<Set<string>>(defaultExpanded || new Set())
94
100
 
101
+ const handleDownloadClick = React.useCallback(async () => {
102
+ if (!onDownload) return
103
+ const result = await onDownload()
104
+ if (!result) return
105
+ const url = URL.createObjectURL(result.blob)
106
+ const anchor = downloadRef.current
107
+ if (anchor) {
108
+ anchor.href = url
109
+ anchor.download = result.filename
110
+ anchor.click()
111
+ }
112
+ URL.revokeObjectURL(url)
113
+ }, [onDownload])
114
+
95
115
  // Auto-expand parents when selectedPath changes
96
116
  React.useEffect(() => {
97
117
  if (selectedPath) {
@@ -147,16 +167,17 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
147
167
  {createButtonLabel ?? "New"}
148
168
  </button>
149
169
  ) : null}
150
- {onDownloadClick ? (
170
+ {onDownload ? (
151
171
  <button
152
172
  type="button"
153
- onClick={onDownloadClick}
173
+ onClick={handleDownloadClick}
154
174
  title="Download all files"
155
175
  className="inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
156
176
  >
157
177
  <Icon name="download" size="sm" />
158
178
  </button>
159
179
  ) : null}
180
+ <a ref={downloadRef} style={{ display: 'none' }} />
160
181
  </div>
161
182
  <div className="p-2">
162
183
  <FileTree
@@ -3,6 +3,7 @@ export {
3
3
  } from "./FileTreeExplorer"
4
4
 
5
5
  export type {
6
+ FileDownloadResult,
6
7
  FileTreeExplorerProps,
7
8
  FileTreeNode,
8
9
  } from "./FileTreeExplorer"
@@ -37,7 +37,7 @@ import { DocumentEditorWithComments } from '@/components/blocks/DocumentEditorWi
37
37
  import { DocumentTabBar } from '@/components/composites/DocumentTabBar'
38
38
  import { AdjustableLayout } from '@/components/composites/AdjustableLayout'
39
39
  import { FileTreeExplorer } from '@/components/composites/FileTreeExplorer'
40
- import type { FileTreeNode } from '@/components/composites/FileTreeExplorer'
40
+ import type { FileDownloadResult, FileTreeNode } from '@/components/composites/FileTreeExplorer'
41
41
  import { cn } from '@/lib/utils'
42
42
  import type { JSONContent } from '@tiptap/core'
43
43
  import type { Annotation, User } from '@/types/ai-editor/annotations'
@@ -106,7 +106,7 @@ export interface TextEditorMultiTabProps {
106
106
  /** When true, hides the document tab bar — useful for single-file mode where the file tree provides navigation. */
107
107
  hideTabBar?: boolean
108
108
  /** Callback when download all button is clicked in the file tree header */
109
- onDownloadAllFiles?: () => void
109
+ onDownloadAllFiles?: () => Promise<FileDownloadResult | undefined>
110
110
  }
111
111
 
112
112
  /**
@@ -389,7 +389,7 @@ export const TextEditor = React.memo<TextEditorProps>(
389
389
  tree={fileTreeNodes}
390
390
  selectedPath={props.activeDocumentId}
391
391
  onSelect={props.onTabSelect}
392
- onDownloadClick={onDownloadAllFiles}
392
+ onDownload={onDownloadAllFiles}
393
393
  />
394
394
  ),
395
395
  },
package/dist/index.cjs CHANGED
@@ -11440,12 +11440,26 @@ var FileTreeExplorer = React3__namespace.memo(
11440
11440
  searchPlaceholder = "Filter files...",
11441
11441
  onCreateClick,
11442
11442
  createButtonLabel,
11443
- onDownloadClick,
11443
+ onDownload,
11444
11444
  headerClassName,
11445
11445
  className
11446
11446
  }) => {
11447
+ const downloadRef = React3__namespace.useRef(null);
11447
11448
  const [searchQuery, setSearchQuery] = React3__namespace.useState("");
11448
11449
  const [userExpanded, setUserExpanded] = React3__namespace.useState(defaultExpanded || /* @__PURE__ */ new Set());
11450
+ const handleDownloadClick = React3__namespace.useCallback(async () => {
11451
+ if (!onDownload) return;
11452
+ const result = await onDownload();
11453
+ if (!result) return;
11454
+ const url = URL.createObjectURL(result.blob);
11455
+ const anchor = downloadRef.current;
11456
+ if (anchor) {
11457
+ anchor.href = url;
11458
+ anchor.download = result.filename;
11459
+ anchor.click();
11460
+ }
11461
+ URL.revokeObjectURL(url);
11462
+ }, [onDownload]);
11449
11463
  React3__namespace.useEffect(() => {
11450
11464
  if (selectedPath) {
11451
11465
  const parts = selectedPath.split("/");
@@ -11504,16 +11518,17 @@ var FileTreeExplorer = React3__namespace.memo(
11504
11518
  ]
11505
11519
  }
11506
11520
  ) : null,
11507
- onDownloadClick ? /* @__PURE__ */ jsxRuntime.jsx(
11521
+ onDownload ? /* @__PURE__ */ jsxRuntime.jsx(
11508
11522
  "button",
11509
11523
  {
11510
11524
  type: "button",
11511
- onClick: onDownloadClick,
11525
+ onClick: handleDownloadClick,
11512
11526
  title: "Download all files",
11513
11527
  className: "inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
11514
11528
  children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "download", size: "sm" })
11515
11529
  }
11516
- ) : null
11530
+ ) : null,
11531
+ /* @__PURE__ */ jsxRuntime.jsx("a", { ref: downloadRef, style: { display: "none" } })
11517
11532
  ] }),
11518
11533
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
11519
11534
  FileTree,
@@ -11717,7 +11732,7 @@ ${format === "json" ? formatJson(currentDocument.content) : currentDocument.cont
11717
11732
  tree: fileTreeNodes,
11718
11733
  selectedPath: props.activeDocumentId,
11719
11734
  onSelect: props.onTabSelect,
11720
- onDownloadClick: onDownloadAllFiles
11735
+ onDownload: onDownloadAllFiles
11721
11736
  }
11722
11737
  )
11723
11738
  },