@databricks/appkit-ui 0.17.0 → 0.19.0
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/CLAUDE.md +9 -1
- package/dist/cli/commands/plugin/create/scaffold.js +2 -8
- package/dist/cli/commands/plugin/create/scaffold.js.map +1 -1
- package/dist/react/charts/base.js +3 -2
- package/dist/react/charts/base.js.map +1 -1
- package/dist/react/charts/normalize.d.ts.map +1 -1
- package/dist/react/charts/normalize.js +3 -1
- package/dist/react/charts/normalize.js.map +1 -1
- package/dist/react/charts/options.d.ts +1 -0
- package/dist/react/charts/options.d.ts.map +1 -1
- package/dist/react/charts/options.js +13 -8
- package/dist/react/charts/options.js.map +1 -1
- package/dist/react/charts/utils.d.ts.map +1 -1
- package/dist/react/charts/utils.js +23 -1
- package/dist/react/charts/utils.js.map +1 -1
- package/dist/react/file-browser/directory-list.d.ts +54 -0
- package/dist/react/file-browser/directory-list.d.ts.map +1 -0
- package/dist/react/file-browser/directory-list.js +74 -0
- package/dist/react/file-browser/directory-list.js.map +1 -0
- package/dist/react/file-browser/file-breadcrumb.d.ts +25 -0
- package/dist/react/file-browser/file-breadcrumb.d.ts.map +1 -0
- package/dist/react/file-browser/file-breadcrumb.js +27 -0
- package/dist/react/file-browser/file-breadcrumb.js.map +1 -0
- package/dist/react/file-browser/file-entry.d.ts +27 -0
- package/dist/react/file-browser/file-entry.d.ts.map +1 -0
- package/dist/react/file-browser/file-entry.js +31 -0
- package/dist/react/file-browser/file-entry.js.map +1 -0
- package/dist/react/file-browser/file-preview-panel.d.ts +42 -0
- package/dist/react/file-browser/file-preview-panel.d.ts.map +1 -0
- package/dist/react/file-browser/file-preview-panel.js +135 -0
- package/dist/react/file-browser/file-preview-panel.js.map +1 -0
- package/dist/react/file-browser/index.d.ts +7 -0
- package/dist/react/file-browser/index.js +6 -0
- package/dist/react/file-browser/new-folder-input.d.ts +36 -0
- package/dist/react/file-browser/new-folder-input.d.ts.map +1 -0
- package/dist/react/file-browser/new-folder-input.js +52 -0
- package/dist/react/file-browser/new-folder-input.js.map +1 -0
- package/dist/react/file-browser/types.d.ts +52 -0
- package/dist/react/file-browser/types.d.ts.map +1 -0
- package/dist/react/genie/genie-chart-inference.d.ts +17 -0
- package/dist/react/genie/genie-chart-inference.d.ts.map +1 -0
- package/dist/react/genie/genie-chart-inference.js +75 -0
- package/dist/react/genie/genie-chart-inference.js.map +1 -0
- package/dist/react/genie/genie-chat-message-list.js +1 -1
- package/dist/react/genie/genie-chat-message.d.ts.map +1 -1
- package/dist/react/genie/genie-chat-message.js +27 -16
- package/dist/react/genie/genie-chat-message.js.map +1 -1
- package/dist/react/genie/genie-query-transform.d.ts +31 -0
- package/dist/react/genie/genie-query-transform.d.ts.map +1 -0
- package/dist/react/genie/genie-query-transform.js +79 -0
- package/dist/react/genie/genie-query-transform.js.map +1 -0
- package/dist/react/genie/genie-query-visualization.d.ts +25 -0
- package/dist/react/genie/genie-query-visualization.d.ts.map +1 -0
- package/dist/react/genie/genie-query-visualization.js +79 -0
- package/dist/react/genie/genie-query-visualization.js.map +1 -0
- package/dist/react/genie/index.d.ts +4 -1
- package/dist/react/genie/index.js +3 -0
- package/dist/react/genie/types.d.ts +2 -2
- package/dist/react/genie/types.d.ts.map +1 -1
- package/dist/react/index.d.ts +13 -2
- package/dist/react/index.js +16 -6
- package/dist/react/lib/format.d.ts +14 -0
- package/dist/react/lib/format.d.ts.map +1 -0
- package/dist/react/lib/format.js +17 -1
- package/dist/react/lib/format.js.map +1 -1
- package/dist/react/table/data-table.js +2 -2
- package/dist/react/table/table-wrapper.js +1 -1
- package/dist/react/ui/breadcrumb.js +1 -1
- package/dist/react/ui/index.js +5 -5
- package/dist/react/ui/navigation-menu.js +1 -1
- package/dist/react/ui/sidebar.js +1 -1
- package/dist/shared/src/genie.d.ts +16 -2
- package/dist/shared/src/genie.d.ts.map +1 -1
- package/dist/shared/src/index.d.ts +1 -1
- package/docs/api/appkit/Class.Plugin.md +60 -12
- package/docs/api/appkit/Class.ResourceRegistry.md +3 -3
- package/docs/api/appkit/Function.createApp.md +3 -3
- package/docs/api/appkit/Interface.PluginManifest.md +9 -3
- package/docs/api/appkit/TypeAlias.PluginData.md +45 -0
- package/docs/api/appkit/TypeAlias.ToPlugin.md +1 -1
- package/docs/api/appkit-ui/files/DirectoryList.md +36 -0
- package/docs/api/appkit-ui/files/FileBreadcrumb.md +27 -0
- package/docs/api/appkit-ui/files/FileEntry.md +27 -0
- package/docs/api/appkit-ui/files/FilePreviewPanel.md +32 -0
- package/docs/api/appkit-ui/files/NewFolderInput.md +30 -0
- package/docs/api/appkit-ui/genie/GenieQueryVisualization.md +29 -0
- package/docs/api/appkit.md +1 -0
- package/docs/configuration.md +15 -0
- package/docs/plugins/custom-plugins.md +4 -13
- package/docs/plugins/files.md +350 -0
- package/docs/plugins.md +2 -1
- package/llms.txt +9 -1
- package/package.json +1 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Button } from "../ui/button.js";
|
|
2
|
+
import { Card } from "../ui/card.js";
|
|
3
|
+
import { Skeleton } from "../ui/skeleton.js";
|
|
4
|
+
import { FileEntry } from "./file-entry.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { AlertCircle, ArrowLeft, FileIcon } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
//#region src/react/file-browser/directory-list.tsx
|
|
9
|
+
/** Card-wrapped directory listing with loading, error, and empty states */
|
|
10
|
+
function DirectoryList({ entries, loading, error, onEntryClick, onNavigateToParent, onRetry, isAtRoot, selectedPath, resolveEntryPath, headerContent, hasCurrentPath, formatSize, labels, className, ...props }) {
|
|
11
|
+
return /* @__PURE__ */ jsx("div", {
|
|
12
|
+
"data-slot": "directory-list",
|
|
13
|
+
className,
|
|
14
|
+
...props,
|
|
15
|
+
children: /* @__PURE__ */ jsxs(Card, {
|
|
16
|
+
className: "p-0 overflow-hidden",
|
|
17
|
+
children: [
|
|
18
|
+
!isAtRoot && onNavigateToParent && /* @__PURE__ */ jsxs("button", {
|
|
19
|
+
type: "button",
|
|
20
|
+
onClick: onNavigateToParent,
|
|
21
|
+
className: "flex items-center gap-2 px-4 py-3 w-full text-left hover:bg-muted/50 border-b text-sm text-muted-foreground transition-colors",
|
|
22
|
+
children: [/* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" }), labels?.backToParent ?? "Back to parent"]
|
|
23
|
+
}),
|
|
24
|
+
headerContent,
|
|
25
|
+
loading && /* @__PURE__ */ jsxs("div", {
|
|
26
|
+
className: "p-4 space-y-3",
|
|
27
|
+
children: [
|
|
28
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }),
|
|
29
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }),
|
|
30
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
|
|
31
|
+
]
|
|
32
|
+
}),
|
|
33
|
+
error && /* @__PURE__ */ jsxs("div", {
|
|
34
|
+
className: "p-6 text-center",
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "h-8 w-8 text-destructive mx-auto mb-2" }),
|
|
37
|
+
/* @__PURE__ */ jsx("p", {
|
|
38
|
+
className: "text-sm text-destructive",
|
|
39
|
+
children: error
|
|
40
|
+
}),
|
|
41
|
+
onRetry && /* @__PURE__ */ jsx(Button, {
|
|
42
|
+
variant: "outline",
|
|
43
|
+
size: "sm",
|
|
44
|
+
className: "mt-3",
|
|
45
|
+
onClick: onRetry,
|
|
46
|
+
children: labels?.retry ?? "Retry"
|
|
47
|
+
})
|
|
48
|
+
]
|
|
49
|
+
}),
|
|
50
|
+
!loading && !error && entries.length === 0 && /* @__PURE__ */ jsxs("div", {
|
|
51
|
+
className: "p-6 text-center text-muted-foreground",
|
|
52
|
+
children: [/* @__PURE__ */ jsx(FileIcon, { className: "h-8 w-8 mx-auto mb-2 opacity-50" }), /* @__PURE__ */ jsx("p", {
|
|
53
|
+
className: "text-sm",
|
|
54
|
+
children: hasCurrentPath ? labels?.emptyDirectory ?? "This directory is empty." : labels?.noVolumeConfigured ?? "No volume configured. Configure volumes in the files plugin to get started."
|
|
55
|
+
})]
|
|
56
|
+
}),
|
|
57
|
+
!loading && !error && entries.map((entry) => {
|
|
58
|
+
const entryPath = resolveEntryPath(entry);
|
|
59
|
+
return /* @__PURE__ */ jsx(FileEntry, {
|
|
60
|
+
entry,
|
|
61
|
+
entryPath,
|
|
62
|
+
isSelected: selectedPath === entryPath,
|
|
63
|
+
formatSize,
|
|
64
|
+
onClick: () => onEntryClick(entry)
|
|
65
|
+
}, entryPath);
|
|
66
|
+
})
|
|
67
|
+
]
|
|
68
|
+
})
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { DirectoryList };
|
|
74
|
+
//# sourceMappingURL=directory-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-list.js","names":[],"sources":["../../../src/react/file-browser/directory-list.tsx"],"sourcesContent":["import { AlertCircle, ArrowLeft, FileIcon } from \"lucide-react\";\nimport { Button } from \"../ui/button\";\nimport { Card } from \"../ui/card\";\nimport { Skeleton } from \"../ui/skeleton\";\nimport { FileEntry } from \"./file-entry\";\nimport type { DirectoryEntry, FileBrowserLabels } from \"./types\";\n\n/** Props for the DirectoryList component */\nexport interface DirectoryListProps\n extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** Directory entries to display */\n entries: DirectoryEntry[];\n /** Whether the directory is currently loading */\n loading?: boolean;\n /** Error message to display */\n error?: string | null;\n /** Called when an entry is clicked */\n onEntryClick: (entry: DirectoryEntry) => void;\n /** Called when the back/parent button is clicked */\n onNavigateToParent?: () => void;\n /** Called when the retry button is clicked */\n onRetry?: () => void;\n /** Whether the user is at the root directory (hides back button) */\n isAtRoot?: boolean;\n /** Currently selected file path for highlighting */\n selectedPath?: string | null;\n /** Resolves a DirectoryEntry to its full path */\n resolveEntryPath: (entry: DirectoryEntry) => string;\n /** Content rendered between the back button and the entry list (e.g., NewFolderInput) */\n headerContent?: React.ReactNode;\n /** Whether a current path is set (affects empty state message) */\n hasCurrentPath?: boolean;\n /** Custom file size formatter */\n formatSize?: (bytes: number | undefined) => string;\n /** Customizable labels */\n labels?: Pick<\n FileBrowserLabels,\n \"backToParent\" | \"emptyDirectory\" | \"noVolumeConfigured\" | \"retry\"\n >;\n}\n\n/** Card-wrapped directory listing with loading, error, and empty states */\nexport function DirectoryList({\n entries,\n loading,\n error,\n onEntryClick,\n onNavigateToParent,\n onRetry,\n isAtRoot,\n selectedPath,\n resolveEntryPath,\n headerContent,\n hasCurrentPath,\n formatSize,\n labels,\n className,\n ...props\n}: DirectoryListProps) {\n return (\n <div data-slot=\"directory-list\" className={className} {...props}>\n <Card className=\"p-0 overflow-hidden\">\n {!isAtRoot && onNavigateToParent && (\n <button\n type=\"button\"\n onClick={onNavigateToParent}\n className=\"flex items-center gap-2 px-4 py-3 w-full text-left hover:bg-muted/50 border-b text-sm text-muted-foreground transition-colors\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n {labels?.backToParent ?? \"Back to parent\"}\n </button>\n )}\n\n {headerContent}\n\n {loading && (\n <div className=\"p-4 space-y-3\">\n <Skeleton className=\"h-10 w-full\" />\n <Skeleton className=\"h-10 w-full\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n )}\n\n {error && (\n <div className=\"p-6 text-center\">\n <AlertCircle className=\"h-8 w-8 text-destructive mx-auto mb-2\" />\n <p className=\"text-sm text-destructive\">{error}</p>\n {onRetry && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={onRetry}\n >\n {labels?.retry ?? \"Retry\"}\n </Button>\n )}\n </div>\n )}\n\n {!loading && !error && entries.length === 0 && (\n <div className=\"p-6 text-center text-muted-foreground\">\n <FileIcon className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p className=\"text-sm\">\n {hasCurrentPath\n ? (labels?.emptyDirectory ?? \"This directory is empty.\")\n : (labels?.noVolumeConfigured ??\n \"No volume configured. Configure volumes in the files plugin to get started.\")}\n </p>\n </div>\n )}\n\n {!loading &&\n !error &&\n entries.map((entry) => {\n const entryPath = resolveEntryPath(entry);\n return (\n <FileEntry\n key={entryPath}\n entry={entry}\n entryPath={entryPath}\n isSelected={selectedPath === entryPath}\n formatSize={formatSize}\n onClick={() => onEntryClick(entry)}\n />\n );\n })}\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AA0CA,SAAgB,cAAc,EAC5B,SACA,SACA,OACA,cACA,oBACA,SACA,UACA,cACA,kBACA,eACA,gBACA,YACA,QACA,WACA,GAAG,SACkB;AACrB,QACE,oBAAC;EAAI,aAAU;EAA4B;EAAW,GAAI;YACxD,qBAAC;GAAK,WAAU;;IACb,CAAC,YAAY,sBACZ,qBAAC;KACC,MAAK;KACL,SAAS;KACT,WAAU;gBAEV,oBAAC,aAAU,WAAU,YAAY,EAChC,QAAQ,gBAAgB;MAClB;IAGV;IAEA,WACC,qBAAC;KAAI,WAAU;;MACb,oBAAC,YAAS,WAAU,gBAAgB;MACpC,oBAAC,YAAS,WAAU,gBAAgB;MACpC,oBAAC,YAAS,WAAU,gBAAgB;;MAChC;IAGP,SACC,qBAAC;KAAI,WAAU;;MACb,oBAAC,eAAY,WAAU,0CAA0C;MACjE,oBAAC;OAAE,WAAU;iBAA4B;QAAU;MAClD,WACC,oBAAC;OACC,SAAQ;OACR,MAAK;OACL,WAAU;OACV,SAAS;iBAER,QAAQ,SAAS;QACX;;MAEP;IAGP,CAAC,WAAW,CAAC,SAAS,QAAQ,WAAW,KACxC,qBAAC;KAAI,WAAU;gBACb,oBAAC,YAAS,WAAU,oCAAoC,EACxD,oBAAC;MAAE,WAAU;gBACV,iBACI,QAAQ,kBAAkB,6BAC1B,QAAQ,sBACT;OACF;MACA;IAGP,CAAC,WACA,CAAC,SACD,QAAQ,KAAK,UAAU;KACrB,MAAM,YAAY,iBAAiB,MAAM;AACzC,YACE,oBAAC;MAEQ;MACI;MACX,YAAY,iBAAiB;MACjB;MACZ,eAAe,aAAa,MAAM;QAL7B,UAML;MAEJ;;IACC;GACH"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
|
|
3
|
+
//#region src/react/file-browser/file-breadcrumb.d.ts
|
|
4
|
+
/** Props for the FileBreadcrumb component */
|
|
5
|
+
interface FileBreadcrumbProps extends Omit<React.ComponentProps<"nav">, "children"> {
|
|
6
|
+
/** Label for the root breadcrumb item */
|
|
7
|
+
rootLabel: string;
|
|
8
|
+
/** Path segments after the root */
|
|
9
|
+
segments: string[];
|
|
10
|
+
/** Called when the root breadcrumb is clicked */
|
|
11
|
+
onNavigateToRoot: () => void;
|
|
12
|
+
/** Called when a segment breadcrumb is clicked (receives segment index) */
|
|
13
|
+
onNavigateToSegment: (index: number) => void;
|
|
14
|
+
}
|
|
15
|
+
/** Path-aware breadcrumb navigation built on top of Breadcrumb primitives */
|
|
16
|
+
declare function FileBreadcrumb({
|
|
17
|
+
rootLabel,
|
|
18
|
+
segments,
|
|
19
|
+
onNavigateToRoot,
|
|
20
|
+
onNavigateToSegment,
|
|
21
|
+
...props
|
|
22
|
+
}: FileBreadcrumbProps): react_jsx_runtime0.JSX.Element;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { FileBreadcrumb, FileBreadcrumbProps };
|
|
25
|
+
//# sourceMappingURL=file-breadcrumb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-breadcrumb.d.ts","names":[],"sources":["../../../src/react/file-browser/file-breadcrumb.tsx"],"mappings":";;;;UAUiB,mBAAA,SACP,IAAA,CAAK,KAAA,CAAM,cAAA;;EAEnB,SAAA;EAFA;EAIA,QAAA;EAJY;EAMZ,gBAAA;EANa;EAQb,mBAAA,GAAsB,KAAA;AAAA;;iBAIR,cAAA,CAAA;EACd,SAAA;EACA,QAAA;EACA,gBAAA;EACA,mBAAA;EAAA,GACG;AAAA,GACF,mBAAA,GAAmB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "../ui/breadcrumb.js";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/react/file-browser/file-breadcrumb.tsx
|
|
5
|
+
/** Path-aware breadcrumb navigation built on top of Breadcrumb primitives */
|
|
6
|
+
function FileBreadcrumb({ rootLabel, segments, onNavigateToRoot, onNavigateToSegment, ...props }) {
|
|
7
|
+
return /* @__PURE__ */ jsx(Breadcrumb, {
|
|
8
|
+
"data-slot": "file-breadcrumb",
|
|
9
|
+
...props,
|
|
10
|
+
children: /* @__PURE__ */ jsxs(BreadcrumbList, { children: [/* @__PURE__ */ jsx(BreadcrumbItem, { children: segments.length > 0 ? /* @__PURE__ */ jsx(BreadcrumbLink, {
|
|
11
|
+
className: "cursor-pointer",
|
|
12
|
+
onClick: onNavigateToRoot,
|
|
13
|
+
children: rootLabel
|
|
14
|
+
}) : /* @__PURE__ */ jsx(BreadcrumbPage, { children: rootLabel }) }), segments.map((segment, index) => /* @__PURE__ */ jsxs("span", {
|
|
15
|
+
className: "contents",
|
|
16
|
+
children: [/* @__PURE__ */ jsx(BreadcrumbSeparator, {}), /* @__PURE__ */ jsx(BreadcrumbItem, { children: index === segments.length - 1 ? /* @__PURE__ */ jsx(BreadcrumbPage, { children: segment }) : /* @__PURE__ */ jsx(BreadcrumbLink, {
|
|
17
|
+
className: "cursor-pointer",
|
|
18
|
+
onClick: () => onNavigateToSegment(index),
|
|
19
|
+
children: segment
|
|
20
|
+
}) })]
|
|
21
|
+
}, segment))] })
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
export { FileBreadcrumb };
|
|
27
|
+
//# sourceMappingURL=file-breadcrumb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-breadcrumb.js","names":[],"sources":["../../../src/react/file-browser/file-breadcrumb.tsx"],"sourcesContent":["import {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"../ui/breadcrumb\";\n\n/** Props for the FileBreadcrumb component */\nexport interface FileBreadcrumbProps\n extends Omit<React.ComponentProps<\"nav\">, \"children\"> {\n /** Label for the root breadcrumb item */\n rootLabel: string;\n /** Path segments after the root */\n segments: string[];\n /** Called when the root breadcrumb is clicked */\n onNavigateToRoot: () => void;\n /** Called when a segment breadcrumb is clicked (receives segment index) */\n onNavigateToSegment: (index: number) => void;\n}\n\n/** Path-aware breadcrumb navigation built on top of Breadcrumb primitives */\nexport function FileBreadcrumb({\n rootLabel,\n segments,\n onNavigateToRoot,\n onNavigateToSegment,\n ...props\n}: FileBreadcrumbProps) {\n return (\n <Breadcrumb data-slot=\"file-breadcrumb\" {...props}>\n <BreadcrumbList>\n <BreadcrumbItem>\n {segments.length > 0 ? (\n <BreadcrumbLink\n className=\"cursor-pointer\"\n onClick={onNavigateToRoot}\n >\n {rootLabel}\n </BreadcrumbLink>\n ) : (\n <BreadcrumbPage>{rootLabel}</BreadcrumbPage>\n )}\n </BreadcrumbItem>\n {segments.map((segment, index) => (\n <span key={segment} className=\"contents\">\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n {index === segments.length - 1 ? (\n <BreadcrumbPage>{segment}</BreadcrumbPage>\n ) : (\n <BreadcrumbLink\n className=\"cursor-pointer\"\n onClick={() => onNavigateToSegment(index)}\n >\n {segment}\n </BreadcrumbLink>\n )}\n </BreadcrumbItem>\n </span>\n ))}\n </BreadcrumbList>\n </Breadcrumb>\n );\n}\n"],"mappings":";;;;;AAuBA,SAAgB,eAAe,EAC7B,WACA,UACA,kBACA,qBACA,GAAG,SACmB;AACtB,QACE,oBAAC;EAAW,aAAU;EAAkB,GAAI;YAC1C,qBAAC,6BACC,oBAAC,4BACE,SAAS,SAAS,IACjB,oBAAC;GACC,WAAU;GACV,SAAS;aAER;IACc,GAEjB,oBAAC,4BAAgB,YAA2B,GAE/B,EAChB,SAAS,KAAK,SAAS,UACtB,qBAAC;GAAmB,WAAU;cAC5B,oBAAC,wBAAsB,EACvB,oBAAC,4BACE,UAAU,SAAS,SAAS,IAC3B,oBAAC,4BAAgB,UAAyB,GAE1C,oBAAC;IACC,WAAU;IACV,eAAe,oBAAoB,MAAM;cAExC;KACc,GAEJ;KAbR,QAcJ,CACP,IACa;GACN"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { DirectoryEntry } from "./types.js";
|
|
2
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/react/file-browser/file-entry.d.ts
|
|
5
|
+
/** Props for the FileEntry component */
|
|
6
|
+
interface FileEntryProps extends Omit<React.ComponentProps<"button">, "children"> {
|
|
7
|
+
/** The directory entry to render */
|
|
8
|
+
entry: DirectoryEntry;
|
|
9
|
+
/** Resolved full path for this entry */
|
|
10
|
+
entryPath: string;
|
|
11
|
+
/** Whether this entry is currently selected */
|
|
12
|
+
isSelected?: boolean;
|
|
13
|
+
/** Custom file size formatter (defaults to formatFileSize) */
|
|
14
|
+
formatSize?: (bytes: number | undefined) => string;
|
|
15
|
+
}
|
|
16
|
+
/** Single file or directory row with icon, name, size, and selection state */
|
|
17
|
+
declare function FileEntry({
|
|
18
|
+
entry,
|
|
19
|
+
entryPath,
|
|
20
|
+
isSelected,
|
|
21
|
+
formatSize,
|
|
22
|
+
className,
|
|
23
|
+
...props
|
|
24
|
+
}: FileEntryProps): react_jsx_runtime0.JSX.Element;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { FileEntry, FileEntryProps };
|
|
27
|
+
//# sourceMappingURL=file-entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-entry.d.ts","names":[],"sources":["../../../src/react/file-browser/file-entry.tsx"],"mappings":";;;;;UAMiB,cAAA,SACP,IAAA,CAAK,KAAA,CAAM,cAAA;;EAEnB,KAAA,EAAO,cAAA;EAFP;EAIA,SAAA;EAJa;EAMb,UAAA;EANQ;EAQR,UAAA,IAAc,KAAA;AAAA;;iBAIA,SAAA,CAAA;EACd,KAAA;EACA,SAAA;EACA,UAAA;EACA,UAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,cAAA,GAAc,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { formatFileSize } from "../lib/format.js";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { ChevronRight, FileIcon, FolderIcon } from "lucide-react";
|
|
5
|
+
|
|
6
|
+
//#region src/react/file-browser/file-entry.tsx
|
|
7
|
+
/** Single file or directory row with icon, name, size, and selection state */
|
|
8
|
+
function FileEntry({ entry, entryPath, isSelected, formatSize = formatFileSize, className, ...props }) {
|
|
9
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
10
|
+
type: "button",
|
|
11
|
+
"data-slot": "file-entry",
|
|
12
|
+
className: cn("flex items-center gap-3 px-4 py-3 w-full text-left hover:bg-muted/50 border-b last:border-b-0 transition-colors", isSelected && "bg-muted", className),
|
|
13
|
+
...props,
|
|
14
|
+
children: [
|
|
15
|
+
entry.is_directory ? /* @__PURE__ */ jsx(FolderIcon, { className: "h-5 w-5 text-blue-500 shrink-0" }) : /* @__PURE__ */ jsx(FileIcon, { className: "h-5 w-5 text-muted-foreground shrink-0" }),
|
|
16
|
+
/* @__PURE__ */ jsx("span", {
|
|
17
|
+
className: "flex-1 truncate text-sm text-foreground",
|
|
18
|
+
children: entry.name ?? entryPath.split("/").pop()
|
|
19
|
+
}),
|
|
20
|
+
entry.is_directory && /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
|
|
21
|
+
!entry.is_directory && entry.file_size !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
22
|
+
className: "text-xs text-muted-foreground shrink-0",
|
|
23
|
+
children: formatSize(entry.file_size)
|
|
24
|
+
})
|
|
25
|
+
]
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { FileEntry };
|
|
31
|
+
//# sourceMappingURL=file-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-entry.js","names":[],"sources":["../../../src/react/file-browser/file-entry.tsx"],"sourcesContent":["import { ChevronRight, FileIcon, FolderIcon } from \"lucide-react\";\nimport { formatFileSize } from \"../lib/format\";\nimport { cn } from \"../lib/utils\";\nimport type { DirectoryEntry } from \"./types\";\n\n/** Props for the FileEntry component */\nexport interface FileEntryProps\n extends Omit<React.ComponentProps<\"button\">, \"children\"> {\n /** The directory entry to render */\n entry: DirectoryEntry;\n /** Resolved full path for this entry */\n entryPath: string;\n /** Whether this entry is currently selected */\n isSelected?: boolean;\n /** Custom file size formatter (defaults to formatFileSize) */\n formatSize?: (bytes: number | undefined) => string;\n}\n\n/** Single file or directory row with icon, name, size, and selection state */\nexport function FileEntry({\n entry,\n entryPath,\n isSelected,\n formatSize = formatFileSize,\n className,\n ...props\n}: FileEntryProps) {\n return (\n <button\n type=\"button\"\n data-slot=\"file-entry\"\n className={cn(\n \"flex items-center gap-3 px-4 py-3 w-full text-left hover:bg-muted/50 border-b last:border-b-0 transition-colors\",\n isSelected && \"bg-muted\",\n className,\n )}\n {...props}\n >\n {entry.is_directory ? (\n <FolderIcon className=\"h-5 w-5 text-blue-500 shrink-0\" />\n ) : (\n <FileIcon className=\"h-5 w-5 text-muted-foreground shrink-0\" />\n )}\n <span className=\"flex-1 truncate text-sm text-foreground\">\n {entry.name ?? entryPath.split(\"/\").pop()}\n </span>\n {entry.is_directory && (\n <ChevronRight className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n )}\n {!entry.is_directory && entry.file_size !== undefined && (\n <span className=\"text-xs text-muted-foreground shrink-0\">\n {formatSize(entry.file_size)}\n </span>\n )}\n </button>\n );\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,UAAU,EACxB,OACA,WACA,YACA,aAAa,gBACb,WACA,GAAG,SACc;AACjB,QACE,qBAAC;EACC,MAAK;EACL,aAAU;EACV,WAAW,GACT,mHACA,cAAc,YACd,UACD;EACD,GAAI;;GAEH,MAAM,eACL,oBAAC,cAAW,WAAU,mCAAmC,GAEzD,oBAAC,YAAS,WAAU,2CAA2C;GAEjE,oBAAC;IAAK,WAAU;cACb,MAAM,QAAQ,UAAU,MAAM,IAAI,CAAC,KAAK;KACpC;GACN,MAAM,gBACL,oBAAC,gBAAa,WAAU,2CAA2C;GAEpE,CAAC,MAAM,gBAAgB,MAAM,cAAc,UAC1C,oBAAC;IAAK,WAAU;cACb,WAAW,MAAM,UAAU;KACvB;;GAEF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { FileBrowserLabels, FilePreview } from "./types.js";
|
|
2
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/react/file-browser/file-preview-panel.d.ts
|
|
5
|
+
/** Props for the FilePreviewPanel component */
|
|
6
|
+
interface FilePreviewPanelProps extends Omit<React.ComponentProps<"div">, "children"> {
|
|
7
|
+
/** Full path of the selected file (null when nothing is selected) */
|
|
8
|
+
selectedFile: string | null;
|
|
9
|
+
/** Preview data for the selected file */
|
|
10
|
+
preview: FilePreview | null;
|
|
11
|
+
/** Whether the preview is loading */
|
|
12
|
+
previewLoading?: boolean;
|
|
13
|
+
/** Called when the download button is clicked */
|
|
14
|
+
onDownload?: (filePath: string) => void;
|
|
15
|
+
/** Called when the delete button is clicked */
|
|
16
|
+
onDelete?: (filePath: string) => void;
|
|
17
|
+
/** Whether a delete operation is in progress */
|
|
18
|
+
deleting?: boolean;
|
|
19
|
+
/** Image preview source — string URL or function that receives the file path */
|
|
20
|
+
imagePreviewSrc?: string | ((filePath: string) => string);
|
|
21
|
+
/** Custom file size formatter (defaults to formatFileSize) */
|
|
22
|
+
formatSize?: (bytes: number | undefined) => string;
|
|
23
|
+
/** Customizable labels */
|
|
24
|
+
labels?: Pick<FileBrowserLabels, "selectFilePrompt" | "previewNotAvailable" | "previewFailed" | "download" | "size" | "type" | "modified" | "unknown">;
|
|
25
|
+
}
|
|
26
|
+
/** Preview panel displaying file metadata, image/text preview, and download/delete actions */
|
|
27
|
+
declare function FilePreviewPanel({
|
|
28
|
+
selectedFile,
|
|
29
|
+
preview,
|
|
30
|
+
previewLoading,
|
|
31
|
+
onDownload,
|
|
32
|
+
onDelete,
|
|
33
|
+
deleting,
|
|
34
|
+
imagePreviewSrc,
|
|
35
|
+
formatSize,
|
|
36
|
+
labels,
|
|
37
|
+
className,
|
|
38
|
+
...props
|
|
39
|
+
}: FilePreviewPanelProps): react_jsx_runtime0.JSX.Element;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { FilePreviewPanel, FilePreviewPanelProps };
|
|
42
|
+
//# sourceMappingURL=file-preview-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-preview-panel.d.ts","names":[],"sources":["../../../src/react/file-browser/file-preview-panel.tsx"],"mappings":";;;;;UAQiB,qBAAA,SACP,IAAA,CAAK,KAAA,CAAM,cAAA;;EAEnB,YAAA;EAFA;EAIA,OAAA,EAAS,WAAA;EAJI;EAMb,cAAA;EAaE;EAXF,UAAA,IAAc,QAAA;EARN;EAUR,QAAA,IAAY,QAAA;EAVA;EAYZ,QAAA;EAZa;EAcb,eAAA,cAA6B,QAAA;EAZ7B;EAcA,UAAA,IAAc,KAAA;EAZL;EAcT,MAAA,GAAS,IAAA,CACP,iBAAA;AAAA;;iBAaY,gBAAA,CAAA;EACd,YAAA;EACA,OAAA;EACA,cAAA;EACA,UAAA;EACA,QAAA;EACA,QAAA;EACA,eAAA;EACA,UAAA;EACA,MAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,qBAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { formatFileSize } from "../lib/format.js";
|
|
2
|
+
import { Button } from "../ui/button.js";
|
|
3
|
+
import { Card } from "../ui/card.js";
|
|
4
|
+
import { Skeleton } from "../ui/skeleton.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { AlertCircle, Download, FileIcon, Loader2, Trash2 } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
//#region src/react/file-browser/file-preview-panel.tsx
|
|
9
|
+
/** Preview panel displaying file metadata, image/text preview, and download/delete actions */
|
|
10
|
+
function FilePreviewPanel({ selectedFile, preview, previewLoading, onDownload, onDelete, deleting, imagePreviewSrc, formatSize = formatFileSize, labels, className, ...props }) {
|
|
11
|
+
const resolveImageSrc = (filePath) => {
|
|
12
|
+
if (!imagePreviewSrc) return "";
|
|
13
|
+
if (typeof imagePreviewSrc === "string") return imagePreviewSrc;
|
|
14
|
+
return imagePreviewSrc(filePath);
|
|
15
|
+
};
|
|
16
|
+
return /* @__PURE__ */ jsx("div", {
|
|
17
|
+
"data-slot": "file-preview-panel",
|
|
18
|
+
className,
|
|
19
|
+
...props,
|
|
20
|
+
children: /* @__PURE__ */ jsxs(Card, {
|
|
21
|
+
className: "p-6",
|
|
22
|
+
children: [
|
|
23
|
+
!selectedFile && /* @__PURE__ */ jsxs("div", {
|
|
24
|
+
className: "text-center text-muted-foreground py-8",
|
|
25
|
+
children: [/* @__PURE__ */ jsx(FileIcon, { className: "h-10 w-10 mx-auto mb-3 opacity-40" }), /* @__PURE__ */ jsx("p", {
|
|
26
|
+
className: "text-sm",
|
|
27
|
+
children: labels?.selectFilePrompt ?? "Select a file to preview"
|
|
28
|
+
})]
|
|
29
|
+
}),
|
|
30
|
+
selectedFile && previewLoading && /* @__PURE__ */ jsxs("div", {
|
|
31
|
+
className: "space-y-3",
|
|
32
|
+
children: [
|
|
33
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-3/4" }),
|
|
34
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-1/2" }),
|
|
35
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-2/3" }),
|
|
36
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-32 w-full mt-4" })
|
|
37
|
+
]
|
|
38
|
+
}),
|
|
39
|
+
selectedFile && !previewLoading && preview && /* @__PURE__ */ jsxs("div", {
|
|
40
|
+
className: "space-y-4",
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
|
|
43
|
+
className: "font-semibold text-foreground truncate mb-1",
|
|
44
|
+
children: selectedFile.split("/").pop()
|
|
45
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
46
|
+
className: "text-xs text-muted-foreground truncate",
|
|
47
|
+
children: selectedFile
|
|
48
|
+
})] }),
|
|
49
|
+
/* @__PURE__ */ jsxs("div", {
|
|
50
|
+
className: "space-y-2 text-sm",
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ jsxs("div", {
|
|
53
|
+
className: "flex justify-between",
|
|
54
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
55
|
+
className: "text-muted-foreground",
|
|
56
|
+
children: labels?.size ?? "Size"
|
|
57
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
58
|
+
className: "text-foreground",
|
|
59
|
+
children: formatSize(preview.contentLength)
|
|
60
|
+
})]
|
|
61
|
+
}),
|
|
62
|
+
/* @__PURE__ */ jsxs("div", {
|
|
63
|
+
className: "flex justify-between",
|
|
64
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
65
|
+
className: "text-muted-foreground",
|
|
66
|
+
children: labels?.type ?? "Type"
|
|
67
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
68
|
+
className: "text-foreground truncate ml-2",
|
|
69
|
+
children: preview.contentType ?? labels?.unknown ?? "Unknown"
|
|
70
|
+
})]
|
|
71
|
+
}),
|
|
72
|
+
preview.lastModified && /* @__PURE__ */ jsxs("div", {
|
|
73
|
+
className: "flex justify-between",
|
|
74
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
75
|
+
className: "text-muted-foreground",
|
|
76
|
+
children: labels?.modified ?? "Modified"
|
|
77
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
78
|
+
className: "text-foreground",
|
|
79
|
+
children: preview.lastModified
|
|
80
|
+
})]
|
|
81
|
+
})
|
|
82
|
+
]
|
|
83
|
+
}),
|
|
84
|
+
/* @__PURE__ */ jsxs("div", {
|
|
85
|
+
className: "flex gap-2",
|
|
86
|
+
children: [onDownload && /* @__PURE__ */ jsxs(Button, {
|
|
87
|
+
variant: "outline",
|
|
88
|
+
size: "sm",
|
|
89
|
+
className: "flex-1",
|
|
90
|
+
onClick: () => onDownload(selectedFile),
|
|
91
|
+
children: [/* @__PURE__ */ jsx(Download, { className: "h-4 w-4 mr-2" }), labels?.download ?? "Download"]
|
|
92
|
+
}), onDelete && /* @__PURE__ */ jsx(Button, {
|
|
93
|
+
variant: "destructive",
|
|
94
|
+
size: "sm",
|
|
95
|
+
disabled: deleting,
|
|
96
|
+
onClick: () => onDelete(selectedFile),
|
|
97
|
+
children: deleting ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
|
|
98
|
+
})]
|
|
99
|
+
}),
|
|
100
|
+
preview.isImage && imagePreviewSrc && /* @__PURE__ */ jsx("div", {
|
|
101
|
+
className: "border rounded overflow-hidden",
|
|
102
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
103
|
+
src: resolveImageSrc(selectedFile),
|
|
104
|
+
alt: selectedFile.split("/").pop() ?? "Preview",
|
|
105
|
+
className: "w-full h-auto"
|
|
106
|
+
})
|
|
107
|
+
}),
|
|
108
|
+
preview.isText && preview.textPreview !== null && /* @__PURE__ */ jsx("div", {
|
|
109
|
+
className: "border rounded",
|
|
110
|
+
children: /* @__PURE__ */ jsx("pre", {
|
|
111
|
+
className: "p-3 text-xs font-mono overflow-auto max-h-80 whitespace-pre-wrap text-foreground bg-muted/30",
|
|
112
|
+
children: preview.textPreview
|
|
113
|
+
})
|
|
114
|
+
}),
|
|
115
|
+
!preview.isText && !preview.isImage && /* @__PURE__ */ jsx("div", {
|
|
116
|
+
className: "text-center py-4 text-sm text-muted-foreground",
|
|
117
|
+
children: labels?.previewNotAvailable ?? "Preview not available for this file type."
|
|
118
|
+
})
|
|
119
|
+
]
|
|
120
|
+
}),
|
|
121
|
+
selectedFile && !previewLoading && !preview && /* @__PURE__ */ jsxs("div", {
|
|
122
|
+
className: "text-center py-8",
|
|
123
|
+
children: [/* @__PURE__ */ jsx(AlertCircle, { className: "h-8 w-8 text-destructive mx-auto mb-2" }), /* @__PURE__ */ jsx("p", {
|
|
124
|
+
className: "text-sm text-destructive",
|
|
125
|
+
children: labels?.previewFailed ?? "Failed to load preview"
|
|
126
|
+
})]
|
|
127
|
+
})
|
|
128
|
+
]
|
|
129
|
+
})
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
export { FilePreviewPanel };
|
|
135
|
+
//# sourceMappingURL=file-preview-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-preview-panel.js","names":[],"sources":["../../../src/react/file-browser/file-preview-panel.tsx"],"sourcesContent":["import { AlertCircle, Download, FileIcon, Loader2, Trash2 } from \"lucide-react\";\nimport { formatFileSize } from \"../lib/format\";\nimport { Button } from \"../ui/button\";\nimport { Card } from \"../ui/card\";\nimport { Skeleton } from \"../ui/skeleton\";\nimport type { FileBrowserLabels, FilePreview } from \"./types\";\n\n/** Props for the FilePreviewPanel component */\nexport interface FilePreviewPanelProps\n extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** Full path of the selected file (null when nothing is selected) */\n selectedFile: string | null;\n /** Preview data for the selected file */\n preview: FilePreview | null;\n /** Whether the preview is loading */\n previewLoading?: boolean;\n /** Called when the download button is clicked */\n onDownload?: (filePath: string) => void;\n /** Called when the delete button is clicked */\n onDelete?: (filePath: string) => void;\n /** Whether a delete operation is in progress */\n deleting?: boolean;\n /** Image preview source — string URL or function that receives the file path */\n imagePreviewSrc?: string | ((filePath: string) => string);\n /** Custom file size formatter (defaults to formatFileSize) */\n formatSize?: (bytes: number | undefined) => string;\n /** Customizable labels */\n labels?: Pick<\n FileBrowserLabels,\n | \"selectFilePrompt\"\n | \"previewNotAvailable\"\n | \"previewFailed\"\n | \"download\"\n | \"size\"\n | \"type\"\n | \"modified\"\n | \"unknown\"\n >;\n}\n\n/** Preview panel displaying file metadata, image/text preview, and download/delete actions */\nexport function FilePreviewPanel({\n selectedFile,\n preview,\n previewLoading,\n onDownload,\n onDelete,\n deleting,\n imagePreviewSrc,\n formatSize = formatFileSize,\n labels,\n className,\n ...props\n}: FilePreviewPanelProps) {\n const resolveImageSrc = (filePath: string) => {\n if (!imagePreviewSrc) return \"\";\n if (typeof imagePreviewSrc === \"string\") return imagePreviewSrc;\n return imagePreviewSrc(filePath);\n };\n\n return (\n <div data-slot=\"file-preview-panel\" className={className} {...props}>\n <Card className=\"p-6\">\n {/* No file selected */}\n {!selectedFile && (\n <div className=\"text-center text-muted-foreground py-8\">\n <FileIcon className=\"h-10 w-10 mx-auto mb-3 opacity-40\" />\n <p className=\"text-sm\">\n {labels?.selectFilePrompt ?? \"Select a file to preview\"}\n </p>\n </div>\n )}\n\n {/* Loading state */}\n {selectedFile && previewLoading && (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-5 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-4 w-2/3\" />\n <Skeleton className=\"h-32 w-full mt-4\" />\n </div>\n )}\n\n {/* Preview content */}\n {selectedFile && !previewLoading && preview && (\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"font-semibold text-foreground truncate mb-1\">\n {selectedFile.split(\"/\").pop()}\n </h3>\n <p className=\"text-xs text-muted-foreground truncate\">\n {selectedFile}\n </p>\n </div>\n\n <div className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {labels?.size ?? \"Size\"}\n </span>\n <span className=\"text-foreground\">\n {formatSize(preview.contentLength)}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {labels?.type ?? \"Type\"}\n </span>\n <span className=\"text-foreground truncate ml-2\">\n {preview.contentType ?? labels?.unknown ?? \"Unknown\"}\n </span>\n </div>\n {preview.lastModified && (\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {labels?.modified ?? \"Modified\"}\n </span>\n <span className=\"text-foreground\">\n {preview.lastModified}\n </span>\n </div>\n )}\n </div>\n\n <div className=\"flex gap-2\">\n {onDownload && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"flex-1\"\n onClick={() => onDownload(selectedFile)}\n >\n <Download className=\"h-4 w-4 mr-2\" />\n {labels?.download ?? \"Download\"}\n </Button>\n )}\n {onDelete && (\n <Button\n variant=\"destructive\"\n size=\"sm\"\n disabled={deleting}\n onClick={() => onDelete(selectedFile)}\n >\n {deleting ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Trash2 className=\"h-4 w-4\" />\n )}\n </Button>\n )}\n </div>\n\n {preview.isImage && imagePreviewSrc && (\n <div className=\"border rounded overflow-hidden\">\n <img\n src={resolveImageSrc(selectedFile)}\n alt={selectedFile.split(\"/\").pop() ?? \"Preview\"}\n className=\"w-full h-auto\"\n />\n </div>\n )}\n\n {preview.isText && preview.textPreview !== null && (\n <div className=\"border rounded\">\n <pre className=\"p-3 text-xs font-mono overflow-auto max-h-80 whitespace-pre-wrap text-foreground bg-muted/30\">\n {preview.textPreview}\n </pre>\n </div>\n )}\n\n {!preview.isText && !preview.isImage && (\n <div className=\"text-center py-4 text-sm text-muted-foreground\">\n {labels?.previewNotAvailable ??\n \"Preview not available for this file type.\"}\n </div>\n )}\n </div>\n )}\n\n {/* Preview load failed */}\n {selectedFile && !previewLoading && !preview && (\n <div className=\"text-center py-8\">\n <AlertCircle className=\"h-8 w-8 text-destructive mx-auto mb-2\" />\n <p className=\"text-sm text-destructive\">\n {labels?.previewFailed ?? \"Failed to load preview\"}\n </p>\n </div>\n )}\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAyCA,SAAgB,iBAAiB,EAC/B,cACA,SACA,gBACA,YACA,UACA,UACA,iBACA,aAAa,gBACb,QACA,WACA,GAAG,SACqB;CACxB,MAAM,mBAAmB,aAAqB;AAC5C,MAAI,CAAC,gBAAiB,QAAO;AAC7B,MAAI,OAAO,oBAAoB,SAAU,QAAO;AAChD,SAAO,gBAAgB,SAAS;;AAGlC,QACE,oBAAC;EAAI,aAAU;EAAgC;EAAW,GAAI;YAC5D,qBAAC;GAAK,WAAU;;IAEb,CAAC,gBACA,qBAAC;KAAI,WAAU;gBACb,oBAAC,YAAS,WAAU,sCAAsC,EAC1D,oBAAC;MAAE,WAAU;gBACV,QAAQ,oBAAoB;OAC3B;MACA;IAIP,gBAAgB,kBACf,qBAAC;KAAI,WAAU;;MACb,oBAAC,YAAS,WAAU,cAAc;MAClC,oBAAC,YAAS,WAAU,cAAc;MAClC,oBAAC,YAAS,WAAU,cAAc;MAClC,oBAAC,YAAS,WAAU,qBAAqB;;MACrC;IAIP,gBAAgB,CAAC,kBAAkB,WAClC,qBAAC;KAAI,WAAU;;MACb,qBAAC,oBACC,oBAAC;OAAG,WAAU;iBACX,aAAa,MAAM,IAAI,CAAC,KAAK;QAC3B,EACL,oBAAC;OAAE,WAAU;iBACV;QACC,IACA;MAEN,qBAAC;OAAI,WAAU;;QACb,qBAAC;SAAI,WAAU;oBACb,oBAAC;UAAK,WAAU;oBACb,QAAQ,QAAQ;WACZ,EACP,oBAAC;UAAK,WAAU;oBACb,WAAW,QAAQ,cAAc;WAC7B;UACH;QACN,qBAAC;SAAI,WAAU;oBACb,oBAAC;UAAK,WAAU;oBACb,QAAQ,QAAQ;WACZ,EACP,oBAAC;UAAK,WAAU;oBACb,QAAQ,eAAe,QAAQ,WAAW;WACtC;UACH;QACL,QAAQ,gBACP,qBAAC;SAAI,WAAU;oBACb,oBAAC;UAAK,WAAU;oBACb,QAAQ,YAAY;WAChB,EACP,oBAAC;UAAK,WAAU;oBACb,QAAQ;WACJ;UACH;;QAEJ;MAEN,qBAAC;OAAI,WAAU;kBACZ,cACC,qBAAC;QACC,SAAQ;QACR,MAAK;QACL,WAAU;QACV,eAAe,WAAW,aAAa;mBAEvC,oBAAC,YAAS,WAAU,iBAAiB,EACpC,QAAQ,YAAY;SACd,EAEV,YACC,oBAAC;QACC,SAAQ;QACR,MAAK;QACL,UAAU;QACV,eAAe,SAAS,aAAa;kBAEpC,WACC,oBAAC,WAAQ,WAAU,yBAAyB,GAE5C,oBAAC,UAAO,WAAU,YAAY;SAEzB;QAEP;MAEL,QAAQ,WAAW,mBAClB,oBAAC;OAAI,WAAU;iBACb,oBAAC;QACC,KAAK,gBAAgB,aAAa;QAClC,KAAK,aAAa,MAAM,IAAI,CAAC,KAAK,IAAI;QACtC,WAAU;SACV;QACE;MAGP,QAAQ,UAAU,QAAQ,gBAAgB,QACzC,oBAAC;OAAI,WAAU;iBACb,oBAAC;QAAI,WAAU;kBACZ,QAAQ;SACL;QACF;MAGP,CAAC,QAAQ,UAAU,CAAC,QAAQ,WAC3B,oBAAC;OAAI,WAAU;iBACZ,QAAQ,uBACP;QACE;;MAEJ;IAIP,gBAAgB,CAAC,kBAAkB,CAAC,WACnC,qBAAC;KAAI,WAAU;gBACb,oBAAC,eAAY,WAAU,0CAA0C,EACjE,oBAAC;MAAE,WAAU;gBACV,QAAQ,iBAAiB;OACxB;MACA;;IAEH;GACH"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { formatFileSize } from "../lib/format.js";
|
|
2
|
+
import { DirectoryEntry, FileBrowserLabels, FilePreview } from "./types.js";
|
|
3
|
+
import { DirectoryList, DirectoryListProps } from "./directory-list.js";
|
|
4
|
+
import { FileBreadcrumb, FileBreadcrumbProps } from "./file-breadcrumb.js";
|
|
5
|
+
import { FileEntry, FileEntryProps } from "./file-entry.js";
|
|
6
|
+
import { FilePreviewPanel, FilePreviewPanelProps } from "./file-preview-panel.js";
|
|
7
|
+
import { NewFolderInput, NewFolderInputProps } from "./new-folder-input.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { formatFileSize } from "../lib/format.js";
|
|
2
|
+
import { FileEntry } from "./file-entry.js";
|
|
3
|
+
import { DirectoryList } from "./directory-list.js";
|
|
4
|
+
import { FileBreadcrumb } from "./file-breadcrumb.js";
|
|
5
|
+
import { FilePreviewPanel } from "./file-preview-panel.js";
|
|
6
|
+
import { NewFolderInput } from "./new-folder-input.js";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { FileBrowserLabels } from "./types.js";
|
|
2
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/react/file-browser/new-folder-input.d.ts
|
|
5
|
+
/** Props for the NewFolderInput component */
|
|
6
|
+
interface NewFolderInputProps extends Omit<React.ComponentProps<"div">, "children" | "onChange"> {
|
|
7
|
+
/** Current folder name value */
|
|
8
|
+
value: string;
|
|
9
|
+
/** Called when folder name changes */
|
|
10
|
+
onChange: (value: string) => void;
|
|
11
|
+
/** Called when the user confirms creation */
|
|
12
|
+
onCreate: () => void;
|
|
13
|
+
/** Called when the user cancels */
|
|
14
|
+
onCancel: () => void;
|
|
15
|
+
/** Whether folder creation is in progress */
|
|
16
|
+
creating?: boolean;
|
|
17
|
+
/** Auto-focus the input on mount */
|
|
18
|
+
autoFocus?: boolean;
|
|
19
|
+
/** Customizable labels */
|
|
20
|
+
labels?: Pick<FileBrowserLabels, "create" | "folderNamePlaceholder">;
|
|
21
|
+
}
|
|
22
|
+
/** Inline folder-name input with create/cancel actions */
|
|
23
|
+
declare function NewFolderInput({
|
|
24
|
+
value,
|
|
25
|
+
onChange,
|
|
26
|
+
onCreate,
|
|
27
|
+
onCancel,
|
|
28
|
+
creating,
|
|
29
|
+
autoFocus,
|
|
30
|
+
labels,
|
|
31
|
+
className,
|
|
32
|
+
...props
|
|
33
|
+
}: NewFolderInputProps): react_jsx_runtime0.JSX.Element;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { NewFolderInput, NewFolderInputProps };
|
|
36
|
+
//# sourceMappingURL=new-folder-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"new-folder-input.d.ts","names":[],"sources":["../../../src/react/file-browser/new-folder-input.tsx"],"mappings":";;;;;UAOiB,mBAAA,SACP,IAAA,CAAK,KAAA,CAAM,cAAA;;EAEnB,KAAA;EAFA;EAIA,QAAA,GAAW,KAAA;EAJE;EAMb,QAAA;EAQS;EANT,QAAA;EARY;EAUZ,QAAA;EAVQ;EAYR,SAAA;EAZmB;EAcnB,MAAA,GAAS,IAAA,CAAK,iBAAA;AAAA;;iBAIA,cAAA,CAAA;EACd,KAAA;EACA,QAAA;EACA,QAAA;EACA,QAAA;EACA,QAAA;EACA,SAAA;EACA,MAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,mBAAA,GAAmB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Button } from "../ui/button.js";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { FolderPlus, Loader2, X } from "lucide-react";
|
|
6
|
+
|
|
7
|
+
//#region src/react/file-browser/new-folder-input.tsx
|
|
8
|
+
/** Inline folder-name input with create/cancel actions */
|
|
9
|
+
function NewFolderInput({ value, onChange, onCreate, onCancel, creating, autoFocus = true, labels, className, ...props }) {
|
|
10
|
+
const inputRef = useRef(null);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (autoFocus) inputRef.current?.focus();
|
|
13
|
+
}, [autoFocus]);
|
|
14
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
15
|
+
"data-slot": "new-folder-input",
|
|
16
|
+
className: cn("flex items-center gap-2 px-4 py-3 border-b bg-muted/30", className),
|
|
17
|
+
...props,
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ jsx(FolderPlus, { className: "h-5 w-5 text-blue-500 shrink-0" }),
|
|
20
|
+
/* @__PURE__ */ jsx("input", {
|
|
21
|
+
ref: inputRef,
|
|
22
|
+
type: "text",
|
|
23
|
+
value,
|
|
24
|
+
onChange: (e) => onChange(e.target.value),
|
|
25
|
+
onKeyDown: (e) => {
|
|
26
|
+
if (e.key === "Enter") onCreate();
|
|
27
|
+
if (e.key === "Escape") onCancel();
|
|
28
|
+
},
|
|
29
|
+
placeholder: labels?.folderNamePlaceholder ?? "Folder name",
|
|
30
|
+
className: "flex-1 text-sm bg-background border rounded px-2 py-1 outline-none focus:ring-1 focus:ring-ring",
|
|
31
|
+
disabled: creating
|
|
32
|
+
}),
|
|
33
|
+
/* @__PURE__ */ jsx(Button, {
|
|
34
|
+
variant: "ghost",
|
|
35
|
+
size: "sm",
|
|
36
|
+
disabled: creating || !value.trim(),
|
|
37
|
+
onClick: onCreate,
|
|
38
|
+
children: creating ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : labels?.create ?? "Create"
|
|
39
|
+
}),
|
|
40
|
+
/* @__PURE__ */ jsx("button", {
|
|
41
|
+
type: "button",
|
|
42
|
+
onClick: onCancel,
|
|
43
|
+
className: "text-muted-foreground hover:text-foreground",
|
|
44
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
45
|
+
})
|
|
46
|
+
]
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { NewFolderInput };
|
|
52
|
+
//# sourceMappingURL=new-folder-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"new-folder-input.js","names":[],"sources":["../../../src/react/file-browser/new-folder-input.tsx"],"sourcesContent":["import { FolderPlus, Loader2, X } from \"lucide-react\";\nimport { useEffect, useRef } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"../ui/button\";\nimport type { FileBrowserLabels } from \"./types\";\n\n/** Props for the NewFolderInput component */\nexport interface NewFolderInputProps\n extends Omit<React.ComponentProps<\"div\">, \"children\" | \"onChange\"> {\n /** Current folder name value */\n value: string;\n /** Called when folder name changes */\n onChange: (value: string) => void;\n /** Called when the user confirms creation */\n onCreate: () => void;\n /** Called when the user cancels */\n onCancel: () => void;\n /** Whether folder creation is in progress */\n creating?: boolean;\n /** Auto-focus the input on mount */\n autoFocus?: boolean;\n /** Customizable labels */\n labels?: Pick<FileBrowserLabels, \"create\" | \"folderNamePlaceholder\">;\n}\n\n/** Inline folder-name input with create/cancel actions */\nexport function NewFolderInput({\n value,\n onChange,\n onCreate,\n onCancel,\n creating,\n autoFocus = true,\n labels,\n className,\n ...props\n}: NewFolderInputProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (autoFocus) {\n inputRef.current?.focus();\n }\n }, [autoFocus]);\n\n return (\n <div\n data-slot=\"new-folder-input\"\n className={cn(\n \"flex items-center gap-2 px-4 py-3 border-b bg-muted/30\",\n className,\n )}\n {...props}\n >\n <FolderPlus className=\"h-5 w-5 text-blue-500 shrink-0\" />\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") onCreate();\n if (e.key === \"Escape\") onCancel();\n }}\n placeholder={labels?.folderNamePlaceholder ?? \"Folder name\"}\n className=\"flex-1 text-sm bg-background border rounded px-2 py-1 outline-none focus:ring-1 focus:ring-ring\"\n disabled={creating}\n />\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={creating || !value.trim()}\n onClick={onCreate}\n >\n {creating ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n (labels?.create ?? \"Create\")\n )}\n </Button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"text-muted-foreground hover:text-foreground\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AA0BA,SAAgB,eAAe,EAC7B,OACA,UACA,UACA,UACA,UACA,YAAY,MACZ,QACA,WACA,GAAG,SACmB;CACtB,MAAM,WAAW,OAAyB,KAAK;AAE/C,iBAAgB;AACd,MAAI,UACF,UAAS,SAAS,OAAO;IAE1B,CAAC,UAAU,CAAC;AAEf,QACE,qBAAC;EACC,aAAU;EACV,WAAW,GACT,0DACA,UACD;EACD,GAAI;;GAEJ,oBAAC,cAAW,WAAU,mCAAmC;GACzD,oBAAC;IACC,KAAK;IACL,MAAK;IACE;IACP,WAAW,MAAM,SAAS,EAAE,OAAO,MAAM;IACzC,YAAY,MAAM;AAChB,SAAI,EAAE,QAAQ,QAAS,WAAU;AACjC,SAAI,EAAE,QAAQ,SAAU,WAAU;;IAEpC,aAAa,QAAQ,yBAAyB;IAC9C,WAAU;IACV,UAAU;KACV;GACF,oBAAC;IACC,SAAQ;IACR,MAAK;IACL,UAAU,YAAY,CAAC,MAAM,MAAM;IACnC,SAAS;cAER,WACC,oBAAC,WAAQ,WAAU,yBAAyB,GAE3C,QAAQ,UAAU;KAEd;GACT,oBAAC;IACC,MAAK;IACL,SAAS;IACT,WAAU;cAEV,oBAAC,KAAE,WAAU,YAAY;KAClB;;GACL"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/react/file-browser/types.d.ts
|
|
2
|
+
/** A single entry (file or directory) in a directory listing */
|
|
3
|
+
interface DirectoryEntry {
|
|
4
|
+
name?: string;
|
|
5
|
+
path?: string;
|
|
6
|
+
is_directory?: boolean;
|
|
7
|
+
file_size?: number;
|
|
8
|
+
last_modified?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Metadata and content preview for a selected file */
|
|
11
|
+
interface FilePreview {
|
|
12
|
+
contentLength: number | undefined;
|
|
13
|
+
contentType: string | undefined;
|
|
14
|
+
lastModified: string | undefined;
|
|
15
|
+
textPreview: string | null;
|
|
16
|
+
isText: boolean;
|
|
17
|
+
isImage: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Customizable labels for file browser components (i18n-ready) */
|
|
20
|
+
interface FileBrowserLabels {
|
|
21
|
+
/** Back button text (default: "Back to parent") */
|
|
22
|
+
backToParent?: string;
|
|
23
|
+
/** Empty directory message (default: "This directory is empty.") */
|
|
24
|
+
emptyDirectory?: string;
|
|
25
|
+
/** No volume configured message */
|
|
26
|
+
noVolumeConfigured?: string;
|
|
27
|
+
/** Retry button text (default: "Retry") */
|
|
28
|
+
retry?: string;
|
|
29
|
+
/** Select file prompt (default: "Select a file to preview") */
|
|
30
|
+
selectFilePrompt?: string;
|
|
31
|
+
/** Preview not available message */
|
|
32
|
+
previewNotAvailable?: string;
|
|
33
|
+
/** Failed to load preview message */
|
|
34
|
+
previewFailed?: string;
|
|
35
|
+
/** Download button text (default: "Download") */
|
|
36
|
+
download?: string;
|
|
37
|
+
/** Create button text (default: "Create") */
|
|
38
|
+
create?: string;
|
|
39
|
+
/** Folder name placeholder (default: "Folder name") */
|
|
40
|
+
folderNamePlaceholder?: string;
|
|
41
|
+
/** Size label (default: "Size") */
|
|
42
|
+
size?: string;
|
|
43
|
+
/** Type label (default: "Type") */
|
|
44
|
+
type?: string;
|
|
45
|
+
/** Modified label (default: "Modified") */
|
|
46
|
+
modified?: string;
|
|
47
|
+
/** Unknown value fallback (default: "Unknown") */
|
|
48
|
+
unknown?: string;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { DirectoryEntry, FileBrowserLabels, FilePreview };
|
|
52
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/react/file-browser/types.ts"],"mappings":";;UACiB,cAAA;EACf,IAAA;EACA,IAAA;EACA,YAAA;EACA,SAAA;EACA,aAAA;AAAA;;UAIe,WAAA;EACf,aAAA;EACA,WAAA;EACA,YAAA;EACA,WAAA;EACA,MAAA;EACA,OAAA;AAAA;;UAIe,iBAAA;EANf;EAQA,YAAA;EANA;EAQA,cAAA;EARO;EAUP,kBAAA;EANgC;EAQhC,KAAA;EARgC;EAUhC,gBAAA;EANA;EAQA,mBAAA;EAJA;EAMA,aAAA;EAFA;EAIA,QAAA;EAAA;EAEA,MAAA;EAEA;EAAA,qBAAA;EAIA;EAFA,IAAA;EAMA;EAJA,IAAA;EAIO;EAFP,QAAA;;EAEA,OAAA;AAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ChartType } from "../charts/types.js";
|
|
2
|
+
import { GenieColumnMeta } from "./genie-query-transform.js";
|
|
3
|
+
|
|
4
|
+
//#region src/react/genie/genie-chart-inference.d.ts
|
|
5
|
+
interface ChartInference {
|
|
6
|
+
chartType: ChartType;
|
|
7
|
+
xKey: string;
|
|
8
|
+
yKey: string | string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Infer the best chart type for the given Genie query result.
|
|
12
|
+
* Returns `null` when the data is not suitable for charting.
|
|
13
|
+
*/
|
|
14
|
+
declare function inferChartType(rows: Record<string, unknown>[], columns: GenieColumnMeta[]): ChartInference | null;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { ChartInference, inferChartType };
|
|
17
|
+
//# sourceMappingURL=genie-chart-inference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"genie-chart-inference.d.ts","names":[],"sources":["../../../src/react/genie/genie-chart-inference.ts"],"mappings":";;;;UAqDiB,cAAA;EACf,SAAA,EAAW,SAAA;EACX,IAAA;EACA,IAAA;AAAA;;;;;iBA6Bc,cAAA,CACd,IAAA,EAAM,MAAA,qBACN,OAAA,EAAS,eAAA,KACR,cAAA"}
|