@bendyline/docblocks-react 0.1.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/LICENSE +21 -0
- package/README.md +70 -0
- package/dist/AppMenu/AppMenu.d.ts +11 -0
- package/dist/AppMenu/AppMenu.d.ts.map +1 -0
- package/dist/AppMenu/AppMenu.js +27 -0
- package/dist/AppMenu/AppMenu.js.map +1 -0
- package/dist/AppMenu/index.d.ts +3 -0
- package/dist/AppMenu/index.d.ts.map +1 -0
- package/dist/AppMenu/index.js +2 -0
- package/dist/AppMenu/index.js.map +1 -0
- package/dist/DocBlocksShell/DocBlocksShell.d.ts +16 -0
- package/dist/DocBlocksShell/DocBlocksShell.d.ts.map +1 -0
- package/dist/DocBlocksShell/DocBlocksShell.js +487 -0
- package/dist/DocBlocksShell/DocBlocksShell.js.map +1 -0
- package/dist/DocBlocksShell/index.d.ts +3 -0
- package/dist/DocBlocksShell/index.d.ts.map +1 -0
- package/dist/DocBlocksShell/index.js +2 -0
- package/dist/DocBlocksShell/index.js.map +1 -0
- package/dist/Export/ExportDialog.d.ts +16 -0
- package/dist/Export/ExportDialog.d.ts.map +1 -0
- package/dist/Export/ExportDialog.js +42 -0
- package/dist/Export/ExportDialog.js.map +1 -0
- package/dist/Export/ExportToolbarControls.d.ts +17 -0
- package/dist/Export/ExportToolbarControls.d.ts.map +1 -0
- package/dist/Export/ExportToolbarControls.js +109 -0
- package/dist/Export/ExportToolbarControls.js.map +1 -0
- package/dist/Export/export-options.d.ts +18 -0
- package/dist/Export/export-options.d.ts.map +1 -0
- package/dist/Export/export-options.js +44 -0
- package/dist/Export/export-options.js.map +1 -0
- package/dist/Export/index.d.ts +6 -0
- package/dist/Export/index.d.ts.map +1 -0
- package/dist/Export/index.js +3 -0
- package/dist/Export/index.js.map +1 -0
- package/dist/Export/run-export.d.ts +8 -0
- package/dist/Export/run-export.d.ts.map +1 -0
- package/dist/Export/run-export.js +208 -0
- package/dist/Export/run-export.js.map +1 -0
- package/dist/FileExplorer/FileExplorer.d.ts +21 -0
- package/dist/FileExplorer/FileExplorer.d.ts.map +1 -0
- package/dist/FileExplorer/FileExplorer.js +125 -0
- package/dist/FileExplorer/FileExplorer.js.map +1 -0
- package/dist/FileExplorer/FileTreeNode.d.ts +18 -0
- package/dist/FileExplorer/FileTreeNode.d.ts.map +1 -0
- package/dist/FileExplorer/FileTreeNode.js +86 -0
- package/dist/FileExplorer/FileTreeNode.js.map +1 -0
- package/dist/FileExplorer/index.d.ts +6 -0
- package/dist/FileExplorer/index.d.ts.map +1 -0
- package/dist/FileExplorer/index.js +4 -0
- package/dist/FileExplorer/index.js.map +1 -0
- package/dist/FileExplorer/useFileTree.d.ts +35 -0
- package/dist/FileExplorer/useFileTree.d.ts.map +1 -0
- package/dist/FileExplorer/useFileTree.js +124 -0
- package/dist/FileExplorer/useFileTree.js.map +1 -0
- package/dist/WorkspacePicker/WorkspacePicker.d.ts +17 -0
- package/dist/WorkspacePicker/WorkspacePicker.d.ts.map +1 -0
- package/dist/WorkspacePicker/WorkspacePicker.js +57 -0
- package/dist/WorkspacePicker/WorkspacePicker.js.map +1 -0
- package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts +10 -0
- package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts.map +1 -0
- package/dist/WorkspacePicker/WorkspaceSettingsButton.js +27 -0
- package/dist/WorkspacePicker/WorkspaceSettingsButton.js.map +1 -0
- package/dist/WorkspacePicker/index.d.ts +3 -0
- package/dist/WorkspacePicker/index.d.ts.map +1 -0
- package/dist/WorkspacePicker/index.js +2 -0
- package/dist/WorkspacePicker/index.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useAutoSave.d.ts +9 -0
- package/dist/hooks/useAutoSave.d.ts.map +1 -0
- package/dist/hooks/useAutoSave.js +48 -0
- package/dist/hooks/useAutoSave.js.map +1 -0
- package/dist/icons.d.ts +6 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +24 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
- package/src/AppMenu/AppMenu.tsx +124 -0
- package/src/AppMenu/index.ts +2 -0
- package/src/DocBlocksShell/DocBlocksShell.tsx +662 -0
- package/src/DocBlocksShell/index.ts +2 -0
- package/src/Export/ExportDialog.tsx +173 -0
- package/src/Export/ExportToolbarControls.tsx +183 -0
- package/src/Export/export-options.ts +57 -0
- package/src/Export/index.ts +5 -0
- package/src/Export/run-export.ts +238 -0
- package/src/FileExplorer/FileExplorer.tsx +260 -0
- package/src/FileExplorer/FileTreeNode.tsx +172 -0
- package/src/FileExplorer/index.ts +5 -0
- package/src/FileExplorer/useFileTree.ts +178 -0
- package/src/WorkspacePicker/WorkspacePicker.tsx +126 -0
- package/src/WorkspacePicker/WorkspaceSettingsButton.tsx +79 -0
- package/src/WorkspacePicker/index.ts +2 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useAutoSave.ts +58 -0
- package/src/icons.tsx +60 -0
- package/src/index.ts +31 -0
- package/src/styles/docblocks.css +961 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ExportToolbarControls — toolbar-right slot content.
|
|
4
|
+
*
|
|
5
|
+
* Renders a "..." overflow menu on the right side of the toolbar
|
|
6
|
+
* containing export actions (document export + video export).
|
|
7
|
+
*
|
|
8
|
+
* Must be rendered inside <EditorProvider> so useEditorContext() works.
|
|
9
|
+
*/
|
|
10
|
+
import { useState, useCallback, useEffect, useRef, useMemo } from 'react';
|
|
11
|
+
import { useEditorContext } from '@bendyline/squisq-editor-react';
|
|
12
|
+
import { getThemeSummaries } from '@bendyline/squisq/schemas';
|
|
13
|
+
import { getTransformStyleSummaries } from '@bendyline/squisq/transform';
|
|
14
|
+
import { parseMarkdown } from '@bendyline/squisq/markdown';
|
|
15
|
+
import { markdownToDoc } from '@bendyline/squisq/doc';
|
|
16
|
+
import { VideoExportModal } from '@bendyline/squisq-video-react';
|
|
17
|
+
import { PLAYER_BUNDLE } from '@bendyline/squisq-react/standalone-source';
|
|
18
|
+
import { DEFAULT_OPTIONS, FORMAT_EXTENSIONS, loadLastExportOptions, saveExportOptions, } from './export-options.js';
|
|
19
|
+
import { ExportDialog } from './ExportDialog.js';
|
|
20
|
+
import { runExport } from './run-export.js';
|
|
21
|
+
/** Build the quick-export label from saved options. */
|
|
22
|
+
function quickLabel(opts) {
|
|
23
|
+
const ext = FORMAT_EXTENSIONS[opts.format].toUpperCase().replace('.', '');
|
|
24
|
+
const parts = [];
|
|
25
|
+
if (opts.themeId !== 'standard') {
|
|
26
|
+
const theme = getThemeSummaries().find((t) => t.id === opts.themeId);
|
|
27
|
+
if (theme)
|
|
28
|
+
parts.push(theme.name);
|
|
29
|
+
}
|
|
30
|
+
if (opts.format === 'pptx' && opts.transformStyle) {
|
|
31
|
+
const transform = getTransformStyleSummaries().find((t) => t.id === opts.transformStyle);
|
|
32
|
+
if (transform)
|
|
33
|
+
parts.push(transform.name);
|
|
34
|
+
}
|
|
35
|
+
if (parts.length > 0) {
|
|
36
|
+
return `Export ${ext} with ${parts.join(' + ')}`;
|
|
37
|
+
}
|
|
38
|
+
return `Export ${ext}`;
|
|
39
|
+
}
|
|
40
|
+
export function ExportToolbarControls({ selectedFile, mediaContainer, }) {
|
|
41
|
+
const { markdownSource } = useEditorContext();
|
|
42
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
43
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
44
|
+
const [videoModalOpen, setVideoModalOpen] = useState(false);
|
|
45
|
+
const [exporting, setExporting] = useState(false);
|
|
46
|
+
const menuRef = useRef(null);
|
|
47
|
+
const lastOptions = loadLastExportOptions();
|
|
48
|
+
/** Build a Doc from the current markdown for video export. */
|
|
49
|
+
const doc = useMemo(() => {
|
|
50
|
+
if (!videoModalOpen)
|
|
51
|
+
return null;
|
|
52
|
+
const mdDoc = parseMarkdown(markdownSource);
|
|
53
|
+
return markdownToDoc(mdDoc);
|
|
54
|
+
}, [videoModalOpen, markdownSource]);
|
|
55
|
+
// Close menu on outside click
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!menuOpen)
|
|
58
|
+
return;
|
|
59
|
+
const onPointerDown = (e) => {
|
|
60
|
+
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
61
|
+
setMenuOpen(false);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
document.addEventListener('pointerdown', onPointerDown);
|
|
65
|
+
return () => document.removeEventListener('pointerdown', onPointerDown);
|
|
66
|
+
}, [menuOpen]);
|
|
67
|
+
const handleToggleMenu = useCallback(() => {
|
|
68
|
+
setMenuOpen((prev) => !prev);
|
|
69
|
+
}, []);
|
|
70
|
+
const handleOpenDialog = useCallback(() => {
|
|
71
|
+
setMenuOpen(false);
|
|
72
|
+
setDialogOpen(true);
|
|
73
|
+
}, []);
|
|
74
|
+
const handleCloseDialog = useCallback(() => {
|
|
75
|
+
setDialogOpen(false);
|
|
76
|
+
}, []);
|
|
77
|
+
const handleOpenVideoModal = useCallback(() => {
|
|
78
|
+
setMenuOpen(false);
|
|
79
|
+
setVideoModalOpen(true);
|
|
80
|
+
}, []);
|
|
81
|
+
const handleCloseVideoModal = useCallback(() => {
|
|
82
|
+
setVideoModalOpen(false);
|
|
83
|
+
}, []);
|
|
84
|
+
const handleExport = useCallback(async (opts) => {
|
|
85
|
+
setExporting(true);
|
|
86
|
+
try {
|
|
87
|
+
await runExport(markdownSource, selectedFile, opts, mediaContainer);
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
setExporting(false);
|
|
91
|
+
setDialogOpen(false);
|
|
92
|
+
}
|
|
93
|
+
}, [markdownSource, selectedFile, mediaContainer]);
|
|
94
|
+
const handleQuickExport = useCallback(async () => {
|
|
95
|
+
if (!lastOptions)
|
|
96
|
+
return;
|
|
97
|
+
setMenuOpen(false);
|
|
98
|
+
setExporting(true);
|
|
99
|
+
try {
|
|
100
|
+
saveExportOptions(lastOptions);
|
|
101
|
+
await runExport(markdownSource, selectedFile, lastOptions, mediaContainer);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
setExporting(false);
|
|
105
|
+
}
|
|
106
|
+
}, [lastOptions, markdownSource, selectedFile, mediaContainer]);
|
|
107
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "db-toolbar-menu", ref: menuRef, children: [_jsx("button", { className: "db-toolbar-menu-trigger", onClick: handleToggleMenu, "aria-label": "More actions", title: "More actions", children: "\u00B7\u00B7\u00B7" }), menuOpen && (_jsxs("div", { className: "db-toolbar-menu-dropdown", children: [lastOptions && (_jsx("button", { className: "db-toolbar-menu-item", onClick: handleQuickExport, disabled: exporting, children: quickLabel(lastOptions) })), _jsx("button", { className: "db-toolbar-menu-item", onClick: handleOpenDialog, children: "Export..." }), _jsx("div", { className: "db-toolbar-menu-divider" }), _jsx("button", { className: "db-toolbar-menu-item", onClick: handleOpenVideoModal, children: "Export Video..." })] }))] }), dialogOpen && (_jsx(ExportDialog, { initial: lastOptions ?? DEFAULT_OPTIONS, exporting: exporting, onExport: handleExport, onClose: handleCloseDialog })), videoModalOpen && doc && (_jsx(VideoExportModal, { doc: doc, playerScript: PLAYER_BUNDLE, onClose: handleCloseVideoModal }))] }));
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=ExportToolbarControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportToolbarControls.js","sourceRoot":"","sources":["../../src/Export/ExportToolbarControls.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export option types and localStorage persistence for quick-export.
|
|
3
|
+
*/
|
|
4
|
+
export type ExportFormat = 'docx' | 'pdf' | 'pptx' | 'md' | 'html';
|
|
5
|
+
export interface ExportOptions {
|
|
6
|
+
format: ExportFormat;
|
|
7
|
+
themeId: string;
|
|
8
|
+
/** Transform style for PPTX — controls how content is segmented and styled. */
|
|
9
|
+
transformStyle: string;
|
|
10
|
+
/** Only applies to PDF */
|
|
11
|
+
pageSize: 'letter' | 'a4';
|
|
12
|
+
}
|
|
13
|
+
export declare const FORMAT_LABELS: Record<ExportFormat, string>;
|
|
14
|
+
export declare const FORMAT_EXTENSIONS: Record<ExportFormat, string>;
|
|
15
|
+
export declare const DEFAULT_OPTIONS: ExportOptions;
|
|
16
|
+
export declare function loadLastExportOptions(): ExportOptions | null;
|
|
17
|
+
export declare function saveExportOptions(options: ExportOptions): void;
|
|
18
|
+
//# sourceMappingURL=export-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-options.d.ts","sourceRoot":"","sources":["../../src/Export/export-options.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,cAAc,EAAE,MAAM,CAAC;IACvB,0BAA0B;IAC1B,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAMtD,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAM1D,CAAC;AAIF,eAAO,MAAM,eAAe,EAAE,aAK7B,CAAC;AAEF,wBAAgB,qBAAqB,IAAI,aAAa,GAAG,IAAI,CAQ5D;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAM9D"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export option types and localStorage persistence for quick-export.
|
|
3
|
+
*/
|
|
4
|
+
export const FORMAT_LABELS = {
|
|
5
|
+
docx: 'Word Document (.docx)',
|
|
6
|
+
pdf: 'PDF (.pdf)',
|
|
7
|
+
pptx: 'PowerPoint (.pptx)',
|
|
8
|
+
md: 'Markdown (.md)',
|
|
9
|
+
html: 'HTML (.html)',
|
|
10
|
+
};
|
|
11
|
+
export const FORMAT_EXTENSIONS = {
|
|
12
|
+
docx: '.docx',
|
|
13
|
+
pdf: '.pdf',
|
|
14
|
+
pptx: '.pptx',
|
|
15
|
+
md: '.md',
|
|
16
|
+
html: '.html',
|
|
17
|
+
};
|
|
18
|
+
const STORAGE_KEY = 'docblocks-export-options';
|
|
19
|
+
export const DEFAULT_OPTIONS = {
|
|
20
|
+
format: 'pdf',
|
|
21
|
+
themeId: 'standard',
|
|
22
|
+
transformStyle: 'documentary',
|
|
23
|
+
pageSize: 'letter',
|
|
24
|
+
};
|
|
25
|
+
export function loadLastExportOptions() {
|
|
26
|
+
try {
|
|
27
|
+
const raw = localStorage.getItem(STORAGE_KEY);
|
|
28
|
+
if (!raw)
|
|
29
|
+
return null;
|
|
30
|
+
return JSON.parse(raw);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function saveExportOptions(options) {
|
|
37
|
+
try {
|
|
38
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(options));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Ignore storage errors
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=export-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-options.js","sourceRoot":"","sources":["../../src/Export/export-options.ts"],"names":[],"mappings":"AAAA;;GAEG;AAaH,MAAM,CAAC,MAAM,aAAa,GAAiC;IACzD,IAAI,EAAE,uBAAuB;IAC7B,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,oBAAoB;IAC1B,EAAE,EAAE,gBAAgB;IACpB,IAAI,EAAE,cAAc;CACrB,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAiC;IAC7D,IAAI,EAAE,OAAO;IACb,GAAG,EAAE,MAAM;IACX,IAAI,EAAE,OAAO;IACb,EAAE,EAAE,KAAK;IACT,IAAI,EAAE,OAAO;CACd,CAAC;AAEF,MAAM,WAAW,GAAG,0BAA0B,CAAC;AAE/C,MAAM,CAAC,MAAM,eAAe,GAAkB;IAC5C,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,UAAU;IACnB,cAAc,EAAE,aAAa;IAC7B,QAAQ,EAAE,QAAQ;CACnB,CAAC;AAEF,MAAM,UAAU,qBAAqB;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAsB;IACtD,IAAI,CAAC;QACH,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,wBAAwB;IAC1B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { ExportToolbarControls } from './ExportToolbarControls.js';
|
|
2
|
+
export type { ExportToolbarControlsProps } from './ExportToolbarControls.js';
|
|
3
|
+
export { ExportDialog } from './ExportDialog.js';
|
|
4
|
+
export type { ExportDialogProps } from './ExportDialog.js';
|
|
5
|
+
export type { ExportFormat, ExportOptions } from './export-options.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Export/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Export/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute an export using @bendyline/squisq-formats.
|
|
3
|
+
*/
|
|
4
|
+
import type { ContentContainer } from '@bendyline/squisq/storage';
|
|
5
|
+
import type { ExportOptions } from './export-options.js';
|
|
6
|
+
/** Run the export and trigger a download. */
|
|
7
|
+
export declare function runExport(markdown: string, selectedFile: string | null, options: ExportOptions, mediaContainer?: ContentContainer | null): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=run-export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-export.d.ts","sourceRoot":"","sources":["../../src/Export/run-export.ts"],"names":[],"mappings":"AAAA;;GAEG;AAaH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,qBAAqB,CAAC;AA2BvE,6CAA6C;AAC7C,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,OAAO,EAAE,aAAa,EACtB,cAAc,CAAC,EAAE,gBAAgB,GAAG,IAAI,GACvC,OAAO,CAAC,IAAI,CAAC,CA6Cf"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute an export using @bendyline/squisq-formats.
|
|
3
|
+
*/
|
|
4
|
+
import { parseMarkdown } from '@bendyline/squisq/markdown';
|
|
5
|
+
import { markdownToDoc } from '@bendyline/squisq/doc';
|
|
6
|
+
import { applyTransform } from '@bendyline/squisq/transform';
|
|
7
|
+
import { markdownDocToDocx } from '@bendyline/squisq-formats/docx';
|
|
8
|
+
import { markdownDocToPdf } from '@bendyline/squisq-formats/pdf';
|
|
9
|
+
import { docToPptx } from '@bendyline/squisq-formats/pptx';
|
|
10
|
+
import { FORMAT_EXTENSIONS } from './export-options.js';
|
|
11
|
+
const MIME_TYPES = {
|
|
12
|
+
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
13
|
+
pdf: 'application/pdf',
|
|
14
|
+
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
15
|
+
md: 'text/markdown',
|
|
16
|
+
html: 'text/html',
|
|
17
|
+
};
|
|
18
|
+
/** Trigger a browser download for a Blob. */
|
|
19
|
+
function downloadBlob(blob, filename) {
|
|
20
|
+
const url = URL.createObjectURL(blob);
|
|
21
|
+
const a = document.createElement('a');
|
|
22
|
+
a.href = url;
|
|
23
|
+
a.download = filename;
|
|
24
|
+
a.click();
|
|
25
|
+
URL.revokeObjectURL(url);
|
|
26
|
+
}
|
|
27
|
+
/** Derive a filename from the selected file path and export format. */
|
|
28
|
+
function buildFilename(selectedFile, format) {
|
|
29
|
+
const base = selectedFile ? selectedFile.replace(/^\//, '').replace(/\.[^.]+$/, '') : 'document';
|
|
30
|
+
return base + FORMAT_EXTENSIONS[format];
|
|
31
|
+
}
|
|
32
|
+
/** Run the export and trigger a download. */
|
|
33
|
+
export async function runExport(markdown, selectedFile, options, mediaContainer) {
|
|
34
|
+
const filename = buildFilename(selectedFile, options.format);
|
|
35
|
+
const themeId = options.themeId !== 'standard' ? options.themeId : undefined;
|
|
36
|
+
if (options.format === 'md') {
|
|
37
|
+
downloadBlob(new Blob([markdown], { type: MIME_TYPES.md }), filename);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (options.format === 'html') {
|
|
41
|
+
const html = wrapMarkdownAsHtml(markdown);
|
|
42
|
+
downloadBlob(new Blob([html], { type: MIME_TYPES.html }), filename);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const doc = parseMarkdown(markdown);
|
|
46
|
+
if (options.format === 'docx') {
|
|
47
|
+
const images = mediaContainer ? await resolveImages(doc, mediaContainer) : undefined;
|
|
48
|
+
const buf = await markdownDocToDocx(doc, { themeId, images });
|
|
49
|
+
downloadBlob(new Blob([buf], { type: MIME_TYPES.docx }), filename);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (options.format === 'pdf') {
|
|
53
|
+
const buf = await markdownDocToPdf(doc, {
|
|
54
|
+
themeId,
|
|
55
|
+
pageSize: options.pageSize,
|
|
56
|
+
});
|
|
57
|
+
downloadBlob(new Blob([buf], { type: MIME_TYPES.pdf }), filename);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (options.format === 'pptx') {
|
|
61
|
+
// Use the full transform pipeline: markdown → Doc → transform → PPTX
|
|
62
|
+
const baseDoc = markdownToDoc(doc);
|
|
63
|
+
const transformed = applyTransform(baseDoc, options.transformStyle);
|
|
64
|
+
const enrichedDoc = transformed.doc;
|
|
65
|
+
if (themeId) {
|
|
66
|
+
enrichedDoc.themeId = themeId;
|
|
67
|
+
}
|
|
68
|
+
const buf = await docToPptx(enrichedDoc, { themeId });
|
|
69
|
+
downloadBlob(new Blob([buf], { type: MIME_TYPES.pptx }), filename);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Wrap raw markdown in a basic styled HTML page. */
|
|
74
|
+
function wrapMarkdownAsHtml(markdown) {
|
|
75
|
+
// Convert markdown to simple HTML via the parser
|
|
76
|
+
const doc = parseMarkdown(markdown);
|
|
77
|
+
// Build a minimal representation from the parsed nodes
|
|
78
|
+
const lines = [];
|
|
79
|
+
for (const node of doc.children) {
|
|
80
|
+
lines.push(nodeToHtml(node));
|
|
81
|
+
}
|
|
82
|
+
const body = lines.join('\n');
|
|
83
|
+
return `<!DOCTYPE html>
|
|
84
|
+
<html lang="en">
|
|
85
|
+
<head>
|
|
86
|
+
<meta charset="UTF-8">
|
|
87
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
88
|
+
<title>Document</title>
|
|
89
|
+
<style>
|
|
90
|
+
body { font-family: system-ui, -apple-system, sans-serif; max-width: 800px; margin: 2em auto; padding: 0 1em; line-height: 1.6; color: #1f2937; }
|
|
91
|
+
h1, h2, h3, h4, h5, h6 { margin-top: 1.5em; margin-bottom: 0.5em; }
|
|
92
|
+
pre { background: #f3f4f6; padding: 1em; border-radius: 4px; overflow-x: auto; }
|
|
93
|
+
code { background: #f3f4f6; padding: 0.15em 0.3em; border-radius: 3px; font-size: 0.9em; }
|
|
94
|
+
pre code { background: none; padding: 0; }
|
|
95
|
+
blockquote { border-left: 3px solid #d1d5db; margin-left: 0; padding-left: 1em; color: #6b7280; }
|
|
96
|
+
img { max-width: 100%; }
|
|
97
|
+
a { color: #3b82f6; }
|
|
98
|
+
</style>
|
|
99
|
+
</head>
|
|
100
|
+
<body>
|
|
101
|
+
${body}
|
|
102
|
+
</body>
|
|
103
|
+
</html>`;
|
|
104
|
+
}
|
|
105
|
+
/** Convert a markdown AST node to HTML (basic). */
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
107
|
+
function nodeToHtml(node) {
|
|
108
|
+
if (!node)
|
|
109
|
+
return '';
|
|
110
|
+
switch (node.type) {
|
|
111
|
+
case 'heading': {
|
|
112
|
+
const tag = `h${node.depth ?? 1}`;
|
|
113
|
+
return `<${tag}>${childrenToHtml(node)}</${tag}>`;
|
|
114
|
+
}
|
|
115
|
+
case 'paragraph':
|
|
116
|
+
return `<p>${childrenToHtml(node)}</p>`;
|
|
117
|
+
case 'text':
|
|
118
|
+
return escapeHtml(node.value ?? '');
|
|
119
|
+
case 'strong':
|
|
120
|
+
return `<strong>${childrenToHtml(node)}</strong>`;
|
|
121
|
+
case 'emphasis':
|
|
122
|
+
return `<em>${childrenToHtml(node)}</em>`;
|
|
123
|
+
case 'delete':
|
|
124
|
+
return `<del>${childrenToHtml(node)}</del>`;
|
|
125
|
+
case 'inlineCode':
|
|
126
|
+
return `<code>${escapeHtml(node.value ?? '')}</code>`;
|
|
127
|
+
case 'code':
|
|
128
|
+
return `<pre><code>${escapeHtml(node.value ?? '')}</code></pre>`;
|
|
129
|
+
case 'blockquote':
|
|
130
|
+
return `<blockquote>${childrenToHtml(node)}</blockquote>`;
|
|
131
|
+
case 'list': {
|
|
132
|
+
const tag = node.ordered ? 'ol' : 'ul';
|
|
133
|
+
return `<${tag}>${childrenToHtml(node)}</${tag}>`;
|
|
134
|
+
}
|
|
135
|
+
case 'listItem':
|
|
136
|
+
return `<li>${childrenToHtml(node)}</li>`;
|
|
137
|
+
case 'link':
|
|
138
|
+
return `<a href="${escapeAttr(node.url ?? '')}">${childrenToHtml(node)}</a>`;
|
|
139
|
+
case 'image':
|
|
140
|
+
return `<img src="${escapeAttr(node.url ?? '')}" alt="${escapeAttr(node.alt ?? '')}" />`;
|
|
141
|
+
case 'thematicBreak':
|
|
142
|
+
return '<hr />';
|
|
143
|
+
default:
|
|
144
|
+
return node.children ? childrenToHtml(node) : escapeHtml(node.value ?? '');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
148
|
+
function childrenToHtml(node) {
|
|
149
|
+
if (!node.children)
|
|
150
|
+
return node.value ? escapeHtml(node.value) : '';
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
152
|
+
return node.children.map((c) => nodeToHtml(c)).join('');
|
|
153
|
+
}
|
|
154
|
+
function escapeHtml(s) {
|
|
155
|
+
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
156
|
+
}
|
|
157
|
+
function escapeAttr(s) {
|
|
158
|
+
return escapeHtml(s).replace(/"/g, '"');
|
|
159
|
+
}
|
|
160
|
+
const IMAGE_MIME = {
|
|
161
|
+
png: 'image/png',
|
|
162
|
+
jpg: 'image/jpeg',
|
|
163
|
+
jpeg: 'image/jpeg',
|
|
164
|
+
gif: 'image/gif',
|
|
165
|
+
webp: 'image/webp',
|
|
166
|
+
bmp: 'image/bmp',
|
|
167
|
+
};
|
|
168
|
+
/** Walk the markdown AST and collect all image URLs. */
|
|
169
|
+
function collectImageUrls(doc) {
|
|
170
|
+
const urls = [];
|
|
171
|
+
function walkBlocks(nodes) {
|
|
172
|
+
for (const node of nodes) {
|
|
173
|
+
if ('children' in node && Array.isArray(node.children)) {
|
|
174
|
+
// Check if children are inline or block nodes
|
|
175
|
+
for (const child of node.children) {
|
|
176
|
+
if (child.type === 'image') {
|
|
177
|
+
urls.push(child.url);
|
|
178
|
+
}
|
|
179
|
+
else if ('children' in child && Array.isArray(child.children)) {
|
|
180
|
+
walkBlocks(child.children);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
walkBlocks(doc.children);
|
|
187
|
+
return urls;
|
|
188
|
+
}
|
|
189
|
+
/** Resolve image URLs to binary data from a ContentContainer. */
|
|
190
|
+
async function resolveImages(doc, container) {
|
|
191
|
+
const urls = collectImageUrls(doc);
|
|
192
|
+
const map = new Map();
|
|
193
|
+
for (const url of urls) {
|
|
194
|
+
if (map.has(url))
|
|
195
|
+
continue;
|
|
196
|
+
// Skip external URLs
|
|
197
|
+
if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('data:'))
|
|
198
|
+
continue;
|
|
199
|
+
const data = await container.readFile(url);
|
|
200
|
+
if (!data)
|
|
201
|
+
continue;
|
|
202
|
+
const ext = url.slice(url.lastIndexOf('.') + 1).toLowerCase();
|
|
203
|
+
const contentType = IMAGE_MIME[ext] || 'image/png';
|
|
204
|
+
map.set(url, { data, contentType });
|
|
205
|
+
}
|
|
206
|
+
return map;
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=run-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-export.js","sourceRoot":"","sources":["../../src/Export/run-export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileExplorer — tree component rendering FileSystemProvider contents.
|
|
3
|
+
*
|
|
4
|
+
* Shows a file/folder tree with expand/collapse, selection, and a toolbar
|
|
5
|
+
* for creating new files/folders.
|
|
6
|
+
*/
|
|
7
|
+
import type { FileSystemProvider } from '@bendyline/docblocks/filesystem';
|
|
8
|
+
export interface FileExplorerProps {
|
|
9
|
+
/** The filesystem to display. */
|
|
10
|
+
provider: FileSystemProvider | null;
|
|
11
|
+
/** Called when any entry is selected (file or directory). */
|
|
12
|
+
onSelect?: (path: string, kind: 'file' | 'directory') => void;
|
|
13
|
+
/** Called after any mutation (create, delete, rename). */
|
|
14
|
+
onTreeChange?: () => void;
|
|
15
|
+
/** Called when supported files are dropped onto the explorer. */
|
|
16
|
+
onImportFiles?: (files: File[]) => void;
|
|
17
|
+
/** Optional className for the root element. */
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function FileExplorer({ provider, onSelect, onTreeChange, onImportFiles, className, }: FileExplorerProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
//# sourceMappingURL=FileExplorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileExplorer.d.ts","sourceRoot":"","sources":["../../src/FileExplorer/FileExplorer.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAmB,MAAM,iCAAiC,CAAC;AAO3F,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,KAAK,IAAI,CAAC;IAC9D,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,iEAAiE;IACjE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACxC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,SAAS,GACV,EAAE,iBAAiB,2CAiOnB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* FileExplorer — tree component rendering FileSystemProvider contents.
|
|
4
|
+
*
|
|
5
|
+
* Shows a file/folder tree with expand/collapse, selection, and a toolbar
|
|
6
|
+
* for creating new files/folders.
|
|
7
|
+
*/
|
|
8
|
+
import { useCallback, useState } from 'react';
|
|
9
|
+
import { useFileTree } from './useFileTree.js';
|
|
10
|
+
import { FileTreeNode } from './FileTreeNode.js';
|
|
11
|
+
import { NewFileIcon, NewFolderIcon, RefreshIcon } from '../icons.js';
|
|
12
|
+
const SUPPORTED_EXTENSIONS = new Set(['.txt', '.md', '.docx', '.pdf', '.dbk', '.zip']);
|
|
13
|
+
export function FileExplorer({ provider, onSelect, onTreeChange, onImportFiles, className, }) {
|
|
14
|
+
const tree = useFileTree(provider);
|
|
15
|
+
const { childEntries } = tree;
|
|
16
|
+
const [newItemName, setNewItemName] = useState('');
|
|
17
|
+
const [newItemType, setNewItemType] = useState(null);
|
|
18
|
+
const [dragOver, setDragOver] = useState(false);
|
|
19
|
+
const dragCounter = useState({ current: 0 })[0];
|
|
20
|
+
const hasSupported = useCallback((dt) => {
|
|
21
|
+
for (const item of Array.from(dt.items)) {
|
|
22
|
+
if (item.kind !== 'file')
|
|
23
|
+
continue;
|
|
24
|
+
const name = item.getAsFile?.()?.name;
|
|
25
|
+
// During dragover the filename may not be available, so accept broadly
|
|
26
|
+
if (!name)
|
|
27
|
+
return true;
|
|
28
|
+
const ext = name.slice(name.lastIndexOf('.')).toLowerCase();
|
|
29
|
+
if (SUPPORTED_EXTENSIONS.has(ext))
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return dt.items.length > 0;
|
|
33
|
+
}, []);
|
|
34
|
+
const handleDragEnter = useCallback((e) => {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
dragCounter.current += 1;
|
|
37
|
+
if (hasSupported(e.dataTransfer))
|
|
38
|
+
setDragOver(true);
|
|
39
|
+
}, [hasSupported, dragCounter]);
|
|
40
|
+
const handleDragOver = useCallback((e) => {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
e.dataTransfer.dropEffect = 'copy';
|
|
43
|
+
}, []);
|
|
44
|
+
const handleDragLeave = useCallback((e) => {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
dragCounter.current -= 1;
|
|
47
|
+
if (dragCounter.current <= 0) {
|
|
48
|
+
dragCounter.current = 0;
|
|
49
|
+
setDragOver(false);
|
|
50
|
+
}
|
|
51
|
+
}, [dragCounter]);
|
|
52
|
+
const handleDrop = useCallback((e) => {
|
|
53
|
+
e.preventDefault();
|
|
54
|
+
dragCounter.current = 0;
|
|
55
|
+
setDragOver(false);
|
|
56
|
+
const supported = Array.from(e.dataTransfer.files).filter((f) => {
|
|
57
|
+
const ext = f.name.slice(f.name.lastIndexOf('.')).toLowerCase();
|
|
58
|
+
return SUPPORTED_EXTENSIONS.has(ext);
|
|
59
|
+
});
|
|
60
|
+
if (supported.length > 0)
|
|
61
|
+
onImportFiles?.(supported);
|
|
62
|
+
}, [onImportFiles, dragCounter]);
|
|
63
|
+
const handleSelect = useCallback((path) => {
|
|
64
|
+
// Determine kind from entries (root + children)
|
|
65
|
+
const findKind = (p) => {
|
|
66
|
+
for (const e of tree.entries) {
|
|
67
|
+
if (e.path === p)
|
|
68
|
+
return e.kind;
|
|
69
|
+
}
|
|
70
|
+
for (const children of childEntries.values()) {
|
|
71
|
+
for (const e of children) {
|
|
72
|
+
if (e.path === p)
|
|
73
|
+
return e.kind;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return 'file';
|
|
77
|
+
};
|
|
78
|
+
const kind = findKind(path);
|
|
79
|
+
tree.select(path, kind);
|
|
80
|
+
onSelect?.(path, kind);
|
|
81
|
+
}, [tree, onSelect, childEntries]);
|
|
82
|
+
const handleNewItemSubmit = useCallback(async () => {
|
|
83
|
+
if (!newItemName.trim()) {
|
|
84
|
+
setNewItemType(null);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const name = newItemName.trim();
|
|
88
|
+
// Scope to currently selected folder (or root)
|
|
89
|
+
const prefix = tree.selectedKind === 'directory' && tree.selectedPath ? `${tree.selectedPath}/` : '';
|
|
90
|
+
if (newItemType === 'file') {
|
|
91
|
+
const filename = name.endsWith('.md') ? name : `${name}.md`;
|
|
92
|
+
await tree.createFile(`${prefix}${filename}`, '');
|
|
93
|
+
}
|
|
94
|
+
else if (newItemType === 'directory') {
|
|
95
|
+
await tree.createDirectory(`${prefix}${name}`);
|
|
96
|
+
}
|
|
97
|
+
setNewItemName('');
|
|
98
|
+
setNewItemType(null);
|
|
99
|
+
onTreeChange?.();
|
|
100
|
+
}, [newItemName, newItemType, tree, onTreeChange]);
|
|
101
|
+
const handleDelete = useCallback(async (path) => {
|
|
102
|
+
await tree.deleteEntry(path);
|
|
103
|
+
onTreeChange?.();
|
|
104
|
+
}, [tree, onTreeChange]);
|
|
105
|
+
const handleRename = useCallback(async (oldPath, newPath) => {
|
|
106
|
+
await tree.renameEntry(oldPath, newPath);
|
|
107
|
+
onTreeChange?.();
|
|
108
|
+
}, [tree, onTreeChange]);
|
|
109
|
+
const renderEntries = useCallback((entries, depth) => {
|
|
110
|
+
return entries.map((entry) => (_jsx(FileTreeNode, { entry: entry, depth: depth, expanded: tree.expanded.has(entry.path), selected: tree.selectedPath === entry.path, onToggle: tree.toggleExpand, onSelect: handleSelect, onDelete: handleDelete, onRename: handleRename, renderChildren: (dirPath) => {
|
|
111
|
+
const children = childEntries.get(dirPath) ?? [];
|
|
112
|
+
return renderEntries(children, depth + 1);
|
|
113
|
+
} }, entry.path)));
|
|
114
|
+
}, [tree, handleSelect, handleDelete, handleRename, childEntries]);
|
|
115
|
+
return (_jsxs("div", { className: `db-file-explorer ${dragOver ? 'db-file-explorer--drop-active' : ''} ${className ?? ''}`, onDragEnter: handleDragEnter, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [_jsxs("div", { className: "db-explorer-toolbar", children: [_jsx("span", { className: "db-explorer-title", children: "Files" }), _jsxs("div", { className: "db-explorer-actions", children: [_jsx("button", { className: "db-explorer-btn", onClick: () => setNewItemType('file'), title: "New File", "aria-label": "New File", children: _jsx(NewFileIcon, {}) }), _jsx("button", { className: "db-explorer-btn", onClick: () => setNewItemType('directory'), title: "New Folder", "aria-label": "New Folder", children: _jsx(NewFolderIcon, {}) }), _jsx("button", { className: "db-explorer-btn", onClick: () => tree.refresh(), title: "Refresh file list", "aria-label": "Refresh file list", children: _jsx(RefreshIcon, {}) })] })] }), newItemType && (_jsx("div", { className: "db-new-item", children: _jsxs("form", { className: "db-new-item-row", onSubmit: (e) => {
|
|
116
|
+
e.preventDefault();
|
|
117
|
+
handleNewItemSubmit();
|
|
118
|
+
}, children: [_jsx("input", { className: "db-new-item-input", placeholder: newItemType === 'file' ? 'filename' : 'folder-name', value: newItemName, onChange: (e) => setNewItemName(e.target.value), onKeyDown: (e) => {
|
|
119
|
+
if (e.key === 'Escape') {
|
|
120
|
+
setNewItemType(null);
|
|
121
|
+
setNewItemName('');
|
|
122
|
+
}
|
|
123
|
+
}, autoFocus: true }), newItemType === 'file' && _jsx("span", { className: "db-new-item-suffix", children: ".md" }), _jsx("button", { type: "submit", className: "db-new-item-add", children: "Add" })] }) })), _jsx("div", { className: "db-tree", role: "tree", children: tree.loading ? (_jsx("div", { className: "db-tree-loading", children: "Loading..." })) : tree.entries.length === 0 ? (_jsx("div", { className: "db-tree-empty", children: "No files yet" })) : (renderEntries(tree.entries, 0)) })] }));
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=FileExplorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileExplorer.js","sourceRoot":"","sources":["../../src/FileExplorer/FileExplorer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileTreeNode — recursive tree node for the file explorer.
|
|
3
|
+
*/
|
|
4
|
+
import type { FileSystemEntry } from '@bendyline/docblocks/filesystem';
|
|
5
|
+
export interface FileTreeNodeProps {
|
|
6
|
+
entry: FileSystemEntry;
|
|
7
|
+
depth: number;
|
|
8
|
+
expanded: boolean;
|
|
9
|
+
selected: boolean;
|
|
10
|
+
children?: FileSystemEntry[];
|
|
11
|
+
onToggle: (path: string) => void;
|
|
12
|
+
onSelect: (path: string) => void;
|
|
13
|
+
onDelete: (path: string) => Promise<void>;
|
|
14
|
+
onRename: (oldPath: string, newPath: string) => Promise<void>;
|
|
15
|
+
renderChildren?: (dirPath: string) => React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
export declare function FileTreeNode({ entry, depth, expanded, selected, onToggle, onSelect, onDelete, onRename, renderChildren, }: FileTreeNodeProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=FileTreeNode.d.ts.map
|