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.
- package/components/composites/FileTreeExplorer/FileTreeExplorer.tsx +25 -4
- package/components/composites/FileTreeExplorer/index.ts +1 -0
- package/components/features/TextEditor/TextEditor.tsx +3 -3
- package/dist/index.cjs +20 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
{
|
|
170
|
+
{onDownload ? (
|
|
151
171
|
<button
|
|
152
172
|
type="button"
|
|
153
|
-
onClick={
|
|
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
|
|
@@ -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?: () =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11521
|
+
onDownload ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11508
11522
|
"button",
|
|
11509
11523
|
{
|
|
11510
11524
|
type: "button",
|
|
11511
|
-
onClick:
|
|
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
|
-
|
|
11735
|
+
onDownload: onDownloadAllFiles
|
|
11721
11736
|
}
|
|
11722
11737
|
)
|
|
11723
11738
|
},
|