@bendyline/docblocks-react 2.5.0 → 2.6.1
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/README.md +18 -0
- package/THIRD_PARTY_NOTICES.txt +154 -55
- package/dist/{ExportDialog-VBWHFJ2R.js → ExportDialog-Q4VWI43H.js} +2 -2
- package/dist/{ExportToolbarControls-BUVJCSMV.js → ExportToolbarControls-QYLBRWM7.js} +7 -7
- package/dist/GitGrantNotice-I2VNKPLH.js +29 -0
- package/dist/{GitToolbarControl-VJVK2B4X.js → GitToolbarControl-O5AXBC6T.js} +5 -3
- package/dist/{GitUI-CAKFVKWY.js → GitUI-L5T3XHZG.js} +68 -14
- package/dist/calculation/index.d.ts +27 -0
- package/dist/calculation/index.js +16 -0
- package/dist/chunk-6E635KCJ.js +11 -0
- package/dist/chunk-DUKTAKB4.js +83 -0
- package/dist/{chunk-VRRL6VTD.js → chunk-Q6XNIKDG.js} +63 -0
- package/dist/{chunk-HFYPTTCH.js → chunk-V2ENBGUA.js} +0 -9
- package/dist/export/index.js +5 -5
- package/dist/index.d.ts +42 -7
- package/dist/index.js +926 -514
- package/dist/proofing/index.d.ts +112 -0
- package/dist/proofing/index.js +50 -0
- package/dist/settings/index.d.ts +37 -1
- package/dist/settings/index.js +11 -3
- package/package.json +20 -9
- package/src/styles/docblocks.css +364 -96
- package/dist/{chunk-SIIEGOHY.js → chunk-FMDLZ4ZG.js} +3 -3
package/dist/index.js
CHANGED
|
@@ -1,66 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createBrowserSaveAsAdapter
|
|
3
|
+
} from "./chunk-UMEDHMT7.js";
|
|
1
4
|
import {
|
|
2
5
|
BADGE_GLYPHS,
|
|
3
6
|
BADGE_LABELS,
|
|
4
|
-
GitContext,
|
|
5
7
|
buildBadgeMap,
|
|
6
8
|
conflictedPaths,
|
|
7
|
-
isFileDirty
|
|
9
|
+
isFileDirty
|
|
10
|
+
} from "./chunk-V2ENBGUA.js";
|
|
11
|
+
import {
|
|
12
|
+
useMenuKeyboard
|
|
13
|
+
} from "./chunk-MRUK56JS.js";
|
|
14
|
+
import {
|
|
15
|
+
GitContext,
|
|
8
16
|
useGitContext
|
|
9
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-6E635KCJ.js";
|
|
10
18
|
import {
|
|
11
19
|
createImageSaveOutput,
|
|
12
20
|
updateExportTargetExtension
|
|
13
21
|
} from "./chunk-FNSRCCBC.js";
|
|
22
|
+
import {
|
|
23
|
+
runExport
|
|
24
|
+
} from "./chunk-ODYNOPC3.js";
|
|
25
|
+
import {
|
|
26
|
+
buildExportFilename
|
|
27
|
+
} from "./chunk-M5Y5WO7Z.js";
|
|
28
|
+
import {
|
|
29
|
+
createLocalProofingIgnoreStore
|
|
30
|
+
} from "./chunk-DUKTAKB4.js";
|
|
14
31
|
import {
|
|
15
32
|
AccentColorSettings,
|
|
16
33
|
DB_CHROME_COLORS,
|
|
34
|
+
DEFAULT_PROOFING_PREFERENCES,
|
|
17
35
|
DEFAULT_WRITE_CANVAS_FONT_SCHEME,
|
|
18
36
|
DEFAULT_WRITE_CANVAS_PREFERENCES,
|
|
37
|
+
ProofingSettingsControls,
|
|
19
38
|
SettingsDialog,
|
|
20
39
|
ThemeSettings,
|
|
21
40
|
WRITE_CANVAS_FONT_SCHEMES,
|
|
22
41
|
WriteCanvasSettingsControls,
|
|
23
42
|
loadAccentColor,
|
|
43
|
+
loadProofingPreferences,
|
|
24
44
|
loadThemePreference,
|
|
25
45
|
loadWriteCanvasPreferences,
|
|
26
46
|
resolveWriteCanvasFonts,
|
|
27
47
|
saveAccentColor,
|
|
48
|
+
saveProofingPreferences,
|
|
28
49
|
saveThemePreference,
|
|
29
50
|
saveWriteCanvasPreferences
|
|
30
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-Q6XNIKDG.js";
|
|
31
52
|
import {
|
|
32
53
|
pickEmptyDocumentPrompt,
|
|
33
54
|
useResponsivePreviewViewportPreset
|
|
34
55
|
} from "./chunk-JDJVRDOP.js";
|
|
35
56
|
import {
|
|
36
57
|
ExportDialog
|
|
37
|
-
} from "./chunk-
|
|
38
|
-
import {
|
|
39
|
-
runExport
|
|
40
|
-
} from "./chunk-ODYNOPC3.js";
|
|
41
|
-
import {
|
|
42
|
-
createBrowserSaveAsAdapter
|
|
43
|
-
} from "./chunk-UMEDHMT7.js";
|
|
44
|
-
import {
|
|
45
|
-
useMenuKeyboard
|
|
46
|
-
} from "./chunk-MRUK56JS.js";
|
|
58
|
+
} from "./chunk-FMDLZ4ZG.js";
|
|
47
59
|
import "./chunk-YBEYTVU2.js";
|
|
48
|
-
import {
|
|
49
|
-
Dialog
|
|
50
|
-
} from "./chunk-LG6HAWCK.js";
|
|
51
|
-
import {
|
|
52
|
-
buildExportFilename
|
|
53
|
-
} from "./chunk-M5Y5WO7Z.js";
|
|
54
60
|
import {
|
|
55
61
|
DEFAULT_OPTIONS,
|
|
56
62
|
loadLastExportOptions
|
|
57
63
|
} from "./chunk-EBWYGTN7.js";
|
|
64
|
+
import {
|
|
65
|
+
Dialog
|
|
66
|
+
} from "./chunk-LG6HAWCK.js";
|
|
58
67
|
|
|
59
68
|
// src/FileExplorer/FileExplorer.tsx
|
|
60
69
|
import { useCallback as useCallback4, useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState4 } from "react";
|
|
61
70
|
import {
|
|
62
71
|
isFileSystemMoveStateError,
|
|
63
|
-
parseWorkspacePath as
|
|
72
|
+
parseWorkspacePath as parseWorkspacePath4
|
|
64
73
|
} from "@bendyline/docblocks/filesystem";
|
|
65
74
|
|
|
66
75
|
// src/FileExplorer/useFileTree.ts
|
|
@@ -1588,54 +1597,654 @@ function isHiddenFileEntry(entry) {
|
|
|
1588
1597
|
if (name.startsWith(".")) return true;
|
|
1589
1598
|
return entry.kind === "directory" && name.endsWith("_files");
|
|
1590
1599
|
}
|
|
1591
|
-
function filterVisibleFileEntries(entries) {
|
|
1592
|
-
return entries.filter((entry) => !isHiddenFileEntry(entry));
|
|
1600
|
+
function filterVisibleFileEntries(entries) {
|
|
1601
|
+
return entries.filter((entry) => !isHiddenFileEntry(entry));
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
// src/FileExplorer/entry-sort.ts
|
|
1605
|
+
function compareText(left, right) {
|
|
1606
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
1607
|
+
}
|
|
1608
|
+
function modifiedTime(entry) {
|
|
1609
|
+
if (entry.kind !== "file" || !entry.lastModified) return null;
|
|
1610
|
+
const timestamp = Date.parse(entry.lastModified);
|
|
1611
|
+
return Number.isNaN(timestamp) ? null : timestamp;
|
|
1612
|
+
}
|
|
1613
|
+
function sortFileEntries(entries, mode) {
|
|
1614
|
+
return [...entries].sort((left, right) => {
|
|
1615
|
+
if (left.kind !== right.kind) return left.kind === "directory" ? -1 : 1;
|
|
1616
|
+
if (left.kind === "directory" || right.kind === "directory" || mode === "name") {
|
|
1617
|
+
return compareText(left.name, right.name);
|
|
1618
|
+
}
|
|
1619
|
+
const leftTime = modifiedTime(left);
|
|
1620
|
+
const rightTime = modifiedTime(right);
|
|
1621
|
+
if (leftTime !== null && rightTime !== null && leftTime !== rightTime) {
|
|
1622
|
+
return rightTime - leftTime;
|
|
1623
|
+
}
|
|
1624
|
+
if (leftTime === null && rightTime !== null) return 1;
|
|
1625
|
+
if (leftTime !== null && rightTime === null) return -1;
|
|
1626
|
+
return compareText(left.name, right.name);
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
// src/DocBlocksShell/outside-in.ts
|
|
1631
|
+
import {
|
|
1632
|
+
FileSystemContentContainer,
|
|
1633
|
+
FsError as FsError3,
|
|
1634
|
+
getFileSystemProviderV2 as getFileSystemProviderV23,
|
|
1635
|
+
parseWorkspacePath as parseWorkspacePath3
|
|
1636
|
+
} from "@bendyline/docblocks/filesystem";
|
|
1637
|
+
import {
|
|
1638
|
+
createFileSystemDocumentTarget
|
|
1639
|
+
} from "@bendyline/docblocks/document";
|
|
1640
|
+
|
|
1641
|
+
// src/DocBlocksShell/provider-io.ts
|
|
1642
|
+
import {
|
|
1643
|
+
FsError as FsError2,
|
|
1644
|
+
getFileSystemProviderV2 as getFileSystemProviderV22,
|
|
1645
|
+
parseWorkspacePath as parseWorkspacePath2
|
|
1646
|
+
} from "@bendyline/docblocks/filesystem";
|
|
1647
|
+
async function providerEntryExists(provider, path) {
|
|
1648
|
+
const providerV2 = getFileSystemProviderV22(provider);
|
|
1649
|
+
return providerV2 ? await providerV2.stat(parseWorkspacePath2(path)) !== null : provider.exists(path);
|
|
1650
|
+
}
|
|
1651
|
+
async function writeProviderText(provider, path, content, mode = "upsert") {
|
|
1652
|
+
const providerV2 = getFileSystemProviderV22(provider);
|
|
1653
|
+
if (providerV2) {
|
|
1654
|
+
await providerV2.writeFile(parseWorkspacePath2(path), new TextEncoder().encode(content), {
|
|
1655
|
+
mode,
|
|
1656
|
+
createParents: true,
|
|
1657
|
+
expectedVersion: mode === "create" ? null : void 0
|
|
1658
|
+
});
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
if (mode === "create" && await provider.exists(path)) {
|
|
1662
|
+
throw new FsError2("already-exists", "File already exists.", { operation: "write", path });
|
|
1663
|
+
}
|
|
1664
|
+
await provider.writeFile(path, content);
|
|
1665
|
+
}
|
|
1666
|
+
async function removeProviderEntry(provider, path) {
|
|
1667
|
+
const providerV2 = getFileSystemProviderV22(provider);
|
|
1668
|
+
if (providerV2) {
|
|
1669
|
+
await providerV2.remove(parseWorkspacePath2(path), { recursive: true, missing: "ignore" });
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
await provider.delete(path);
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
// src/DocBlocksShell/outside-in-contract.ts
|
|
1676
|
+
var OUTSIDE_IN_FORMAT_IDS = ["html", "docx", "pdf", "pptx", "xlsx", "csv"];
|
|
1677
|
+
var FORMAT_IDS = new Set(OUTSIDE_IN_FORMAT_IDS);
|
|
1678
|
+
var UPDATE_FROM_MARKDOWN_KEY = "squisq-updatefrommarkdown";
|
|
1679
|
+
var HTML_OUTPUT_KEY = "squisq-html-output";
|
|
1680
|
+
async function loadOutsideInModule() {
|
|
1681
|
+
return await import("@bendyline/squisq-formats/outside-in");
|
|
1682
|
+
}
|
|
1683
|
+
function normalizePath(path) {
|
|
1684
|
+
const leading = path.replace(/\\/g, "/").startsWith("/") ? "/" : "";
|
|
1685
|
+
const parts = path.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
1686
|
+
if (parts.some((part) => part === "." || part === "..")) {
|
|
1687
|
+
throw new Error(`Outside-in paths must be canonical workspace paths: ${path}`);
|
|
1688
|
+
}
|
|
1689
|
+
return leading + parts.join("/");
|
|
1690
|
+
}
|
|
1691
|
+
function join(parent, child) {
|
|
1692
|
+
if (!parent || parent === "/") return parent === "/" ? `/${child}` : child;
|
|
1693
|
+
return `${parent}/${child}`;
|
|
1694
|
+
}
|
|
1695
|
+
function slug(stem) {
|
|
1696
|
+
return stem.normalize("NFKD").replace(/\p{Mark}+/gu, "").toLocaleLowerCase("en-US").replace(/[^\p{Letter}\p{Number}]+/gu, "-").replace(/^-+|-+$/g, "") || "document";
|
|
1697
|
+
}
|
|
1698
|
+
function resolveOutsideInLayout(path) {
|
|
1699
|
+
const targetPath = normalizePath(path);
|
|
1700
|
+
const slash = targetPath.lastIndexOf("/");
|
|
1701
|
+
const parentDirectory = slash < 0 ? "" : slash === 0 ? "/" : targetPath.slice(0, slash);
|
|
1702
|
+
const filename = slash < 0 ? targetPath : targetPath.slice(slash + 1);
|
|
1703
|
+
const dot = filename.lastIndexOf(".");
|
|
1704
|
+
if (dot <= 0) return null;
|
|
1705
|
+
const rawFormat = filename.slice(dot + 1).toLowerCase();
|
|
1706
|
+
const format = rawFormat === "htm" ? "html" : rawFormat;
|
|
1707
|
+
if (!FORMAT_IDS.has(format)) return null;
|
|
1708
|
+
const stem = filename.slice(0, dot);
|
|
1709
|
+
const companionName = `${stem}_files`;
|
|
1710
|
+
const companionDirectory = join(parentDirectory, companionName);
|
|
1711
|
+
const markdownFilename = `${slug(stem)}.md`;
|
|
1712
|
+
const backupDirectory = join(companionDirectory, ".original");
|
|
1713
|
+
const backupFilename = `original.${format}`;
|
|
1714
|
+
return {
|
|
1715
|
+
targetPath,
|
|
1716
|
+
format,
|
|
1717
|
+
parentDirectory,
|
|
1718
|
+
stem,
|
|
1719
|
+
companionName,
|
|
1720
|
+
companionDirectory,
|
|
1721
|
+
markdownFilename,
|
|
1722
|
+
markdownPath: join(companionDirectory, markdownFilename),
|
|
1723
|
+
relativeTargetPath: `../${filename}`,
|
|
1724
|
+
backupDirectory,
|
|
1725
|
+
backupFilename,
|
|
1726
|
+
backupPath: join(backupDirectory, backupFilename)
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
function chooseOutsideInMarkdownPath(layout, paths) {
|
|
1730
|
+
const canonical = normalizePath(layout.markdownPath);
|
|
1731
|
+
const normalized = paths.map(normalizePath);
|
|
1732
|
+
const exact = normalized.find((path) => path === canonical);
|
|
1733
|
+
if (exact) return exact;
|
|
1734
|
+
const folded = normalized.find(
|
|
1735
|
+
(path) => path.toLocaleLowerCase("en-US") === canonical.toLocaleLowerCase("en-US")
|
|
1736
|
+
);
|
|
1737
|
+
if (folded) return folded;
|
|
1738
|
+
const prefix = `${normalizePath(layout.companionDirectory).replace(/\/$/, "")}/`;
|
|
1739
|
+
const markdown = normalized.filter(
|
|
1740
|
+
(path) => path.startsWith(prefix) && !path.slice(prefix.length).includes("/") && path.toLocaleLowerCase("en-US").endsWith(".md")
|
|
1741
|
+
);
|
|
1742
|
+
return markdown.length === 1 ? markdown[0] : null;
|
|
1743
|
+
}
|
|
1744
|
+
async function readOutsideInMetadata(source) {
|
|
1745
|
+
const { readOutsideInMetadata: readMetadata } = await loadOutsideInModule();
|
|
1746
|
+
const metadata = readMetadata(source);
|
|
1747
|
+
return metadata ? {
|
|
1748
|
+
...metadata,
|
|
1749
|
+
updateFromMarkdown: await isOutsideInMarkdownEditingEnabled(source)
|
|
1750
|
+
} : null;
|
|
1751
|
+
}
|
|
1752
|
+
async function withOutsideInMetadata(source, layout) {
|
|
1753
|
+
const { withOutsideInMetadata: addMetadata } = await loadOutsideInModule();
|
|
1754
|
+
return addMetadata(source, layout);
|
|
1755
|
+
}
|
|
1756
|
+
async function isOutsideInMarkdownEditingEnabled(source) {
|
|
1757
|
+
const module = await loadOutsideInModule();
|
|
1758
|
+
if (module.isOutsideInMarkdownEditingEnabled) {
|
|
1759
|
+
return module.isOutsideInMarkdownEditingEnabled(source);
|
|
1760
|
+
}
|
|
1761
|
+
const { parseFrontmatter, splitFrontmatterBlock } = await import("@bendyline/squisq/markdown");
|
|
1762
|
+
const block = splitFrontmatterBlock(source).frontmatter;
|
|
1763
|
+
if (!block) return false;
|
|
1764
|
+
const firstBreak = block.indexOf("\n");
|
|
1765
|
+
if (firstBreak < 0) return false;
|
|
1766
|
+
const yaml = block.slice(firstBreak + 1).replace(/\r?\n---(?:\r?\n)?$/, "");
|
|
1767
|
+
return parseFrontmatter(yaml)?.[UPDATE_FROM_MARKDOWN_KEY] === true;
|
|
1768
|
+
}
|
|
1769
|
+
async function withOutsideInMarkdownEditing(source, layout, enabled = true) {
|
|
1770
|
+
const module = await loadOutsideInModule();
|
|
1771
|
+
if (module.withOutsideInMarkdownEditing) {
|
|
1772
|
+
return module.withOutsideInMarkdownEditing(source, layout, enabled);
|
|
1773
|
+
}
|
|
1774
|
+
const { setFrontmatterValues } = await import("@bendyline/squisq/markdown");
|
|
1775
|
+
return setFrontmatterValues(await withOutsideInMetadata(source, layout), {
|
|
1776
|
+
[UPDATE_FROM_MARKDOWN_KEY]: enabled
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
async function readOutsideInHtmlOutput(source) {
|
|
1780
|
+
const { parseFrontmatter, splitFrontmatterBlock } = await import("@bendyline/squisq/markdown");
|
|
1781
|
+
const block = splitFrontmatterBlock(source).frontmatter;
|
|
1782
|
+
if (!block) return null;
|
|
1783
|
+
const firstBreak = block.indexOf("\n");
|
|
1784
|
+
if (firstBreak < 0) return null;
|
|
1785
|
+
const yaml = block.slice(firstBreak + 1).replace(/\r?\n---(?:\r?\n)?$/, "");
|
|
1786
|
+
const value = parseFrontmatter(yaml)?.[HTML_OUTPUT_KEY];
|
|
1787
|
+
return value === "interactive" || value === "static" ? value : null;
|
|
1788
|
+
}
|
|
1789
|
+
async function withOutsideInHtmlOutput(source, output) {
|
|
1790
|
+
const { setFrontmatterValues } = await import("@bendyline/squisq/markdown");
|
|
1791
|
+
return setFrontmatterValues(source, { [HTML_OUTPUT_KEY]: output });
|
|
1792
|
+
}
|
|
1793
|
+
async function importOutsideInDocument(source, options = {}) {
|
|
1794
|
+
const { importOutsideInDocument: importDocument } = await loadOutsideInModule();
|
|
1795
|
+
const imported = await importDocument(source, options);
|
|
1796
|
+
const layout = resolveOutsideInLayout(source.targetPath);
|
|
1797
|
+
if (!layout) throw new Error(`Outside-in editing does not support "${source.targetPath}".`);
|
|
1798
|
+
return { ...imported, layout };
|
|
1799
|
+
}
|
|
1800
|
+
function isOutsideInDataFormat(format) {
|
|
1801
|
+
return format === "csv" || format === "xlsx";
|
|
1802
|
+
}
|
|
1803
|
+
async function importOutsideInDataSidecar(source) {
|
|
1804
|
+
const layout = resolveOutsideInLayout(source.targetPath);
|
|
1805
|
+
if (!layout || !isOutsideInDataFormat(layout.format)) {
|
|
1806
|
+
throw new Error(`Outside-in data import does not support "${source.targetPath}".`);
|
|
1807
|
+
}
|
|
1808
|
+
const data = source.data instanceof ArrayBuffer ? source.data : source.data.buffer.slice(
|
|
1809
|
+
source.data.byteOffset,
|
|
1810
|
+
source.data.byteOffset + source.data.byteLength
|
|
1811
|
+
);
|
|
1812
|
+
const sourceName = source.targetPath.replace(/\\/g, "/").split("/").pop() ?? `data.${layout.format}`;
|
|
1813
|
+
const container = layout.format === "csv" ? await import("@bendyline/squisq-formats/csv").then(
|
|
1814
|
+
({ csvToContainer }) => csvToContainer(data, { sourceName, sidecar: "always" })
|
|
1815
|
+
) : await import("@bendyline/squisq-formats/xlsx").then(
|
|
1816
|
+
({ xlsxToContainer }) => xlsxToContainer(data, {
|
|
1817
|
+
sourceName,
|
|
1818
|
+
sidecar: "always",
|
|
1819
|
+
sheetHeadings: false
|
|
1820
|
+
})
|
|
1821
|
+
);
|
|
1822
|
+
const importedMarkdown = await container.readDocument();
|
|
1823
|
+
if (importedMarkdown === null) {
|
|
1824
|
+
throw new Error(
|
|
1825
|
+
`The ${layout.format.toUpperCase()} importer did not create a Markdown companion.`
|
|
1826
|
+
);
|
|
1827
|
+
}
|
|
1828
|
+
return {
|
|
1829
|
+
layout,
|
|
1830
|
+
markdown: await withOutsideInMetadata(importedMarkdown, layout),
|
|
1831
|
+
container
|
|
1832
|
+
};
|
|
1833
|
+
}
|
|
1834
|
+
async function renderOutsideInDocument(source, options = {}) {
|
|
1835
|
+
const { renderOutsideInDocument: renderDocument } = await loadOutsideInModule();
|
|
1836
|
+
return renderDocument(source, options);
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// src/DocBlocksShell/outside-in.ts
|
|
1840
|
+
var OUTSIDE_IN_EXTENSION = /\.(?:html?|docx|pdf|pptx|xlsx|csv)$/i;
|
|
1841
|
+
var IMAGE_MIME_TYPES = {
|
|
1842
|
+
avif: "image/avif",
|
|
1843
|
+
bmp: "image/bmp",
|
|
1844
|
+
gif: "image/gif",
|
|
1845
|
+
ico: "image/x-icon",
|
|
1846
|
+
jpeg: "image/jpeg",
|
|
1847
|
+
jpg: "image/jpeg",
|
|
1848
|
+
png: "image/png",
|
|
1849
|
+
webp: "image/webp"
|
|
1850
|
+
};
|
|
1851
|
+
var SQUISQ_RUNTIME_DIRECTORY = "_squisq";
|
|
1852
|
+
var SQUISQ_RUNTIME_FILENAME = "squisq-player.js";
|
|
1853
|
+
function defaultOutsideInLayoutMode(outsideIn) {
|
|
1854
|
+
return outsideIn && isOutsideInDataFormat(outsideIn.format) ? "block" : void 0;
|
|
1855
|
+
}
|
|
1856
|
+
function withoutLeadingSlash(path) {
|
|
1857
|
+
return parseWorkspacePath3(path);
|
|
1858
|
+
}
|
|
1859
|
+
function withLegacySlash(path, like) {
|
|
1860
|
+
const canonical = withoutLeadingSlash(path);
|
|
1861
|
+
return like.startsWith("/") && canonical ? `/${canonical}` : canonical;
|
|
1862
|
+
}
|
|
1863
|
+
function dirname(path) {
|
|
1864
|
+
const canonical = withoutLeadingSlash(path);
|
|
1865
|
+
const slash = canonical.lastIndexOf("/");
|
|
1866
|
+
return slash < 0 ? "" : canonical.slice(0, slash);
|
|
1867
|
+
}
|
|
1868
|
+
function join2(parent, child) {
|
|
1869
|
+
return parent ? `${parent}/${child}` : child;
|
|
1870
|
+
}
|
|
1871
|
+
function relativePath(fromDirectory, targetPath) {
|
|
1872
|
+
const from = withoutLeadingSlash(fromDirectory).split("/").filter(Boolean);
|
|
1873
|
+
const target = withoutLeadingSlash(targetPath).split("/").filter(Boolean);
|
|
1874
|
+
let shared = 0;
|
|
1875
|
+
while (shared < from.length && shared < target.length && from[shared] === target[shared]) {
|
|
1876
|
+
shared++;
|
|
1877
|
+
}
|
|
1878
|
+
const segments = [...from.slice(shared).map(() => ".."), ...target.slice(shared)];
|
|
1879
|
+
return segments.join("/") || ".";
|
|
1880
|
+
}
|
|
1881
|
+
async function readText(provider, path) {
|
|
1882
|
+
const v2 = getFileSystemProviderV23(provider);
|
|
1883
|
+
if (!v2) return provider.readFile(path);
|
|
1884
|
+
const current = await v2.readFile(parseWorkspacePath3(path));
|
|
1885
|
+
if (!current) return null;
|
|
1886
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(current.data);
|
|
1887
|
+
}
|
|
1888
|
+
async function readBytes(provider, path) {
|
|
1889
|
+
const v2 = getFileSystemProviderV23(provider);
|
|
1890
|
+
if (v2) return (await v2.readFile(parseWorkspacePath3(path)))?.data ?? null;
|
|
1891
|
+
return provider.readBinary(path);
|
|
1892
|
+
}
|
|
1893
|
+
async function writeBytes(provider, path, data, mode = "upsert") {
|
|
1894
|
+
const v2 = getFileSystemProviderV23(provider);
|
|
1895
|
+
if (v2) {
|
|
1896
|
+
await v2.writeFile(parseWorkspacePath3(path), data, {
|
|
1897
|
+
mode,
|
|
1898
|
+
createParents: true,
|
|
1899
|
+
expectedVersion: mode === "create" ? null : void 0
|
|
1900
|
+
});
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1903
|
+
if (mode === "create" && await provider.exists(path)) {
|
|
1904
|
+
throw new FsError3("already-exists", "File already exists.", { operation: "write", path });
|
|
1905
|
+
}
|
|
1906
|
+
await provider.writeBinary(path, data);
|
|
1907
|
+
}
|
|
1908
|
+
async function listCompanionFiles(provider, layout) {
|
|
1909
|
+
try {
|
|
1910
|
+
const entries = await provider.readDirectory(layout.companionDirectory);
|
|
1911
|
+
return entries.filter((entry) => entry.kind === "file").map((entry) => entry.path);
|
|
1912
|
+
} catch (error) {
|
|
1913
|
+
if (error instanceof FsError3 && error.code === "not-found") return [];
|
|
1914
|
+
throw error;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
async function removeOutsideInCompanion(provider, layout) {
|
|
1918
|
+
const providerV2 = getFileSystemProviderV23(provider);
|
|
1919
|
+
if (providerV2) {
|
|
1920
|
+
const path = parseWorkspacePath3(layout.companionDirectory);
|
|
1921
|
+
if (await providerV2.stat(path) !== null) {
|
|
1922
|
+
await providerV2.remove(path, { recursive: true, missing: "ignore" });
|
|
1923
|
+
}
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
if (await provider.exists(layout.companionDirectory)) {
|
|
1927
|
+
await provider.delete(layout.companionDirectory);
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
async function persistImportedMedia(provider, layout, container) {
|
|
1931
|
+
const entries = await container.listFiles();
|
|
1932
|
+
for (const entry of entries) {
|
|
1933
|
+
if (/\.md$/i.test(entry.path)) continue;
|
|
1934
|
+
const data = await container.readFile(entry.path);
|
|
1935
|
+
if (!data) continue;
|
|
1936
|
+
await writeBytes(provider, join2(layout.companionDirectory, entry.path), data, "create");
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
async function loadEditableShellDocument(provider, selectedPath) {
|
|
1940
|
+
const imageExtension = selectedPath.slice(selectedPath.lastIndexOf(".") + 1).toLowerCase();
|
|
1941
|
+
const imageMimeType = IMAGE_MIME_TYPES[imageExtension];
|
|
1942
|
+
if (imageMimeType) {
|
|
1943
|
+
const data = await readBytes(provider, selectedPath);
|
|
1944
|
+
return data === null ? null : {
|
|
1945
|
+
displayPath: selectedPath,
|
|
1946
|
+
sourcePath: selectedPath,
|
|
1947
|
+
content: "",
|
|
1948
|
+
outsideIn: null,
|
|
1949
|
+
outsideInEditingEnabled: false,
|
|
1950
|
+
image: { data, mimeType: imageMimeType }
|
|
1951
|
+
};
|
|
1952
|
+
}
|
|
1953
|
+
if (!OUTSIDE_IN_EXTENSION.test(selectedPath)) {
|
|
1954
|
+
const content = await readText(provider, selectedPath);
|
|
1955
|
+
return content === null ? null : {
|
|
1956
|
+
displayPath: selectedPath,
|
|
1957
|
+
sourcePath: selectedPath,
|
|
1958
|
+
content,
|
|
1959
|
+
outsideIn: null,
|
|
1960
|
+
outsideInEditingEnabled: true
|
|
1961
|
+
};
|
|
1962
|
+
}
|
|
1963
|
+
const resolved = resolveOutsideInLayout(selectedPath);
|
|
1964
|
+
if (!resolved) return null;
|
|
1965
|
+
const layout = {
|
|
1966
|
+
...resolved,
|
|
1967
|
+
targetPath: withLegacySlash(resolved.targetPath, selectedPath),
|
|
1968
|
+
companionDirectory: withLegacySlash(resolved.companionDirectory, selectedPath),
|
|
1969
|
+
markdownPath: withLegacySlash(resolved.markdownPath, selectedPath)
|
|
1970
|
+
};
|
|
1971
|
+
const candidates = (await listCompanionFiles(provider, layout)).map(
|
|
1972
|
+
(path) => withLegacySlash(path, selectedPath)
|
|
1973
|
+
);
|
|
1974
|
+
const chosen = chooseOutsideInMarkdownPath(layout, candidates);
|
|
1975
|
+
if (chosen) {
|
|
1976
|
+
const content = await readText(provider, chosen);
|
|
1977
|
+
if (content === null) return null;
|
|
1978
|
+
const metadata = await readOutsideInMetadata(content);
|
|
1979
|
+
if (metadata && metadata.format !== layout.format) {
|
|
1980
|
+
throw new Error(
|
|
1981
|
+
`${chosen} is configured for ${metadata.format}, not ${layout.format}. Rename the rendered file back or repair the companion frontmatter.`
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
const linkedContent = await withOutsideInMetadata(content, layout);
|
|
1985
|
+
if (linkedContent !== content) await writeProviderText(provider, chosen, linkedContent);
|
|
1986
|
+
return {
|
|
1987
|
+
displayPath: selectedPath,
|
|
1988
|
+
sourcePath: chosen,
|
|
1989
|
+
content: linkedContent,
|
|
1990
|
+
outsideIn: { ...layout, markdownPath: chosen },
|
|
1991
|
+
outsideInEditingEnabled: await isOutsideInMarkdownEditingEnabled(linkedContent)
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
const rendered = await readBytes(provider, selectedPath);
|
|
1995
|
+
if (!rendered) return null;
|
|
1996
|
+
const imported = await importOutsideInDocument({
|
|
1997
|
+
data: rendered,
|
|
1998
|
+
targetPath: selectedPath
|
|
1999
|
+
});
|
|
2000
|
+
const importedLayout = {
|
|
2001
|
+
...imported.layout,
|
|
2002
|
+
targetPath: withLegacySlash(imported.layout.targetPath, selectedPath),
|
|
2003
|
+
companionDirectory: withLegacySlash(imported.layout.companionDirectory, selectedPath),
|
|
2004
|
+
markdownPath: withLegacySlash(imported.layout.markdownPath, selectedPath)
|
|
2005
|
+
};
|
|
2006
|
+
await persistImportedMedia(provider, importedLayout, imported.container);
|
|
2007
|
+
await writeProviderText(provider, importedLayout.markdownPath, imported.markdown, "create");
|
|
2008
|
+
return {
|
|
2009
|
+
displayPath: selectedPath,
|
|
2010
|
+
sourcePath: importedLayout.markdownPath,
|
|
2011
|
+
content: imported.markdown,
|
|
2012
|
+
outsideIn: importedLayout,
|
|
2013
|
+
outsideInEditingEnabled: false
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
async function enableOutsideInMarkdownEditing(provider, document2) {
|
|
2017
|
+
const layout = document2.outsideIn;
|
|
2018
|
+
if (!layout) throw new Error("This file does not support outside-in Markdown editing.");
|
|
2019
|
+
const original = await readBytes(provider, layout.targetPath);
|
|
2020
|
+
if (!original) throw new Error(`The rendered file "${layout.targetPath}" was not found.`);
|
|
2021
|
+
try {
|
|
2022
|
+
await writeBytes(provider, layout.backupPath, original, "create");
|
|
2023
|
+
} catch (error) {
|
|
2024
|
+
if (!(error instanceof FsError3 && error.code === "already-exists")) throw error;
|
|
2025
|
+
}
|
|
2026
|
+
const content = await withOutsideInMarkdownEditing(document2.content, layout);
|
|
2027
|
+
if (content !== document2.content) await writeProviderText(provider, document2.sourcePath, content);
|
|
2028
|
+
return { ...document2, content, outsideIn: layout, outsideInEditingEnabled: true };
|
|
2029
|
+
}
|
|
2030
|
+
async function findRuntimePath(provider, targetPath) {
|
|
2031
|
+
let directory = dirname(targetPath);
|
|
2032
|
+
for (; ; ) {
|
|
2033
|
+
const candidateDirectory = join2(directory, SQUISQ_RUNTIME_DIRECTORY);
|
|
2034
|
+
if (await providerEntryExists(provider, candidateDirectory)) {
|
|
2035
|
+
const providerV2 = getFileSystemProviderV23(provider);
|
|
2036
|
+
if (providerV2) {
|
|
2037
|
+
const entry = await providerV2.stat(parseWorkspacePath3(candidateDirectory));
|
|
2038
|
+
if (entry?.kind !== "directory") {
|
|
2039
|
+
throw new Error(`${candidateDirectory} must be a directory.`);
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
return join2(candidateDirectory, SQUISQ_RUNTIME_FILENAME);
|
|
2043
|
+
}
|
|
2044
|
+
if (!directory) break;
|
|
2045
|
+
directory = dirname(directory);
|
|
2046
|
+
}
|
|
2047
|
+
return join2(SQUISQ_RUNTIME_DIRECTORY, SQUISQ_RUNTIME_FILENAME);
|
|
2048
|
+
}
|
|
2049
|
+
async function writeRuntimeIfNeeded(provider, runtimePath) {
|
|
2050
|
+
const { PLAYER_BUNDLE } = await import("@bendyline/squisq-react/standalone-source");
|
|
2051
|
+
const current = await readText(provider, runtimePath);
|
|
2052
|
+
if (current !== PLAYER_BUNDLE) await writeProviderText(provider, runtimePath, PLAYER_BUNDLE);
|
|
1593
2053
|
}
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
2054
|
+
async function renderPlainOutsideInHtml(provider, layout, markdown) {
|
|
2055
|
+
const [{ parseMarkdown }, { markdownDocToPlainHtml }] = await Promise.all([
|
|
2056
|
+
import("@bendyline/squisq/markdown"),
|
|
2057
|
+
import("@bendyline/squisq-formats/html")
|
|
2058
|
+
]);
|
|
2059
|
+
const container = new FileSystemContentContainer(provider, layout.companionDirectory);
|
|
2060
|
+
const images = /* @__PURE__ */ new Map();
|
|
2061
|
+
for (const entry of await container.listFiles()) {
|
|
2062
|
+
const outputPath = `${layout.companionName}/${entry.path}`;
|
|
2063
|
+
images.set(entry.path, outputPath);
|
|
2064
|
+
images.set(`./${entry.path}`, outputPath);
|
|
2065
|
+
}
|
|
2066
|
+
return new TextEncoder().encode(
|
|
2067
|
+
markdownDocToPlainHtml(parseMarkdown(markdown), {
|
|
2068
|
+
title: layout.stem,
|
|
2069
|
+
images: images.size > 0 ? images : void 0
|
|
2070
|
+
})
|
|
2071
|
+
);
|
|
1598
2072
|
}
|
|
1599
|
-
function
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
2073
|
+
async function prepareOutsideInRender(provider, layout, markdown) {
|
|
2074
|
+
const htmlOutput = layout.format === "html" ? await readOutsideInHtmlOutput(markdown) : null;
|
|
2075
|
+
if (htmlOutput === "static") {
|
|
2076
|
+
return {
|
|
2077
|
+
bytes: await renderPlainOutsideInHtml(provider, layout, markdown),
|
|
2078
|
+
runtimePath: null
|
|
2079
|
+
};
|
|
2080
|
+
}
|
|
2081
|
+
const runtimePath = layout.format === "html" ? await findRuntimePath(provider, layout.targetPath) : null;
|
|
2082
|
+
const outputDirectory = dirname(layout.targetPath);
|
|
2083
|
+
const rendered = await renderOutsideInDocument(
|
|
2084
|
+
{
|
|
2085
|
+
markdown,
|
|
2086
|
+
targetPath: layout.targetPath,
|
|
2087
|
+
container: new FileSystemContentContainer(provider, layout.companionDirectory)
|
|
2088
|
+
},
|
|
2089
|
+
runtimePath ? {
|
|
2090
|
+
html: {
|
|
2091
|
+
playerScriptPath: relativePath(outputDirectory, runtimePath),
|
|
2092
|
+
basePath: relativePath(outputDirectory, layout.companionDirectory)
|
|
2093
|
+
},
|
|
2094
|
+
...htmlOutput === "interactive" ? { formatOptions: { html: { mode: "slideshow" } } } : {}
|
|
2095
|
+
} : {}
|
|
2096
|
+
);
|
|
2097
|
+
return { bytes: rendered.bytes, runtimePath };
|
|
1603
2098
|
}
|
|
1604
|
-
function
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
2099
|
+
async function createNewOutsideInDocument(provider, targetPath, htmlOutput) {
|
|
2100
|
+
const layout = resolveOutsideInLayout(targetPath);
|
|
2101
|
+
if (!layout) throw new Error(`Outside-in editing does not support "${targetPath}".`);
|
|
2102
|
+
if (layout.format !== "html" && htmlOutput !== void 0) {
|
|
2103
|
+
throw new Error("Only Web pages have an HTML output style.");
|
|
2104
|
+
}
|
|
2105
|
+
if (await providerEntryExists(provider, layout.targetPath) || await providerEntryExists(provider, layout.companionDirectory)) {
|
|
2106
|
+
throw new FsError3(
|
|
2107
|
+
"already-exists",
|
|
2108
|
+
"A file or companion folder with that name already exists.",
|
|
2109
|
+
{
|
|
2110
|
+
operation: "write",
|
|
2111
|
+
path: layout.targetPath
|
|
2112
|
+
}
|
|
2113
|
+
);
|
|
2114
|
+
}
|
|
2115
|
+
let content = await withOutsideInMarkdownEditing(`# ${layout.stem}
|
|
2116
|
+
`, layout);
|
|
2117
|
+
if (layout.format === "html") {
|
|
2118
|
+
content = await withOutsideInHtmlOutput(content, htmlOutput ?? "interactive");
|
|
2119
|
+
}
|
|
2120
|
+
const prepared = await prepareOutsideInRender(provider, layout, content);
|
|
2121
|
+
if (prepared.runtimePath) await writeRuntimeIfNeeded(provider, prepared.runtimePath);
|
|
2122
|
+
await writeBytes(provider, layout.targetPath, prepared.bytes, "create");
|
|
2123
|
+
await writeProviderText(provider, layout.markdownPath, content, "create");
|
|
2124
|
+
return {
|
|
2125
|
+
displayPath: layout.targetPath,
|
|
2126
|
+
sourcePath: layout.markdownPath,
|
|
2127
|
+
content,
|
|
2128
|
+
outsideIn: layout,
|
|
2129
|
+
outsideInEditingEnabled: true
|
|
2130
|
+
};
|
|
2131
|
+
}
|
|
2132
|
+
function createOutsideInDocumentTarget(provider, layout, onCommitted) {
|
|
2133
|
+
const sourceTarget = createFileSystemDocumentTarget(provider, layout.markdownPath);
|
|
2134
|
+
return {
|
|
2135
|
+
key: `${provider.id}:outside-in:${parseWorkspacePath3(layout.targetPath)}`,
|
|
2136
|
+
async commit(request) {
|
|
2137
|
+
if (!await isOutsideInMarkdownEditingEnabled(request.content)) {
|
|
2138
|
+
throw new Error(
|
|
2139
|
+
"Outside-in editing is read-only until squisq-updatefrommarkdown: true is set."
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
const rendered = await prepareOutsideInRender(provider, layout, request.content);
|
|
2143
|
+
await sourceTarget.commit({ ...request, targetKey: sourceTarget.key });
|
|
2144
|
+
if (rendered.runtimePath) await writeRuntimeIfNeeded(provider, rendered.runtimePath);
|
|
2145
|
+
await writeBytes(provider, layout.targetPath, rendered.bytes);
|
|
2146
|
+
onCommitted?.();
|
|
2147
|
+
return {};
|
|
1614
2148
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2151
|
+
function createOutsideInContentContainer(provider, layout) {
|
|
2152
|
+
return new FileSystemContentContainer(provider, layout.companionDirectory);
|
|
1619
2153
|
}
|
|
1620
2154
|
|
|
1621
|
-
// src/
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
".
|
|
1625
|
-
".md",
|
|
2155
|
+
// src/DocBlocksShell/import-file-types.ts
|
|
2156
|
+
var OUTSIDE_IN_IMPORT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2157
|
+
".csv",
|
|
2158
|
+
".docx",
|
|
1626
2159
|
".html",
|
|
1627
2160
|
".htm",
|
|
1628
|
-
".docx",
|
|
1629
2161
|
".pdf",
|
|
1630
2162
|
".pptx",
|
|
1631
|
-
".xlsx"
|
|
1632
|
-
".dbk",
|
|
1633
|
-
".zip"
|
|
2163
|
+
".xlsx"
|
|
1634
2164
|
]);
|
|
2165
|
+
var BUNDLE_IMPORT_EXTENSIONS = /* @__PURE__ */ new Set([".dbk", ".zip"]);
|
|
2166
|
+
var DIRECT_IMPORT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2167
|
+
".avif",
|
|
2168
|
+
".bash",
|
|
2169
|
+
".bmp",
|
|
2170
|
+
".c",
|
|
2171
|
+
".cc",
|
|
2172
|
+
".cpp",
|
|
2173
|
+
".cs",
|
|
2174
|
+
".css",
|
|
2175
|
+
".gif",
|
|
2176
|
+
".go",
|
|
2177
|
+
".h",
|
|
2178
|
+
".hpp",
|
|
2179
|
+
".ico",
|
|
2180
|
+
".ini",
|
|
2181
|
+
".java",
|
|
2182
|
+
".jpeg",
|
|
2183
|
+
".jpg",
|
|
2184
|
+
".js",
|
|
2185
|
+
".json",
|
|
2186
|
+
".jsonc",
|
|
2187
|
+
".jsx",
|
|
2188
|
+
".kt",
|
|
2189
|
+
".kts",
|
|
2190
|
+
".less",
|
|
2191
|
+
".log",
|
|
2192
|
+
".lua",
|
|
2193
|
+
".markdown",
|
|
2194
|
+
".md",
|
|
2195
|
+
".mdown",
|
|
2196
|
+
".mjs",
|
|
2197
|
+
".php",
|
|
2198
|
+
".png",
|
|
2199
|
+
".py",
|
|
2200
|
+
".rb",
|
|
2201
|
+
".rs",
|
|
2202
|
+
".scss",
|
|
2203
|
+
".sh",
|
|
2204
|
+
".sql",
|
|
2205
|
+
".svg",
|
|
2206
|
+
".swift",
|
|
2207
|
+
".toml",
|
|
2208
|
+
".ts",
|
|
2209
|
+
".tsv",
|
|
2210
|
+
".tsx",
|
|
2211
|
+
".txt",
|
|
2212
|
+
".webp",
|
|
2213
|
+
".xml",
|
|
2214
|
+
".yaml",
|
|
2215
|
+
".yml",
|
|
2216
|
+
".zsh"
|
|
2217
|
+
]);
|
|
2218
|
+
var DIRECT_IMPORT_BASENAMES = /* @__PURE__ */ new Set(["dockerfile", "license", "makefile", "readme"]);
|
|
2219
|
+
function extensionOfFileName(name) {
|
|
2220
|
+
const dot = name.lastIndexOf(".");
|
|
2221
|
+
return dot <= 0 ? "" : name.slice(dot).toLowerCase();
|
|
2222
|
+
}
|
|
2223
|
+
function isSupportedImportFile(file) {
|
|
2224
|
+
const extension = extensionOfFileName(file.name);
|
|
2225
|
+
if (OUTSIDE_IN_IMPORT_EXTENSIONS.has(extension) || BUNDLE_IMPORT_EXTENSIONS.has(extension) || DIRECT_IMPORT_EXTENSIONS.has(extension)) {
|
|
2226
|
+
return true;
|
|
2227
|
+
}
|
|
2228
|
+
const mimeType = file.type.toLowerCase();
|
|
2229
|
+
if (mimeType.startsWith("text/") || mimeType.startsWith("image/")) return true;
|
|
2230
|
+
return !extension && DIRECT_IMPORT_BASENAMES.has(file.name.toLowerCase());
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
// src/FileExplorer/FileExplorer.tsx
|
|
2234
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1635
2235
|
var INTERNAL_DRAG_TYPE = "application/x-docblocks-entry";
|
|
1636
2236
|
var NEW_ITEM_ERROR_ID = "db-new-item-error";
|
|
2237
|
+
var NEW_FILE_EXTENSIONS = {
|
|
2238
|
+
markdown: ".md",
|
|
2239
|
+
docx: ".docx",
|
|
2240
|
+
xlsx: ".xlsx",
|
|
2241
|
+
pdf: ".pdf",
|
|
2242
|
+
"web-interactive": ".html",
|
|
2243
|
+
"web-static": ".html"
|
|
2244
|
+
};
|
|
2245
|
+
var SELECTABLE_FILE_EXTENSION = /\.(?:md|docx|xlsx|pdf|html?)$/i;
|
|
1637
2246
|
function normalisePath2(path) {
|
|
1638
|
-
return
|
|
2247
|
+
return parseWorkspacePath4(path);
|
|
1639
2248
|
}
|
|
1640
2249
|
function hasEquivalentPath2(paths, path) {
|
|
1641
2250
|
const canonical = normalisePath2(path);
|
|
@@ -1701,6 +2310,7 @@ function FileExplorer({
|
|
|
1701
2310
|
[pinnedPaths]
|
|
1702
2311
|
);
|
|
1703
2312
|
const [newItemName, setNewItemName] = useState4("");
|
|
2313
|
+
const [newFileFormat, setNewFileFormat] = useState4("markdown");
|
|
1704
2314
|
const [uncontrolledSortMode, setUncontrolledSortMode] = useState4("name");
|
|
1705
2315
|
const selectedSortMode = sortMode ?? uncontrolledSortMode;
|
|
1706
2316
|
const selectSortMode = useCallback4(
|
|
@@ -1735,12 +2345,11 @@ function FileExplorer({
|
|
|
1735
2345
|
const hasSupported = useCallback4((dt) => {
|
|
1736
2346
|
for (const item of Array.from(dt.items)) {
|
|
1737
2347
|
if (item.kind !== "file") continue;
|
|
1738
|
-
const
|
|
1739
|
-
if (!
|
|
1740
|
-
|
|
1741
|
-
if (SUPPORTED_EXTENSIONS.has(ext)) return true;
|
|
2348
|
+
const file = item.getAsFile();
|
|
2349
|
+
if (!file) return true;
|
|
2350
|
+
if (isSupportedImportFile(file)) return true;
|
|
1742
2351
|
}
|
|
1743
|
-
return dt.
|
|
2352
|
+
return Array.from(dt.files).some(isSupportedImportFile);
|
|
1744
2353
|
}, []);
|
|
1745
2354
|
const handleDragEnter = useCallback4(
|
|
1746
2355
|
(e) => {
|
|
@@ -1774,11 +2383,8 @@ function FileExplorer({
|
|
|
1774
2383
|
e.preventDefault();
|
|
1775
2384
|
dragCounter.current = 0;
|
|
1776
2385
|
setDragOver(false);
|
|
1777
|
-
const
|
|
1778
|
-
|
|
1779
|
-
return SUPPORTED_EXTENSIONS.has(ext);
|
|
1780
|
-
});
|
|
1781
|
-
if (supported.length > 0) onImportFiles?.(supported);
|
|
2386
|
+
const files = Array.from(e.dataTransfer.files);
|
|
2387
|
+
if (files.length > 0) onImportFiles?.(files);
|
|
1782
2388
|
},
|
|
1783
2389
|
[onImportFiles]
|
|
1784
2390
|
);
|
|
@@ -1817,9 +2423,24 @@ function FileExplorer({
|
|
|
1817
2423
|
setNewItemCreationPending(true);
|
|
1818
2424
|
try {
|
|
1819
2425
|
if (itemType === "file") {
|
|
1820
|
-
const
|
|
2426
|
+
const stem = name.replace(SELECTABLE_FILE_EXTENSION, "");
|
|
2427
|
+
if (!stem) {
|
|
2428
|
+
setNewItemError("Enter a file name before the extension.");
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
const filename = `${stem}${NEW_FILE_EXTENSIONS[newFileFormat]}`;
|
|
1821
2432
|
createdPath = `${prefix}${filename}`;
|
|
1822
|
-
|
|
2433
|
+
if (newFileFormat === "markdown") {
|
|
2434
|
+
await tree.createFile(createdPath, "");
|
|
2435
|
+
} else {
|
|
2436
|
+
if (!provider) throw new Error("Open a workspace before creating a document.");
|
|
2437
|
+
await createNewOutsideInDocument(
|
|
2438
|
+
provider,
|
|
2439
|
+
createdPath,
|
|
2440
|
+
newFileFormat === "web-static" ? "static" : newFileFormat === "web-interactive" ? "interactive" : void 0
|
|
2441
|
+
);
|
|
2442
|
+
await tree.refresh();
|
|
2443
|
+
}
|
|
1823
2444
|
handleSelect(createdPath);
|
|
1824
2445
|
} else if (itemType === "directory") {
|
|
1825
2446
|
await tree.createDirectory(createdPath);
|
|
@@ -1834,7 +2455,7 @@ function FileExplorer({
|
|
|
1834
2455
|
setNewItemName("");
|
|
1835
2456
|
setNewItemType(null);
|
|
1836
2457
|
onTreeChange?.({ type: "create", path: createdPath });
|
|
1837
|
-
}, [newItemName, newItemType, tree, handleSelect
|
|
2458
|
+
}, [newFileFormat, newItemName, newItemType, onTreeChange, provider, tree, handleSelect]);
|
|
1838
2459
|
const handleMoveToWorkspace = useCallback4(async () => {
|
|
1839
2460
|
if (!onMoveToWorkspace || !moveDestinationId || movingToWorkspace) return;
|
|
1840
2461
|
setMovingToWorkspace(true);
|
|
@@ -2196,6 +2817,7 @@ function FileExplorer({
|
|
|
2196
2817
|
disabled: newItemCreationPending,
|
|
2197
2818
|
onClick: () => {
|
|
2198
2819
|
setNewItemError(null);
|
|
2820
|
+
setNewFileFormat("markdown");
|
|
2199
2821
|
setNewItemType("file");
|
|
2200
2822
|
},
|
|
2201
2823
|
title: "New File",
|
|
@@ -2274,7 +2896,7 @@ function FileExplorer({
|
|
|
2274
2896
|
/* @__PURE__ */ jsxs4(
|
|
2275
2897
|
"form",
|
|
2276
2898
|
{
|
|
2277
|
-
className:
|
|
2899
|
+
className: `db-new-item-row db-new-item-row--${newItemType}`,
|
|
2278
2900
|
"aria-busy": newItemCreationPending,
|
|
2279
2901
|
onSubmit: (e) => {
|
|
2280
2902
|
e.preventDefault();
|
|
@@ -2299,14 +2921,41 @@ function FileExplorer({
|
|
|
2299
2921
|
if (e.key === "Escape") {
|
|
2300
2922
|
setNewItemType(null);
|
|
2301
2923
|
setNewItemName("");
|
|
2924
|
+
setNewFileFormat("markdown");
|
|
2302
2925
|
setNewItemError(null);
|
|
2303
2926
|
}
|
|
2304
2927
|
},
|
|
2305
2928
|
autoFocus: true
|
|
2306
2929
|
}
|
|
2307
2930
|
),
|
|
2308
|
-
newItemType === "file"
|
|
2309
|
-
|
|
2931
|
+
newItemType === "file" ? /* @__PURE__ */ jsxs4("div", { className: "db-new-item-file-controls", children: [
|
|
2932
|
+
/* @__PURE__ */ jsxs4(
|
|
2933
|
+
"select",
|
|
2934
|
+
{
|
|
2935
|
+
className: "db-new-item-format",
|
|
2936
|
+
"aria-label": "New file type",
|
|
2937
|
+
value: newFileFormat,
|
|
2938
|
+
disabled: newItemCreationPending,
|
|
2939
|
+
onChange: (event) => {
|
|
2940
|
+
setNewFileFormat(event.currentTarget.value);
|
|
2941
|
+
setNewItemError(null);
|
|
2942
|
+
},
|
|
2943
|
+
children: [
|
|
2944
|
+
/* @__PURE__ */ jsxs4("optgroup", { label: "Document", children: [
|
|
2945
|
+
/* @__PURE__ */ jsx5("option", { value: "markdown", children: "Markdown (.md)" }),
|
|
2946
|
+
/* @__PURE__ */ jsx5("option", { value: "docx", children: "Word document (.docx)" }),
|
|
2947
|
+
/* @__PURE__ */ jsx5("option", { value: "xlsx", children: "Excel workbook (.xlsx)" }),
|
|
2948
|
+
/* @__PURE__ */ jsx5("option", { value: "pdf", children: "PDF document (.pdf)" })
|
|
2949
|
+
] }),
|
|
2950
|
+
/* @__PURE__ */ jsxs4("optgroup", { label: "Web page", children: [
|
|
2951
|
+
/* @__PURE__ */ jsx5("option", { value: "web-interactive", children: "Web page \u2014 Interactive (.html)" }),
|
|
2952
|
+
/* @__PURE__ */ jsx5("option", { value: "web-static", children: "Web page \u2014 Static (.html)" })
|
|
2953
|
+
] })
|
|
2954
|
+
]
|
|
2955
|
+
}
|
|
2956
|
+
),
|
|
2957
|
+
/* @__PURE__ */ jsx5("button", { type: "submit", className: "db-new-item-add", disabled: newItemCreationPending, children: newItemCreationPending ? "Adding\u2026" : "Add" })
|
|
2958
|
+
] }) : /* @__PURE__ */ jsx5("button", { type: "submit", className: "db-new-item-add", disabled: newItemCreationPending, children: newItemCreationPending ? "Adding\u2026" : "Add" })
|
|
2310
2959
|
]
|
|
2311
2960
|
}
|
|
2312
2961
|
),
|
|
@@ -2660,6 +3309,8 @@ function AppMenu({
|
|
|
2660
3309
|
onAccentColorChange,
|
|
2661
3310
|
writeCanvasSettings = DEFAULT_WRITE_CANVAS_PREFERENCES,
|
|
2662
3311
|
onWriteCanvasSettingsChange,
|
|
3312
|
+
proofingPreferences = DEFAULT_PROOFING_PREFERENCES,
|
|
3313
|
+
onProofingPreferencesChange,
|
|
2663
3314
|
versioningPreference = "browser-only",
|
|
2664
3315
|
onVersioningPreferenceChange,
|
|
2665
3316
|
onDownloadAllWorkspaces,
|
|
@@ -2834,6 +3485,13 @@ function AppMenu({
|
|
|
2834
3485
|
onChange: (settings) => onWriteCanvasSettingsChange?.(settings)
|
|
2835
3486
|
}
|
|
2836
3487
|
),
|
|
3488
|
+
/* @__PURE__ */ jsx7(
|
|
3489
|
+
ProofingSettingsControls,
|
|
3490
|
+
{
|
|
3491
|
+
value: proofingPreferences,
|
|
3492
|
+
onChange: (settings) => onProofingPreferencesChange?.(settings)
|
|
3493
|
+
}
|
|
3494
|
+
),
|
|
2837
3495
|
getStorageEstimate && /* @__PURE__ */ jsxs6("fieldset", { className: "db-settings-fieldset", children: [
|
|
2838
3496
|
/* @__PURE__ */ jsx7("legend", { className: "db-settings-legend", children: "Storage" }),
|
|
2839
3497
|
/* @__PURE__ */ jsx7("p", { className: "db-settings-hint", children: storageEstimate ? `DocBlocks documents and app data are using ${formatBytes(
|
|
@@ -3236,7 +3894,7 @@ function useDocumentSession(autoSaveDelayMs = 500) {
|
|
|
3236
3894
|
import { lazy, Suspense } from "react";
|
|
3237
3895
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
3238
3896
|
var ExportToolbarControlsImplementation = lazy(
|
|
3239
|
-
() => import("./ExportToolbarControls-
|
|
3897
|
+
() => import("./ExportToolbarControls-QYLBRWM7.js").then((module) => ({
|
|
3240
3898
|
default: module.ExportToolbarControls
|
|
3241
3899
|
}))
|
|
3242
3900
|
);
|
|
@@ -3359,27 +4017,39 @@ function useGit(provider, requestedWorkspaceId, theme) {
|
|
|
3359
4017
|
const available = gitApi !== null && capabilities?.gitAvailable === true;
|
|
3360
4018
|
const [repo, setRepo] = useState10(null);
|
|
3361
4019
|
const [remoteWeb, setRemoteWeb] = useState10(null);
|
|
4020
|
+
const [pendingGrant, setPendingGrant] = useState10(null);
|
|
4021
|
+
const loadRemote = useCallback9(
|
|
4022
|
+
(repositoryId2, isCancelled) => {
|
|
4023
|
+
if (!gitApi) return;
|
|
4024
|
+
void gitApi.listRemotes(repositoryId2).then(
|
|
4025
|
+
(remotes) => {
|
|
4026
|
+
if (isCancelled() || !remotes.ok) return;
|
|
4027
|
+
const first = remotes.value[0];
|
|
4028
|
+
setRemoteWeb(first?.web ?? null);
|
|
4029
|
+
},
|
|
4030
|
+
() => void 0
|
|
4031
|
+
);
|
|
4032
|
+
},
|
|
4033
|
+
[gitApi]
|
|
4034
|
+
);
|
|
3362
4035
|
useEffect9(() => {
|
|
3363
4036
|
setRepo(null);
|
|
3364
4037
|
setRemoteWeb(null);
|
|
4038
|
+
setPendingGrant(null);
|
|
3365
4039
|
if (!gitApi || !workspaceId || !available) return;
|
|
3366
4040
|
let cancelled = false;
|
|
4041
|
+
const isCancelled = () => cancelled;
|
|
3367
4042
|
void gitApi.detectRepo(workspaceId).then(
|
|
3368
4043
|
(result) => {
|
|
3369
|
-
if (cancelled || !result.ok || !result.value.isRepo
|
|
4044
|
+
if (cancelled || !result.ok || !result.value.isRepo) return;
|
|
4045
|
+
if (!result.value.repositoryId) {
|
|
4046
|
+
if (result.value.requiresExpandedGrant) {
|
|
4047
|
+
setPendingGrant({ repositoryRoot: result.value.repositoryRoot ?? null });
|
|
4048
|
+
}
|
|
3370
4049
|
return;
|
|
3371
4050
|
}
|
|
3372
4051
|
setRepo(result.value);
|
|
3373
|
-
|
|
3374
|
-
(remotes) => {
|
|
3375
|
-
if (cancelled || !remotes.ok) return;
|
|
3376
|
-
const first = remotes.value[0];
|
|
3377
|
-
setRemoteWeb(first?.web ?? null);
|
|
3378
|
-
},
|
|
3379
|
-
// No remote is a supported state; a failed probe degrades to it
|
|
3380
|
-
// rather than surfacing an unhandled rejection.
|
|
3381
|
-
() => void 0
|
|
3382
|
-
);
|
|
4052
|
+
loadRemote(result.value.repositoryId, isCancelled);
|
|
3383
4053
|
},
|
|
3384
4054
|
/* detection failure → not a repo, which is the default state */
|
|
3385
4055
|
() => void 0
|
|
@@ -3387,7 +4057,25 @@ function useGit(provider, requestedWorkspaceId, theme) {
|
|
|
3387
4057
|
return () => {
|
|
3388
4058
|
cancelled = true;
|
|
3389
4059
|
};
|
|
3390
|
-
}, [gitApi, workspaceId, available]);
|
|
4060
|
+
}, [gitApi, workspaceId, available, loadRemote]);
|
|
4061
|
+
const [grantBusy, setGrantBusy] = useState10(false);
|
|
4062
|
+
const enableExpandedRepo = useCallback9(
|
|
4063
|
+
async (opts) => {
|
|
4064
|
+
if (!gitApi || !workspaceId) return false;
|
|
4065
|
+
setGrantBusy(true);
|
|
4066
|
+
try {
|
|
4067
|
+
const result = await gitApi.grantExpandedRepo(workspaceId, opts);
|
|
4068
|
+
if (!result.ok || !result.value.repositoryId) return false;
|
|
4069
|
+
setRepo(result.value);
|
|
4070
|
+
setPendingGrant(null);
|
|
4071
|
+
loadRemote(result.value.repositoryId, () => false);
|
|
4072
|
+
return true;
|
|
4073
|
+
} finally {
|
|
4074
|
+
setGrantBusy(false);
|
|
4075
|
+
}
|
|
4076
|
+
},
|
|
4077
|
+
[gitApi, workspaceId, loadRemote]
|
|
4078
|
+
);
|
|
3391
4079
|
const repositoryId = repo?.repositoryId ?? null;
|
|
3392
4080
|
const isRepo = repositoryId !== null;
|
|
3393
4081
|
const { status, refresh, scheduleRefresh } = useGitStatus(gitApi, repositoryId, isRepo);
|
|
@@ -3536,6 +4224,9 @@ function useGit(provider, requestedWorkspaceId, theme) {
|
|
|
3536
4224
|
capabilities,
|
|
3537
4225
|
repo,
|
|
3538
4226
|
repositoryId,
|
|
4227
|
+
pendingGrant,
|
|
4228
|
+
grantBusy,
|
|
4229
|
+
enableExpandedRepo,
|
|
3539
4230
|
remoteWeb,
|
|
3540
4231
|
gitApi,
|
|
3541
4232
|
provider,
|
|
@@ -3563,6 +4254,9 @@ function useGit(provider, requestedWorkspaceId, theme) {
|
|
|
3563
4254
|
capabilities,
|
|
3564
4255
|
repo,
|
|
3565
4256
|
repositoryId,
|
|
4257
|
+
pendingGrant,
|
|
4258
|
+
grantBusy,
|
|
4259
|
+
enableExpandedRepo,
|
|
3566
4260
|
remoteWeb,
|
|
3567
4261
|
gitApi,
|
|
3568
4262
|
provider,
|
|
@@ -3753,159 +4447,11 @@ function hasControlCharacter(value) {
|
|
|
3753
4447
|
}
|
|
3754
4448
|
|
|
3755
4449
|
// src/DocBlocksShell/import-files.ts
|
|
3756
|
-
import {
|
|
3757
|
-
FsError as
|
|
3758
|
-
getFileSystemProviderV2 as
|
|
3759
|
-
parseWorkspacePath as
|
|
3760
|
-
} from "@bendyline/docblocks/filesystem";
|
|
3761
|
-
|
|
3762
|
-
// src/DocBlocksShell/outside-in-contract.ts
|
|
3763
|
-
var OUTSIDE_IN_FORMAT_IDS = ["html", "docx", "pdf", "pptx", "xlsx"];
|
|
3764
|
-
var FORMAT_IDS = new Set(OUTSIDE_IN_FORMAT_IDS);
|
|
3765
|
-
var UPDATE_FROM_MARKDOWN_KEY = "squisq-updatefrommarkdown";
|
|
3766
|
-
function normalizePath(path) {
|
|
3767
|
-
const leading = path.replace(/\\/g, "/").startsWith("/") ? "/" : "";
|
|
3768
|
-
const parts = path.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
3769
|
-
if (parts.some((part) => part === "." || part === "..")) {
|
|
3770
|
-
throw new Error(`Outside-in paths must be canonical workspace paths: ${path}`);
|
|
3771
|
-
}
|
|
3772
|
-
return leading + parts.join("/");
|
|
3773
|
-
}
|
|
3774
|
-
function join(parent, child) {
|
|
3775
|
-
if (!parent || parent === "/") return parent === "/" ? `/${child}` : child;
|
|
3776
|
-
return `${parent}/${child}`;
|
|
3777
|
-
}
|
|
3778
|
-
function slug(stem) {
|
|
3779
|
-
return stem.normalize("NFKD").replace(/\p{Mark}+/gu, "").toLocaleLowerCase("en-US").replace(/[^\p{Letter}\p{Number}]+/gu, "-").replace(/^-+|-+$/g, "") || "document";
|
|
3780
|
-
}
|
|
3781
|
-
function resolveOutsideInLayout(path) {
|
|
3782
|
-
const targetPath = normalizePath(path);
|
|
3783
|
-
const slash = targetPath.lastIndexOf("/");
|
|
3784
|
-
const parentDirectory = slash < 0 ? "" : slash === 0 ? "/" : targetPath.slice(0, slash);
|
|
3785
|
-
const filename = slash < 0 ? targetPath : targetPath.slice(slash + 1);
|
|
3786
|
-
const dot = filename.lastIndexOf(".");
|
|
3787
|
-
if (dot <= 0) return null;
|
|
3788
|
-
const rawFormat = filename.slice(dot + 1).toLowerCase();
|
|
3789
|
-
const format = rawFormat === "htm" ? "html" : rawFormat;
|
|
3790
|
-
if (!FORMAT_IDS.has(format)) return null;
|
|
3791
|
-
const stem = filename.slice(0, dot);
|
|
3792
|
-
const companionName = `${stem}_files`;
|
|
3793
|
-
const companionDirectory = join(parentDirectory, companionName);
|
|
3794
|
-
const markdownFilename = `${slug(stem)}.md`;
|
|
3795
|
-
const backupDirectory = join(companionDirectory, ".original");
|
|
3796
|
-
const backupFilename = `original.${format}`;
|
|
3797
|
-
return {
|
|
3798
|
-
targetPath,
|
|
3799
|
-
format,
|
|
3800
|
-
parentDirectory,
|
|
3801
|
-
stem,
|
|
3802
|
-
companionName,
|
|
3803
|
-
companionDirectory,
|
|
3804
|
-
markdownFilename,
|
|
3805
|
-
markdownPath: join(companionDirectory, markdownFilename),
|
|
3806
|
-
relativeTargetPath: `../${filename}`,
|
|
3807
|
-
backupDirectory,
|
|
3808
|
-
backupFilename,
|
|
3809
|
-
backupPath: join(backupDirectory, backupFilename)
|
|
3810
|
-
};
|
|
3811
|
-
}
|
|
3812
|
-
function chooseOutsideInMarkdownPath(layout, paths) {
|
|
3813
|
-
const canonical = normalizePath(layout.markdownPath);
|
|
3814
|
-
const normalized = paths.map(normalizePath);
|
|
3815
|
-
const exact = normalized.find((path) => path === canonical);
|
|
3816
|
-
if (exact) return exact;
|
|
3817
|
-
const folded = normalized.find(
|
|
3818
|
-
(path) => path.toLocaleLowerCase("en-US") === canonical.toLocaleLowerCase("en-US")
|
|
3819
|
-
);
|
|
3820
|
-
if (folded) return folded;
|
|
3821
|
-
const prefix = `${normalizePath(layout.companionDirectory).replace(/\/$/, "")}/`;
|
|
3822
|
-
const markdown = normalized.filter(
|
|
3823
|
-
(path) => path.startsWith(prefix) && !path.slice(prefix.length).includes("/") && path.toLocaleLowerCase("en-US").endsWith(".md")
|
|
3824
|
-
);
|
|
3825
|
-
return markdown.length === 1 ? markdown[0] : null;
|
|
3826
|
-
}
|
|
3827
|
-
async function readOutsideInMetadata(source) {
|
|
3828
|
-
const { readOutsideInMetadata: readMetadata } = await import("@bendyline/squisq-formats/outside-in");
|
|
3829
|
-
const metadata = readMetadata(source);
|
|
3830
|
-
return metadata ? {
|
|
3831
|
-
...metadata,
|
|
3832
|
-
updateFromMarkdown: await isOutsideInMarkdownEditingEnabled(source)
|
|
3833
|
-
} : null;
|
|
3834
|
-
}
|
|
3835
|
-
async function withOutsideInMetadata(source, layout) {
|
|
3836
|
-
const { withOutsideInMetadata: addMetadata } = await import("@bendyline/squisq-formats/outside-in");
|
|
3837
|
-
return addMetadata(source, layout);
|
|
3838
|
-
}
|
|
3839
|
-
async function isOutsideInMarkdownEditingEnabled(source) {
|
|
3840
|
-
const module = await import("@bendyline/squisq-formats/outside-in");
|
|
3841
|
-
if (module.isOutsideInMarkdownEditingEnabled) {
|
|
3842
|
-
return module.isOutsideInMarkdownEditingEnabled(source);
|
|
3843
|
-
}
|
|
3844
|
-
const { parseFrontmatter, splitFrontmatterBlock } = await import("@bendyline/squisq/markdown");
|
|
3845
|
-
const block = splitFrontmatterBlock(source).frontmatter;
|
|
3846
|
-
if (!block) return false;
|
|
3847
|
-
const firstBreak = block.indexOf("\n");
|
|
3848
|
-
if (firstBreak < 0) return false;
|
|
3849
|
-
const yaml = block.slice(firstBreak + 1).replace(/\r?\n---(?:\r?\n)?$/, "");
|
|
3850
|
-
return parseFrontmatter(yaml)?.[UPDATE_FROM_MARKDOWN_KEY] === true;
|
|
3851
|
-
}
|
|
3852
|
-
async function withOutsideInMarkdownEditing(source, layout, enabled = true) {
|
|
3853
|
-
const module = await import("@bendyline/squisq-formats/outside-in");
|
|
3854
|
-
if (module.withOutsideInMarkdownEditing) {
|
|
3855
|
-
return module.withOutsideInMarkdownEditing(source, layout, enabled);
|
|
3856
|
-
}
|
|
3857
|
-
const { setFrontmatterValues } = await import("@bendyline/squisq/markdown");
|
|
3858
|
-
return setFrontmatterValues(await withOutsideInMetadata(source, layout), {
|
|
3859
|
-
[UPDATE_FROM_MARKDOWN_KEY]: enabled
|
|
3860
|
-
});
|
|
3861
|
-
}
|
|
3862
|
-
async function importOutsideInDocument(source, options = {}) {
|
|
3863
|
-
const { importOutsideInDocument: importDocument } = await import("@bendyline/squisq-formats/outside-in");
|
|
3864
|
-
const imported = await importDocument(source, options);
|
|
3865
|
-
const layout = resolveOutsideInLayout(source.targetPath);
|
|
3866
|
-
if (!layout) throw new Error(`Outside-in editing does not support "${source.targetPath}".`);
|
|
3867
|
-
return { ...imported, layout };
|
|
3868
|
-
}
|
|
3869
|
-
async function renderOutsideInDocument(source, options = {}) {
|
|
3870
|
-
const { renderOutsideInDocument: renderDocument } = await import("@bendyline/squisq-formats/outside-in");
|
|
3871
|
-
return renderDocument(source, options);
|
|
3872
|
-
}
|
|
3873
|
-
|
|
3874
|
-
// src/DocBlocksShell/provider-io.ts
|
|
3875
|
-
import {
|
|
3876
|
-
FsError as FsError2,
|
|
3877
|
-
getFileSystemProviderV2 as getFileSystemProviderV22,
|
|
3878
|
-
parseWorkspacePath as parseWorkspacePath3
|
|
3879
|
-
} from "@bendyline/docblocks/filesystem";
|
|
3880
|
-
async function providerEntryExists(provider, path) {
|
|
3881
|
-
const providerV2 = getFileSystemProviderV22(provider);
|
|
3882
|
-
return providerV2 ? await providerV2.stat(parseWorkspacePath3(path)) !== null : provider.exists(path);
|
|
3883
|
-
}
|
|
3884
|
-
async function writeProviderText(provider, path, content, mode = "upsert") {
|
|
3885
|
-
const providerV2 = getFileSystemProviderV22(provider);
|
|
3886
|
-
if (providerV2) {
|
|
3887
|
-
await providerV2.writeFile(parseWorkspacePath3(path), new TextEncoder().encode(content), {
|
|
3888
|
-
mode,
|
|
3889
|
-
createParents: true,
|
|
3890
|
-
expectedVersion: mode === "create" ? null : void 0
|
|
3891
|
-
});
|
|
3892
|
-
return;
|
|
3893
|
-
}
|
|
3894
|
-
if (mode === "create" && await provider.exists(path)) {
|
|
3895
|
-
throw new FsError2("already-exists", "File already exists.", { operation: "write", path });
|
|
3896
|
-
}
|
|
3897
|
-
await provider.writeFile(path, content);
|
|
3898
|
-
}
|
|
3899
|
-
async function removeProviderEntry(provider, path) {
|
|
3900
|
-
const providerV2 = getFileSystemProviderV22(provider);
|
|
3901
|
-
if (providerV2) {
|
|
3902
|
-
await providerV2.remove(parseWorkspacePath3(path), { recursive: true, missing: "ignore" });
|
|
3903
|
-
return;
|
|
3904
|
-
}
|
|
3905
|
-
await provider.delete(path);
|
|
3906
|
-
}
|
|
3907
|
-
|
|
3908
|
-
// src/DocBlocksShell/import-files.ts
|
|
4450
|
+
import {
|
|
4451
|
+
FsError as FsError4,
|
|
4452
|
+
getFileSystemProviderV2 as getFileSystemProviderV24,
|
|
4453
|
+
parseWorkspacePath as parseWorkspacePath5
|
|
4454
|
+
} from "@bendyline/docblocks/filesystem";
|
|
3909
4455
|
var MAX_NAME_ATTEMPTS = 100;
|
|
3910
4456
|
function withCopySuffix(path, n) {
|
|
3911
4457
|
const dot = path.lastIndexOf(".");
|
|
@@ -3914,7 +4460,7 @@ function withCopySuffix(path, n) {
|
|
|
3914
4460
|
return `${path.slice(0, dot)} (${n})${path.slice(dot)}`;
|
|
3915
4461
|
}
|
|
3916
4462
|
function isAlreadyExists(error) {
|
|
3917
|
-
return error instanceof
|
|
4463
|
+
return error instanceof FsError4 && error.code === "already-exists";
|
|
3918
4464
|
}
|
|
3919
4465
|
async function claimAvailablePath(provider, desiredPath) {
|
|
3920
4466
|
for (let attempt = 1; attempt <= MAX_NAME_ATTEMPTS; attempt++) {
|
|
@@ -3929,9 +4475,9 @@ async function claimAvailablePath(provider, desiredPath) {
|
|
|
3929
4475
|
throw new Error(`Too many documents are already named like \u201C${desiredPath}\u201D.`);
|
|
3930
4476
|
}
|
|
3931
4477
|
async function writeProviderBytes(provider, path, data, mode) {
|
|
3932
|
-
const providerV2 =
|
|
4478
|
+
const providerV2 = getFileSystemProviderV24(provider);
|
|
3933
4479
|
if (providerV2) {
|
|
3934
|
-
await providerV2.writeFile(
|
|
4480
|
+
await providerV2.writeFile(parseWorkspacePath5(path), data, {
|
|
3935
4481
|
mode,
|
|
3936
4482
|
createParents: true,
|
|
3937
4483
|
expectedVersion: mode === "create" ? null : void 0
|
|
@@ -3939,11 +4485,10 @@ async function writeProviderBytes(provider, path, data, mode) {
|
|
|
3939
4485
|
return;
|
|
3940
4486
|
}
|
|
3941
4487
|
if (mode === "create" && await providerEntryExists(provider, path)) {
|
|
3942
|
-
throw new
|
|
4488
|
+
throw new FsError4("already-exists", "File already exists.", { operation: "write", path });
|
|
3943
4489
|
}
|
|
3944
4490
|
await provider.writeBinary(path, data);
|
|
3945
4491
|
}
|
|
3946
|
-
var OUTSIDE_IN_EXTENSIONS = /* @__PURE__ */ new Set([".html", ".htm", ".docx", ".pdf", ".pptx", ".xlsx"]);
|
|
3947
4492
|
async function claimOutsideInTarget(provider, desiredPath) {
|
|
3948
4493
|
for (let attempt = 1; attempt <= MAX_NAME_ATTEMPTS; attempt++) {
|
|
3949
4494
|
const candidate = attempt === 1 ? desiredPath : withCopySuffix(desiredPath, attempt);
|
|
@@ -3964,10 +4509,9 @@ async function importOutsideInFile(file, provider) {
|
|
|
3964
4509
|
const created = [claim.path];
|
|
3965
4510
|
try {
|
|
3966
4511
|
const sourceBytes = await file.arrayBuffer();
|
|
3967
|
-
const
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
});
|
|
4512
|
+
const layout = resolveOutsideInLayout(claim.path);
|
|
4513
|
+
if (!layout) throw new Error(`Outside-in editing does not support \u201C${claim.path}\u201D.`);
|
|
4514
|
+
const imported = await (isOutsideInDataFormat(layout.format) ? importOutsideInDataSidecar({ data: sourceBytes, targetPath: claim.path }) : importOutsideInDocument({ data: sourceBytes, targetPath: claim.path }));
|
|
3971
4515
|
for (const entry of await imported.container.listFiles()) {
|
|
3972
4516
|
if (/\.md$/i.test(entry.path)) continue;
|
|
3973
4517
|
const data = await imported.container.readFile(entry.path);
|
|
@@ -3987,10 +4531,7 @@ async function importOutsideInFile(file, provider) {
|
|
|
3987
4531
|
throw error;
|
|
3988
4532
|
}
|
|
3989
4533
|
}
|
|
3990
|
-
async function readImportedMarkdown(file,
|
|
3991
|
-
if (ext === ".md" || ext === ".txt") {
|
|
3992
|
-
return file.text();
|
|
3993
|
-
}
|
|
4534
|
+
async function readImportedMarkdown(file, destPath, provider) {
|
|
3994
4535
|
const snapshot = await decodeDbkWorkspace(await file.arrayBuffer(), {
|
|
3995
4536
|
targetDocumentPath: destPath
|
|
3996
4537
|
});
|
|
@@ -4004,27 +4545,31 @@ async function writeDbkCompanions(snapshot, provider) {
|
|
|
4004
4545
|
await writeProviderText(provider, entry.path, entry.content, "create");
|
|
4005
4546
|
}
|
|
4006
4547
|
}
|
|
4007
|
-
var SUPPORTED_EXTENSIONS2 = /* @__PURE__ */ new Set([".md", ".txt", ...OUTSIDE_IN_EXTENSIONS, ".dbk", ".zip"]);
|
|
4008
4548
|
async function importDroppedFiles(files, provider) {
|
|
4009
4549
|
const result = { imported: [], failed: [], unsupported: [] };
|
|
4010
4550
|
for (const file of files) {
|
|
4011
|
-
const ext =
|
|
4012
|
-
if (!
|
|
4551
|
+
const ext = extensionOfFileName(file.name);
|
|
4552
|
+
if (!isSupportedImportFile(file)) {
|
|
4013
4553
|
result.unsupported.push(file.name);
|
|
4014
4554
|
continue;
|
|
4015
4555
|
}
|
|
4016
|
-
const baseName = file.name.replace(/\.[^.]+$/, "");
|
|
4017
4556
|
let claimed = null;
|
|
4018
4557
|
try {
|
|
4019
|
-
if (
|
|
4558
|
+
if (OUTSIDE_IN_IMPORT_EXTENSIONS.has(ext)) {
|
|
4020
4559
|
const imported = await importOutsideInFile(file, provider);
|
|
4021
4560
|
result.imported.push({ source: file.name, ...imported });
|
|
4022
4561
|
continue;
|
|
4023
4562
|
}
|
|
4024
|
-
const
|
|
4563
|
+
const isBundle = BUNDLE_IMPORT_EXTENSIONS.has(ext);
|
|
4564
|
+
const desiredPath = isBundle ? `${file.name.replace(/\.[^.]+$/, "")}.md` : file.name;
|
|
4565
|
+
const claim = await claimAvailablePath(provider, desiredPath);
|
|
4025
4566
|
claimed = claim.path;
|
|
4026
|
-
|
|
4027
|
-
|
|
4567
|
+
if (isBundle) {
|
|
4568
|
+
const markdown = await readImportedMarkdown(file, claim.path, provider);
|
|
4569
|
+
await writeProviderText(provider, claim.path, markdown);
|
|
4570
|
+
} else {
|
|
4571
|
+
await writeProviderBytes(provider, claim.path, await file.arrayBuffer(), "upsert");
|
|
4572
|
+
}
|
|
4028
4573
|
result.imported.push({ source: file.name, path: claim.path, renamed: claim.renamed });
|
|
4029
4574
|
} catch (error) {
|
|
4030
4575
|
if (claimed) {
|
|
@@ -4040,16 +4585,13 @@ async function importDroppedFiles(files, provider) {
|
|
|
4040
4585
|
}
|
|
4041
4586
|
function summariseImport(result) {
|
|
4042
4587
|
const { imported, failed, unsupported } = result;
|
|
4043
|
-
|
|
4044
|
-
|
|
4588
|
+
const rejectedCount = failed.length + unsupported.length;
|
|
4589
|
+
if (rejectedCount > 0) {
|
|
4590
|
+
const detail = failed.length === 1 && unsupported.length === 0 ? `Could not import ${failed[0].source} \u2014 ${failed[0].message}` : unsupported.length === 1 && failed.length === 0 ? `${unsupported[0]} is not a file type DocBlocks can import.` : `Could not import ${rejectedCount} of ${rejectedCount + imported.length} files.`;
|
|
4045
4591
|
return { kind: "error", message: detail };
|
|
4046
4592
|
}
|
|
4047
4593
|
if (imported.length === 0) {
|
|
4048
|
-
|
|
4049
|
-
return {
|
|
4050
|
-
kind: "error",
|
|
4051
|
-
message: unsupported.length === 1 ? `${unsupported[0]} is not a file type DocBlocks can import.` : `${unsupported.length} dropped files are not file types DocBlocks can import.`
|
|
4052
|
-
};
|
|
4594
|
+
return null;
|
|
4053
4595
|
}
|
|
4054
4596
|
const renamed = imported.filter((entry) => entry.renamed);
|
|
4055
4597
|
if (renamed.length === 1) {
|
|
@@ -4067,241 +4609,6 @@ function summariseImport(result) {
|
|
|
4067
4609
|
return null;
|
|
4068
4610
|
}
|
|
4069
4611
|
|
|
4070
|
-
// src/DocBlocksShell/outside-in.ts
|
|
4071
|
-
import {
|
|
4072
|
-
FileSystemContentContainer,
|
|
4073
|
-
FsError as FsError4,
|
|
4074
|
-
getFileSystemProviderV2 as getFileSystemProviderV24,
|
|
4075
|
-
parseWorkspacePath as parseWorkspacePath5
|
|
4076
|
-
} from "@bendyline/docblocks/filesystem";
|
|
4077
|
-
import {
|
|
4078
|
-
createFileSystemDocumentTarget
|
|
4079
|
-
} from "@bendyline/docblocks/document";
|
|
4080
|
-
var OUTSIDE_IN_EXTENSION = /\.(?:html?|docx|pdf|pptx|xlsx)$/i;
|
|
4081
|
-
var SQUISQ_RUNTIME_DIRECTORY = "_squisq";
|
|
4082
|
-
var SQUISQ_RUNTIME_FILENAME = "squisq-player.js";
|
|
4083
|
-
function withoutLeadingSlash(path) {
|
|
4084
|
-
return parseWorkspacePath5(path);
|
|
4085
|
-
}
|
|
4086
|
-
function withLegacySlash(path, like) {
|
|
4087
|
-
const canonical = withoutLeadingSlash(path);
|
|
4088
|
-
return like.startsWith("/") && canonical ? `/${canonical}` : canonical;
|
|
4089
|
-
}
|
|
4090
|
-
function dirname(path) {
|
|
4091
|
-
const canonical = withoutLeadingSlash(path);
|
|
4092
|
-
const slash = canonical.lastIndexOf("/");
|
|
4093
|
-
return slash < 0 ? "" : canonical.slice(0, slash);
|
|
4094
|
-
}
|
|
4095
|
-
function join2(parent, child) {
|
|
4096
|
-
return parent ? `${parent}/${child}` : child;
|
|
4097
|
-
}
|
|
4098
|
-
function relativePath(fromDirectory, targetPath) {
|
|
4099
|
-
const from = withoutLeadingSlash(fromDirectory).split("/").filter(Boolean);
|
|
4100
|
-
const target = withoutLeadingSlash(targetPath).split("/").filter(Boolean);
|
|
4101
|
-
let shared = 0;
|
|
4102
|
-
while (shared < from.length && shared < target.length && from[shared] === target[shared]) {
|
|
4103
|
-
shared++;
|
|
4104
|
-
}
|
|
4105
|
-
const segments = [...from.slice(shared).map(() => ".."), ...target.slice(shared)];
|
|
4106
|
-
return segments.join("/") || ".";
|
|
4107
|
-
}
|
|
4108
|
-
async function readText(provider, path) {
|
|
4109
|
-
const v2 = getFileSystemProviderV24(provider);
|
|
4110
|
-
if (!v2) return provider.readFile(path);
|
|
4111
|
-
const current = await v2.readFile(parseWorkspacePath5(path));
|
|
4112
|
-
if (!current) return null;
|
|
4113
|
-
return new TextDecoder("utf-8", { fatal: true }).decode(current.data);
|
|
4114
|
-
}
|
|
4115
|
-
async function readBytes(provider, path) {
|
|
4116
|
-
const v2 = getFileSystemProviderV24(provider);
|
|
4117
|
-
if (v2) return (await v2.readFile(parseWorkspacePath5(path)))?.data ?? null;
|
|
4118
|
-
return provider.readBinary(path);
|
|
4119
|
-
}
|
|
4120
|
-
async function writeBytes(provider, path, data, mode = "upsert") {
|
|
4121
|
-
const v2 = getFileSystemProviderV24(provider);
|
|
4122
|
-
if (v2) {
|
|
4123
|
-
await v2.writeFile(parseWorkspacePath5(path), data, {
|
|
4124
|
-
mode,
|
|
4125
|
-
createParents: true,
|
|
4126
|
-
expectedVersion: mode === "create" ? null : void 0
|
|
4127
|
-
});
|
|
4128
|
-
return;
|
|
4129
|
-
}
|
|
4130
|
-
if (mode === "create" && await provider.exists(path)) {
|
|
4131
|
-
throw new FsError4("already-exists", "File already exists.", { operation: "write", path });
|
|
4132
|
-
}
|
|
4133
|
-
await provider.writeBinary(path, data);
|
|
4134
|
-
}
|
|
4135
|
-
async function listCompanionFiles(provider, layout) {
|
|
4136
|
-
try {
|
|
4137
|
-
const entries = await provider.readDirectory(layout.companionDirectory);
|
|
4138
|
-
return entries.filter((entry) => entry.kind === "file").map((entry) => entry.path);
|
|
4139
|
-
} catch (error) {
|
|
4140
|
-
if (error instanceof FsError4 && error.code === "not-found") return [];
|
|
4141
|
-
throw error;
|
|
4142
|
-
}
|
|
4143
|
-
}
|
|
4144
|
-
async function removeOutsideInCompanion(provider, layout) {
|
|
4145
|
-
const providerV2 = getFileSystemProviderV24(provider);
|
|
4146
|
-
if (providerV2) {
|
|
4147
|
-
const path = parseWorkspacePath5(layout.companionDirectory);
|
|
4148
|
-
if (await providerV2.stat(path) !== null) {
|
|
4149
|
-
await providerV2.remove(path, { recursive: true, missing: "ignore" });
|
|
4150
|
-
}
|
|
4151
|
-
return;
|
|
4152
|
-
}
|
|
4153
|
-
if (await provider.exists(layout.companionDirectory)) {
|
|
4154
|
-
await provider.delete(layout.companionDirectory);
|
|
4155
|
-
}
|
|
4156
|
-
}
|
|
4157
|
-
async function persistImportedMedia(provider, layout, container) {
|
|
4158
|
-
const entries = await container.listFiles();
|
|
4159
|
-
for (const entry of entries) {
|
|
4160
|
-
if (/\.md$/i.test(entry.path)) continue;
|
|
4161
|
-
const data = await container.readFile(entry.path);
|
|
4162
|
-
if (!data) continue;
|
|
4163
|
-
await writeBytes(provider, join2(layout.companionDirectory, entry.path), data, "create");
|
|
4164
|
-
}
|
|
4165
|
-
}
|
|
4166
|
-
async function loadEditableShellDocument(provider, selectedPath) {
|
|
4167
|
-
if (!OUTSIDE_IN_EXTENSION.test(selectedPath)) {
|
|
4168
|
-
const content = await readText(provider, selectedPath);
|
|
4169
|
-
return content === null ? null : {
|
|
4170
|
-
displayPath: selectedPath,
|
|
4171
|
-
sourcePath: selectedPath,
|
|
4172
|
-
content,
|
|
4173
|
-
outsideIn: null,
|
|
4174
|
-
outsideInEditingEnabled: true
|
|
4175
|
-
};
|
|
4176
|
-
}
|
|
4177
|
-
const resolved = resolveOutsideInLayout(selectedPath);
|
|
4178
|
-
if (!resolved) return null;
|
|
4179
|
-
const layout = {
|
|
4180
|
-
...resolved,
|
|
4181
|
-
targetPath: withLegacySlash(resolved.targetPath, selectedPath),
|
|
4182
|
-
companionDirectory: withLegacySlash(resolved.companionDirectory, selectedPath),
|
|
4183
|
-
markdownPath: withLegacySlash(resolved.markdownPath, selectedPath)
|
|
4184
|
-
};
|
|
4185
|
-
const candidates = (await listCompanionFiles(provider, layout)).map(
|
|
4186
|
-
(path) => withLegacySlash(path, selectedPath)
|
|
4187
|
-
);
|
|
4188
|
-
const chosen = chooseOutsideInMarkdownPath(layout, candidates);
|
|
4189
|
-
if (chosen) {
|
|
4190
|
-
const content = await readText(provider, chosen);
|
|
4191
|
-
if (content === null) return null;
|
|
4192
|
-
const metadata = await readOutsideInMetadata(content);
|
|
4193
|
-
if (metadata && metadata.format !== layout.format) {
|
|
4194
|
-
throw new Error(
|
|
4195
|
-
`${chosen} is configured for ${metadata.format}, not ${layout.format}. Rename the rendered file back or repair the companion frontmatter.`
|
|
4196
|
-
);
|
|
4197
|
-
}
|
|
4198
|
-
const linkedContent = await withOutsideInMetadata(content, layout);
|
|
4199
|
-
if (linkedContent !== content) await writeProviderText(provider, chosen, linkedContent);
|
|
4200
|
-
return {
|
|
4201
|
-
displayPath: selectedPath,
|
|
4202
|
-
sourcePath: chosen,
|
|
4203
|
-
content: linkedContent,
|
|
4204
|
-
outsideIn: { ...layout, markdownPath: chosen },
|
|
4205
|
-
outsideInEditingEnabled: await isOutsideInMarkdownEditingEnabled(linkedContent)
|
|
4206
|
-
};
|
|
4207
|
-
}
|
|
4208
|
-
const rendered = await readBytes(provider, selectedPath);
|
|
4209
|
-
if (!rendered) return null;
|
|
4210
|
-
const imported = await importOutsideInDocument({
|
|
4211
|
-
data: rendered,
|
|
4212
|
-
targetPath: selectedPath
|
|
4213
|
-
});
|
|
4214
|
-
const importedLayout = {
|
|
4215
|
-
...imported.layout,
|
|
4216
|
-
targetPath: withLegacySlash(imported.layout.targetPath, selectedPath),
|
|
4217
|
-
companionDirectory: withLegacySlash(imported.layout.companionDirectory, selectedPath),
|
|
4218
|
-
markdownPath: withLegacySlash(imported.layout.markdownPath, selectedPath)
|
|
4219
|
-
};
|
|
4220
|
-
await persistImportedMedia(provider, importedLayout, imported.container);
|
|
4221
|
-
await writeProviderText(provider, importedLayout.markdownPath, imported.markdown, "create");
|
|
4222
|
-
return {
|
|
4223
|
-
displayPath: selectedPath,
|
|
4224
|
-
sourcePath: importedLayout.markdownPath,
|
|
4225
|
-
content: imported.markdown,
|
|
4226
|
-
outsideIn: importedLayout,
|
|
4227
|
-
outsideInEditingEnabled: false
|
|
4228
|
-
};
|
|
4229
|
-
}
|
|
4230
|
-
async function enableOutsideInMarkdownEditing(provider, document2) {
|
|
4231
|
-
const layout = document2.outsideIn;
|
|
4232
|
-
if (!layout) throw new Error("This file does not support outside-in Markdown editing.");
|
|
4233
|
-
const original = await readBytes(provider, layout.targetPath);
|
|
4234
|
-
if (!original) throw new Error(`The rendered file "${layout.targetPath}" was not found.`);
|
|
4235
|
-
try {
|
|
4236
|
-
await writeBytes(provider, layout.backupPath, original, "create");
|
|
4237
|
-
} catch (error) {
|
|
4238
|
-
if (!(error instanceof FsError4 && error.code === "already-exists")) throw error;
|
|
4239
|
-
}
|
|
4240
|
-
const content = await withOutsideInMarkdownEditing(document2.content, layout);
|
|
4241
|
-
if (content !== document2.content) await writeProviderText(provider, document2.sourcePath, content);
|
|
4242
|
-
return { ...document2, content, outsideIn: layout, outsideInEditingEnabled: true };
|
|
4243
|
-
}
|
|
4244
|
-
async function findRuntimePath(provider, targetPath) {
|
|
4245
|
-
let directory = dirname(targetPath);
|
|
4246
|
-
for (; ; ) {
|
|
4247
|
-
const candidateDirectory = join2(directory, SQUISQ_RUNTIME_DIRECTORY);
|
|
4248
|
-
if (await providerEntryExists(provider, candidateDirectory)) {
|
|
4249
|
-
const providerV2 = getFileSystemProviderV24(provider);
|
|
4250
|
-
if (providerV2) {
|
|
4251
|
-
const entry = await providerV2.stat(parseWorkspacePath5(candidateDirectory));
|
|
4252
|
-
if (entry?.kind !== "directory") {
|
|
4253
|
-
throw new Error(`${candidateDirectory} must be a directory.`);
|
|
4254
|
-
}
|
|
4255
|
-
}
|
|
4256
|
-
return join2(candidateDirectory, SQUISQ_RUNTIME_FILENAME);
|
|
4257
|
-
}
|
|
4258
|
-
if (!directory) break;
|
|
4259
|
-
directory = dirname(directory);
|
|
4260
|
-
}
|
|
4261
|
-
return join2(SQUISQ_RUNTIME_DIRECTORY, SQUISQ_RUNTIME_FILENAME);
|
|
4262
|
-
}
|
|
4263
|
-
async function writeRuntimeIfNeeded(provider, runtimePath) {
|
|
4264
|
-
const { PLAYER_BUNDLE } = await import("@bendyline/squisq-react/standalone-source");
|
|
4265
|
-
const current = await readText(provider, runtimePath);
|
|
4266
|
-
if (current !== PLAYER_BUNDLE) await writeProviderText(provider, runtimePath, PLAYER_BUNDLE);
|
|
4267
|
-
}
|
|
4268
|
-
function createOutsideInDocumentTarget(provider, layout, onCommitted) {
|
|
4269
|
-
const sourceTarget = createFileSystemDocumentTarget(provider, layout.markdownPath);
|
|
4270
|
-
return {
|
|
4271
|
-
key: `${provider.id}:outside-in:${parseWorkspacePath5(layout.targetPath)}`,
|
|
4272
|
-
async commit(request) {
|
|
4273
|
-
if (!await isOutsideInMarkdownEditingEnabled(request.content)) {
|
|
4274
|
-
throw new Error(
|
|
4275
|
-
"Outside-in editing is read-only until squisq-updatefrommarkdown: true is set."
|
|
4276
|
-
);
|
|
4277
|
-
}
|
|
4278
|
-
const runtimePath = layout.format === "html" ? await findRuntimePath(provider, layout.targetPath) : null;
|
|
4279
|
-
const outputDirectory = dirname(layout.targetPath);
|
|
4280
|
-
const rendered = await renderOutsideInDocument(
|
|
4281
|
-
{
|
|
4282
|
-
markdown: request.content,
|
|
4283
|
-
targetPath: layout.targetPath,
|
|
4284
|
-
container: new FileSystemContentContainer(provider, layout.companionDirectory)
|
|
4285
|
-
},
|
|
4286
|
-
runtimePath ? {
|
|
4287
|
-
html: {
|
|
4288
|
-
playerScriptPath: relativePath(outputDirectory, runtimePath),
|
|
4289
|
-
basePath: relativePath(outputDirectory, layout.companionDirectory)
|
|
4290
|
-
}
|
|
4291
|
-
} : {}
|
|
4292
|
-
);
|
|
4293
|
-
await sourceTarget.commit({ ...request, targetKey: sourceTarget.key });
|
|
4294
|
-
if (runtimePath) await writeRuntimeIfNeeded(provider, runtimePath);
|
|
4295
|
-
await writeBytes(provider, layout.targetPath, rendered.bytes);
|
|
4296
|
-
onCommitted?.();
|
|
4297
|
-
return {};
|
|
4298
|
-
}
|
|
4299
|
-
};
|
|
4300
|
-
}
|
|
4301
|
-
function createOutsideInContentContainer(provider, layout) {
|
|
4302
|
-
return new FileSystemContentContainer(provider, layout.companionDirectory);
|
|
4303
|
-
}
|
|
4304
|
-
|
|
4305
4612
|
// src/components/usePromptDialog.ts
|
|
4306
4613
|
import React2, { useCallback as useCallback11, useEffect as useEffect12, useRef as useRef11, useState as useState12 } from "react";
|
|
4307
4614
|
|
|
@@ -5130,9 +5437,12 @@ function loadEditorShell() {
|
|
|
5130
5437
|
return editorShellModulePromise;
|
|
5131
5438
|
}
|
|
5132
5439
|
var EditorShell = lazy2(loadEditorShell);
|
|
5133
|
-
var GitUI = lazy2(() => import("./GitUI-
|
|
5440
|
+
var GitUI = lazy2(() => import("./GitUI-L5T3XHZG.js").then((m) => ({ default: m.GitUI })));
|
|
5441
|
+
var GitGrantNotice = lazy2(
|
|
5442
|
+
() => import("./GitGrantNotice-I2VNKPLH.js").then((m) => ({ default: m.GitGrantNotice }))
|
|
5443
|
+
);
|
|
5134
5444
|
var GitToolbarControl = lazy2(
|
|
5135
|
-
() => import("./GitToolbarControl-
|
|
5445
|
+
() => import("./GitToolbarControl-O5AXBC6T.js").then((m) => ({ default: m.GitToolbarControl }))
|
|
5136
5446
|
);
|
|
5137
5447
|
var DOCBLOCKS_VIDEO_EXPORT_PALETTE = Object.freeze({
|
|
5138
5448
|
overlay: "rgba(0, 0, 0, 0.72)",
|
|
@@ -5403,6 +5713,8 @@ function useIsMobile(breakpoint = 768) {
|
|
|
5403
5713
|
}, [breakpoint]);
|
|
5404
5714
|
return isMobile;
|
|
5405
5715
|
}
|
|
5716
|
+
var DESKTOP_TOOLBAR_WRAP_WIDTH = 900;
|
|
5717
|
+
var WEB_TOOLBAR_WRAP_WIDTH = 700;
|
|
5406
5718
|
function FolderGlyph() {
|
|
5407
5719
|
return /* @__PURE__ */ jsx14(
|
|
5408
5720
|
"svg",
|
|
@@ -5434,12 +5746,35 @@ function FileGlyph() {
|
|
|
5434
5746
|
}
|
|
5435
5747
|
);
|
|
5436
5748
|
}
|
|
5749
|
+
function CollapseSidebarGlyph() {
|
|
5750
|
+
return /* @__PURE__ */ jsxs12(
|
|
5751
|
+
"svg",
|
|
5752
|
+
{
|
|
5753
|
+
viewBox: "0 0 64 64",
|
|
5754
|
+
fill: "none",
|
|
5755
|
+
stroke: "currentColor",
|
|
5756
|
+
strokeWidth: "3",
|
|
5757
|
+
strokeLinecap: "round",
|
|
5758
|
+
strokeLinejoin: "round",
|
|
5759
|
+
"aria-hidden": "true",
|
|
5760
|
+
children: [
|
|
5761
|
+
/* @__PURE__ */ jsx14("rect", { x: "7", y: "10", width: "50", height: "44", rx: "6" }),
|
|
5762
|
+
/* @__PURE__ */ jsx14("path", { d: "M24 10v44" }),
|
|
5763
|
+
/* @__PURE__ */ jsx14("path", { d: "m17 25-7 7 7 7" })
|
|
5764
|
+
]
|
|
5765
|
+
}
|
|
5766
|
+
);
|
|
5767
|
+
}
|
|
5437
5768
|
function DocBlocksShell({
|
|
5438
5769
|
theme: hostTheme = "auto",
|
|
5439
5770
|
logoUrl,
|
|
5440
5771
|
issueReportVersion,
|
|
5441
5772
|
appBuildDate,
|
|
5442
5773
|
ffmpegWasm,
|
|
5774
|
+
calcEngineFactory,
|
|
5775
|
+
proofing,
|
|
5776
|
+
proofingDefaultEnabled,
|
|
5777
|
+
proofingIgnoreStore,
|
|
5443
5778
|
homeDocumentTitle,
|
|
5444
5779
|
homeDocumentPath,
|
|
5445
5780
|
allowVersioning = true,
|
|
@@ -5492,6 +5827,11 @@ function DocBlocksShell({
|
|
|
5492
5827
|
setWriteCanvasSettings(settings);
|
|
5493
5828
|
saveWriteCanvasPreferences(settings);
|
|
5494
5829
|
}, []);
|
|
5830
|
+
const [proofingPreferences, setProofingPreferences] = useState15(loadProofingPreferences);
|
|
5831
|
+
const handleProofingPreferencesChange = useCallback15((settings) => {
|
|
5832
|
+
setProofingPreferences(settings);
|
|
5833
|
+
saveProofingPreferences(settings);
|
|
5834
|
+
}, []);
|
|
5495
5835
|
const [viewPreferences, setViewPreferences] = useState15(loadViewPreferences);
|
|
5496
5836
|
const handleViewPreferencesChange = useCallback15((prefs) => {
|
|
5497
5837
|
setViewPreferences(prefs);
|
|
@@ -5508,6 +5848,27 @@ function DocBlocksShell({
|
|
|
5508
5848
|
const [sidebarWidth, setSidebarWidth] = useState15(loadSidebarWidth);
|
|
5509
5849
|
const [compactLayout, setCompactLayout] = useState15(false);
|
|
5510
5850
|
const effectiveCompact = isMobile || compactLayout;
|
|
5851
|
+
const editorAreaRef = useRef15(null);
|
|
5852
|
+
const [desktopToolbarWrapped, setDesktopToolbarWrapped] = useState15(false);
|
|
5853
|
+
useEffect15(() => {
|
|
5854
|
+
const editorArea = editorAreaRef.current;
|
|
5855
|
+
if (!editorArea || effectiveCompact) {
|
|
5856
|
+
setDesktopToolbarWrapped(false);
|
|
5857
|
+
return;
|
|
5858
|
+
}
|
|
5859
|
+
const wrapWidth = isElectronHost3() ? DESKTOP_TOOLBAR_WRAP_WIDTH : WEB_TOOLBAR_WRAP_WIDTH;
|
|
5860
|
+
const updateWrappedState = () => {
|
|
5861
|
+
setDesktopToolbarWrapped(editorArea.getBoundingClientRect().width <= wrapWidth);
|
|
5862
|
+
};
|
|
5863
|
+
updateWrappedState();
|
|
5864
|
+
if (typeof ResizeObserver === "undefined") {
|
|
5865
|
+
window.addEventListener("resize", updateWrappedState);
|
|
5866
|
+
return () => window.removeEventListener("resize", updateWrappedState);
|
|
5867
|
+
}
|
|
5868
|
+
const observer = new ResizeObserver(updateWrappedState);
|
|
5869
|
+
observer.observe(editorArea);
|
|
5870
|
+
return () => observer.disconnect();
|
|
5871
|
+
}, [effectiveCompact]);
|
|
5511
5872
|
const showBrowserStorageWarning = !isElectronHost3();
|
|
5512
5873
|
const appVersion = isElectronHost3() ? `${getDocBlocksHost().env.appVersion} desktop` : issueReportVersion ?? "web";
|
|
5513
5874
|
const issueReportUrl = buildIssueReportUrl({
|
|
@@ -5553,13 +5914,13 @@ function DocBlocksShell({
|
|
|
5553
5914
|
lastRaw = drag.startWidth + (ev.clientX - drag.startX);
|
|
5554
5915
|
if (lastRaw < SIDEBAR_COLLAPSE_THRESHOLD && sidebarRef.current) {
|
|
5555
5916
|
sidebarRef.current.style.width = `${SIDEBAR_WIDTH_MIN}px`;
|
|
5556
|
-
sidebarRef.current.
|
|
5917
|
+
sidebarRef.current.classList.add("db-shell-sidebar--collapse-preview");
|
|
5557
5918
|
return;
|
|
5558
5919
|
}
|
|
5559
5920
|
const clamped = Math.min(SIDEBAR_WIDTH_MAX, Math.max(SIDEBAR_WIDTH_MIN, lastRaw));
|
|
5560
5921
|
if (sidebarRef.current) {
|
|
5561
5922
|
sidebarRef.current.style.width = `${clamped}px`;
|
|
5562
|
-
sidebarRef.current.
|
|
5923
|
+
sidebarRef.current.classList.remove("db-shell-sidebar--collapse-preview");
|
|
5563
5924
|
}
|
|
5564
5925
|
};
|
|
5565
5926
|
const onUp = () => {
|
|
@@ -5568,7 +5929,7 @@ function DocBlocksShell({
|
|
|
5568
5929
|
document.body.style.userSelect = "";
|
|
5569
5930
|
document.body.classList.remove("db-resizing-sidebar");
|
|
5570
5931
|
if (sidebarRef.current) {
|
|
5571
|
-
sidebarRef.current.
|
|
5932
|
+
sidebarRef.current.classList.remove("db-shell-sidebar--collapse-preview");
|
|
5572
5933
|
}
|
|
5573
5934
|
if (lastRaw < SIDEBAR_COLLAPSE_THRESHOLD) {
|
|
5574
5935
|
setCompactLayout(true);
|
|
@@ -5595,6 +5956,11 @@ function DocBlocksShell({
|
|
|
5595
5956
|
const [workspaceStartupError, setWorkspaceStartupError] = useState15(null);
|
|
5596
5957
|
const [activeWorkspaceId, setActiveWorkspaceId] = useState15(null);
|
|
5597
5958
|
const [activeWorkspaceDescriptor, setActiveWorkspaceDescriptor] = useState15(null);
|
|
5959
|
+
const defaultProofingIgnoreStore = useMemo3(
|
|
5960
|
+
() => createLocalProofingIgnoreStore(() => activeWorkspaceId),
|
|
5961
|
+
[activeWorkspaceId]
|
|
5962
|
+
);
|
|
5963
|
+
const effectiveProofingIgnoreStore = proofingIgnoreStore === void 0 ? defaultProofingIgnoreStore : proofingIgnoreStore;
|
|
5598
5964
|
useEffect15(() => {
|
|
5599
5965
|
if (!provider || getTransientWorkspace(provider.id)) return;
|
|
5600
5966
|
const providerV2 = getFileSystemProviderV27(provider);
|
|
@@ -5751,11 +6117,17 @@ function DocBlocksShell({
|
|
|
5751
6117
|
const [selectedSourceFile, setSelectedSourceFile] = useState15(null);
|
|
5752
6118
|
const [selectedOutsideIn, setSelectedOutsideIn] = useState15(null);
|
|
5753
6119
|
const [selectedOutsideInEditingEnabled, setSelectedOutsideInEditingEnabled] = useState15(false);
|
|
6120
|
+
const [selectedImage, setSelectedImage] = useState15(void 0);
|
|
6121
|
+
const editorViewPreferences = useMemo3(() => {
|
|
6122
|
+
const layoutMode = defaultOutsideInLayoutMode(selectedOutsideIn);
|
|
6123
|
+
return layoutMode && viewPreferences.layoutMode === void 0 ? { ...viewPreferences, layoutMode } : viewPreferences;
|
|
6124
|
+
}, [selectedOutsideIn, viewPreferences]);
|
|
5754
6125
|
const adoptSelectedDocument = useCallback15((document2) => {
|
|
5755
6126
|
setSelectedFile(document2?.displayPath ?? null);
|
|
5756
6127
|
setSelectedSourceFile(document2?.sourcePath ?? null);
|
|
5757
6128
|
setSelectedOutsideIn(document2?.outsideIn ?? null);
|
|
5758
6129
|
setSelectedOutsideInEditingEnabled(document2?.outsideInEditingEnabled ?? false);
|
|
6130
|
+
setSelectedImage(document2?.image);
|
|
5759
6131
|
}, []);
|
|
5760
6132
|
const adoptRegularDocument = useCallback15((path) => {
|
|
5761
6133
|
if (path === null) {
|
|
@@ -5763,13 +6135,27 @@ function DocBlocksShell({
|
|
|
5763
6135
|
setSelectedSourceFile(null);
|
|
5764
6136
|
setSelectedOutsideIn(null);
|
|
5765
6137
|
setSelectedOutsideInEditingEnabled(false);
|
|
6138
|
+
setSelectedImage(void 0);
|
|
5766
6139
|
return;
|
|
5767
6140
|
}
|
|
5768
6141
|
setSelectedFile(path);
|
|
5769
6142
|
setSelectedSourceFile(path);
|
|
5770
6143
|
setSelectedOutsideIn(null);
|
|
5771
6144
|
setSelectedOutsideInEditingEnabled(false);
|
|
6145
|
+
setSelectedImage(void 0);
|
|
5772
6146
|
}, []);
|
|
6147
|
+
const selectedImageUrl = useMemo3(() => {
|
|
6148
|
+
if (!selectedImage || typeof URL === "undefined" || typeof URL.createObjectURL !== "function") {
|
|
6149
|
+
return void 0;
|
|
6150
|
+
}
|
|
6151
|
+
return URL.createObjectURL(new Blob([selectedImage.data], { type: selectedImage.mimeType }));
|
|
6152
|
+
}, [selectedImage]);
|
|
6153
|
+
useEffect15(
|
|
6154
|
+
() => () => {
|
|
6155
|
+
if (selectedImageUrl) URL.revokeObjectURL(selectedImageUrl);
|
|
6156
|
+
},
|
|
6157
|
+
[selectedImageUrl]
|
|
6158
|
+
);
|
|
5773
6159
|
useDocumentTitle(selectedFile, homeDocumentTitle, homeDocumentPath);
|
|
5774
6160
|
const exportDestinationAdapter = useMemo3(() => {
|
|
5775
6161
|
if (!selectedFile) return void 0;
|
|
@@ -6632,7 +7018,7 @@ function DocBlocksShell({
|
|
|
6632
7018
|
const providerV2 = getFileSystemProviderV27(provider);
|
|
6633
7019
|
if (!providerV2?.capabilities.watch) return;
|
|
6634
7020
|
const watchedFile = selectedSourceFile ?? selectedFile;
|
|
6635
|
-
if (!watchedFile || !documentSnapshot.targetKey) return;
|
|
7021
|
+
if (!watchedFile || !documentSnapshot.targetKey || selectedImage) return;
|
|
6636
7022
|
const targetKey = documentSnapshot.targetKey;
|
|
6637
7023
|
let disposed = false;
|
|
6638
7024
|
let reading = false;
|
|
@@ -6686,7 +7072,14 @@ function DocBlocksShell({
|
|
|
6686
7072
|
disposed = true;
|
|
6687
7073
|
void subscription.dispose();
|
|
6688
7074
|
};
|
|
6689
|
-
}, [
|
|
7075
|
+
}, [
|
|
7076
|
+
provider,
|
|
7077
|
+
selectedFile,
|
|
7078
|
+
selectedSourceFile,
|
|
7079
|
+
selectedImage,
|
|
7080
|
+
documentSession,
|
|
7081
|
+
documentSnapshot.targetKey
|
|
7082
|
+
]);
|
|
6690
7083
|
const transitionAwayFromDocument = useCallback15(
|
|
6691
7084
|
async (requestId) => {
|
|
6692
7085
|
if (requestId !== navigationRequestRef.current) return false;
|
|
@@ -7698,7 +8091,7 @@ function DocBlocksShell({
|
|
|
7698
8091
|
const nextFile = selectedFile ? relocateProviderPath(selectedFile, change.oldPath, change.newPath) : null;
|
|
7699
8092
|
const nextFolder = selectedFolder ? relocateProviderPath(selectedFolder, change.oldPath, change.newPath) : null;
|
|
7700
8093
|
if (nextFile !== selectedFile) {
|
|
7701
|
-
if (nextFile
|
|
8094
|
+
if (nextFile) {
|
|
7702
8095
|
const opened = await loadEditableShellDocument(provider, nextFile);
|
|
7703
8096
|
adoptSelectedDocument(opened);
|
|
7704
8097
|
} else {
|
|
@@ -7743,7 +8136,6 @@ function DocBlocksShell({
|
|
|
7743
8136
|
adoptRegularDocument,
|
|
7744
8137
|
adoptSelectedDocument,
|
|
7745
8138
|
selectedFile,
|
|
7746
|
-
selectedOutsideIn,
|
|
7747
8139
|
selectedFolder,
|
|
7748
8140
|
activeWorkspaceId,
|
|
7749
8141
|
pinnedDocuments,
|
|
@@ -8372,7 +8764,7 @@ function DocBlocksShell({
|
|
|
8372
8764
|
return /* @__PURE__ */ jsx14(
|
|
8373
8765
|
"div",
|
|
8374
8766
|
{
|
|
8375
|
-
className: `db-shell${effectiveCompact ? " db-shell--mobile" : ""}`,
|
|
8767
|
+
className: `db-shell${effectiveCompact ? " db-shell--mobile" : ""}${desktopToolbarWrapped ? " db-shell--desktop-toolbar-wrapped" : ""}`,
|
|
8376
8768
|
"data-theme": resolvedTheme,
|
|
8377
8769
|
"data-accent": accentColor,
|
|
8378
8770
|
"data-document-status": documentSnapshot.status,
|
|
@@ -8433,6 +8825,8 @@ function DocBlocksShell({
|
|
|
8433
8825
|
onAccentColorChange: handleAccentColorChange,
|
|
8434
8826
|
writeCanvasSettings,
|
|
8435
8827
|
onWriteCanvasSettingsChange: handleWriteCanvasSettingsChange,
|
|
8828
|
+
proofingPreferences,
|
|
8829
|
+
onProofingPreferencesChange: handleProofingPreferencesChange,
|
|
8436
8830
|
versioningPreference,
|
|
8437
8831
|
onVersioningPreferenceChange: handleVersioningPreferenceChange,
|
|
8438
8832
|
onDownloadAllWorkspaces: handleDownloadAllWorkspaces,
|
|
@@ -8544,6 +8938,7 @@ function DocBlocksShell({
|
|
|
8544
8938
|
]
|
|
8545
8939
|
}
|
|
8546
8940
|
),
|
|
8941
|
+
git.available && git.pendingGrant && /* @__PURE__ */ jsx14(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx14(GitGrantNotice, {}) }),
|
|
8547
8942
|
/* @__PURE__ */ jsxs12("div", { className: "db-shell-sidebar-footer", children: [
|
|
8548
8943
|
/* @__PURE__ */ jsx14("a", { href: "https://docblocks.com/docs/", target: "_blank", rel: "noopener noreferrer", children: "Docs" }),
|
|
8549
8944
|
/* @__PURE__ */ jsx14("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
|
|
@@ -8563,6 +8958,10 @@ function DocBlocksShell({
|
|
|
8563
8958
|
}
|
|
8564
8959
|
)
|
|
8565
8960
|
] })
|
|
8961
|
+
] }),
|
|
8962
|
+
/* @__PURE__ */ jsxs12("div", { className: "db-sidebar-collapse-preview", "aria-hidden": "true", children: [
|
|
8963
|
+
/* @__PURE__ */ jsx14("span", { className: "db-sidebar-collapse-preview-icon", children: /* @__PURE__ */ jsx14(CollapseSidebarGlyph, {}) }),
|
|
8964
|
+
/* @__PURE__ */ jsx14("span", { className: "db-sidebar-collapse-preview-label", children: "Release to hide files" })
|
|
8566
8965
|
] })
|
|
8567
8966
|
]
|
|
8568
8967
|
}
|
|
@@ -8580,6 +8979,7 @@ function DocBlocksShell({
|
|
|
8580
8979
|
(!effectiveCompact || mobileShowEditor) && /* @__PURE__ */ jsxs12(
|
|
8581
8980
|
"main",
|
|
8582
8981
|
{
|
|
8982
|
+
ref: editorAreaRef,
|
|
8583
8983
|
"aria-label": "Document editor",
|
|
8584
8984
|
className: updateAvailable && onApplyUpdate && updateStatusBarVisible ? "db-shell-editor-area db-shell-editor-area--has-update" : "db-shell-editor-area",
|
|
8585
8985
|
style: {
|
|
@@ -8599,11 +8999,13 @@ function DocBlocksShell({
|
|
|
8599
8999
|
EditorShell,
|
|
8600
9000
|
{
|
|
8601
9001
|
initialMarkdown: editorContent,
|
|
8602
|
-
readOnly: selectedOutsideIn !== null && !selectedOutsideInEditingEnabled,
|
|
9002
|
+
readOnly: selectedImage !== void 0 || selectedOutsideIn !== null && !selectedOutsideInEditingEnabled,
|
|
8603
9003
|
initialView,
|
|
8604
9004
|
defaultViewportPreset: defaultPreviewViewportPreset,
|
|
8605
9005
|
articleId: selectedFile,
|
|
8606
|
-
fileName: selectedFile,
|
|
9006
|
+
fileName: selectedSourceFile ?? selectedFile,
|
|
9007
|
+
imageSrc: selectedImageUrl,
|
|
9008
|
+
imageAlt: basenameOf(selectedFile),
|
|
8607
9009
|
saveCoverImageOutput: saveRenderedImageOutput,
|
|
8608
9010
|
saveDashboardImageOutput: saveRenderedImageOutput,
|
|
8609
9011
|
onChange: handleEditorChange,
|
|
@@ -8614,6 +9016,12 @@ function DocBlocksShell({
|
|
|
8614
9016
|
placeholder: editorPlaceholder,
|
|
8615
9017
|
outlineWidth: 280,
|
|
8616
9018
|
mediaProvider,
|
|
9019
|
+
calcEngineFactory,
|
|
9020
|
+
proofing,
|
|
9021
|
+
proofingDefaultEnabled,
|
|
9022
|
+
proofingSpellingEnabled: proofingPreferences.spelling,
|
|
9023
|
+
proofingGrammarEnabled: proofingPreferences.grammar,
|
|
9024
|
+
proofingIgnoreStore: effectiveProofingIgnoreStore,
|
|
8617
9025
|
showCodeCopyButton,
|
|
8618
9026
|
onCopyCode,
|
|
8619
9027
|
allowRecording,
|
|
@@ -8621,8 +9029,8 @@ function DocBlocksShell({
|
|
|
8621
9029
|
allowPresentationFullscreen,
|
|
8622
9030
|
documentLinkProvider,
|
|
8623
9031
|
workspaceContainer: versionsContainer ?? void 0,
|
|
8624
|
-
allowVersioning: effectiveVersioning,
|
|
8625
|
-
viewPreferences,
|
|
9032
|
+
allowVersioning: selectedImage === void 0 && effectiveVersioning,
|
|
9033
|
+
viewPreferences: editorViewPreferences,
|
|
8626
9034
|
onViewPreferencesChange: handleViewPreferencesChange,
|
|
8627
9035
|
versionBasename: versionBasename ?? stripExtension(basenameOf(selectedFile)),
|
|
8628
9036
|
versioningPrunePolicy,
|
|
@@ -8764,12 +9172,14 @@ export {
|
|
|
8764
9172
|
AccentColorSettings,
|
|
8765
9173
|
AppMenu,
|
|
8766
9174
|
DEFAULT_OPTIONS,
|
|
9175
|
+
DEFAULT_PROOFING_PREFERENCES,
|
|
8767
9176
|
DEFAULT_WRITE_CANVAS_FONT_SCHEME,
|
|
8768
9177
|
DocBlocksShell,
|
|
8769
9178
|
ExportDialog,
|
|
8770
9179
|
ExportToolbarControls,
|
|
8771
9180
|
FileExplorer,
|
|
8772
9181
|
FileTreeNode,
|
|
9182
|
+
ProofingSettingsControls,
|
|
8773
9183
|
SettingsDialog,
|
|
8774
9184
|
ThemeSettings,
|
|
8775
9185
|
WRITE_CANVAS_FONT_SCHEMES,
|
|
@@ -8780,8 +9190,10 @@ export {
|
|
|
8780
9190
|
createImageSaveOutput as createDashboardImageSaveOutput,
|
|
8781
9191
|
createImageSaveOutput,
|
|
8782
9192
|
loadLastExportOptions,
|
|
9193
|
+
loadProofingPreferences,
|
|
8783
9194
|
resolveWriteCanvasFonts,
|
|
8784
9195
|
runExport,
|
|
9196
|
+
saveProofingPreferences,
|
|
8785
9197
|
updateExportTargetExtension,
|
|
8786
9198
|
useDocumentSession,
|
|
8787
9199
|
useFileTree
|