@bendyline/docblocks-react 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/THIRD_PARTY_NOTICES.txt +457 -50
- package/dist/{ExportDialog-VBWHFJ2R.js → ExportDialog-Q4VWI43H.js} +2 -2
- package/dist/{ExportToolbarControls-N3TCL5DD.js → ExportToolbarControls-QYLBRWM7.js} +8 -8
- 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/{ShareDialog-PAMOQQFB.js → ShareDialog-4OX3UPJ4.js} +150 -3
- 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 +45 -8
- package/dist/index.js +952 -511
- 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 +22 -9
- package/src/styles/docblocks.css +443 -97
- package/dist/{chunk-SIIEGOHY.js → chunk-FMDLZ4ZG.js} +3 -3
|
@@ -5,21 +5,21 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
useMenuKeyboard
|
|
7
7
|
} from "./chunk-MRUK56JS.js";
|
|
8
|
-
import {
|
|
9
|
-
loadTransformStyleSummaries
|
|
10
|
-
} from "./chunk-YBEYTVU2.js";
|
|
11
|
-
import {
|
|
12
|
-
Dialog
|
|
13
|
-
} from "./chunk-LG6HAWCK.js";
|
|
14
8
|
import {
|
|
15
9
|
buildExportFilename
|
|
16
10
|
} from "./chunk-M5Y5WO7Z.js";
|
|
11
|
+
import {
|
|
12
|
+
loadTransformStyleSummaries
|
|
13
|
+
} from "./chunk-YBEYTVU2.js";
|
|
17
14
|
import {
|
|
18
15
|
DEFAULT_OPTIONS,
|
|
19
16
|
FORMAT_EXTENSIONS,
|
|
20
17
|
loadLastExportOptions,
|
|
21
18
|
saveExportOptions
|
|
22
19
|
} from "./chunk-EBWYGTN7.js";
|
|
20
|
+
import {
|
|
21
|
+
Dialog
|
|
22
|
+
} from "./chunk-LG6HAWCK.js";
|
|
23
23
|
|
|
24
24
|
// src/Export/ExportToolbarControls.tsx
|
|
25
25
|
import {
|
|
@@ -36,10 +36,10 @@ import { getThemeSummaries } from "@bendyline/squisq/schemas";
|
|
|
36
36
|
import { parseMarkdown } from "@bendyline/squisq/markdown";
|
|
37
37
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
38
38
|
var ExportDialog = lazy(
|
|
39
|
-
() => import("./ExportDialog-
|
|
39
|
+
() => import("./ExportDialog-Q4VWI43H.js").then((module) => ({ default: module.ExportDialog }))
|
|
40
40
|
);
|
|
41
41
|
var ShareDialog = lazy(
|
|
42
|
-
() => import("./ShareDialog-
|
|
42
|
+
() => import("./ShareDialog-4OX3UPJ4.js").then((module) => ({ default: module.ShareDialog }))
|
|
43
43
|
);
|
|
44
44
|
var runExportModulePromise = null;
|
|
45
45
|
function loadRunExportModule() {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useGitContext
|
|
3
|
+
} from "./chunk-6E635KCJ.js";
|
|
4
|
+
|
|
5
|
+
// src/Git/GitGrantNotice.tsx
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
function GitGrantNotice() {
|
|
8
|
+
const git = useGitContext();
|
|
9
|
+
if (!git || git.repo || !git.pendingGrant) return null;
|
|
10
|
+
const { repositoryRoot } = git.pendingGrant;
|
|
11
|
+
const detail = repositoryRoot ? `This folder is part of the repository ${repositoryRoot}.` : "This folder is part of a larger repository.";
|
|
12
|
+
return /* @__PURE__ */ jsxs("div", { className: "db-git-grant-notice", children: [
|
|
13
|
+
/* @__PURE__ */ jsx("span", { className: "db-git-grant-notice-text", children: "Git is off for this folder" }),
|
|
14
|
+
/* @__PURE__ */ jsx(
|
|
15
|
+
"button",
|
|
16
|
+
{
|
|
17
|
+
type: "button",
|
|
18
|
+
className: "db-git-grant-notice-action",
|
|
19
|
+
onClick: () => git.openDialog({ kind: "expanded-grant" }),
|
|
20
|
+
"aria-label": `Enable Git for this folder. ${detail}`,
|
|
21
|
+
title: detail,
|
|
22
|
+
children: "Enable"
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
] });
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
GitGrantNotice
|
|
29
|
+
};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import "./chunk-APC4KI4B.js";
|
|
2
2
|
import {
|
|
3
|
-
isFileDirty
|
|
4
|
-
|
|
5
|
-
} from "./chunk-HFYPTTCH.js";
|
|
3
|
+
isFileDirty
|
|
4
|
+
} from "./chunk-V2ENBGUA.js";
|
|
6
5
|
import {
|
|
7
6
|
useMenuKeyboard
|
|
8
7
|
} from "./chunk-MRUK56JS.js";
|
|
8
|
+
import {
|
|
9
|
+
useGitContext
|
|
10
|
+
} from "./chunk-6E635KCJ.js";
|
|
9
11
|
|
|
10
12
|
// src/Git/GitToolbarControl.tsx
|
|
11
13
|
import { useEffect, useRef, useState } from "react";
|
|
@@ -4,12 +4,14 @@ import {
|
|
|
4
4
|
BADGE_LABELS,
|
|
5
5
|
badgeKindFor,
|
|
6
6
|
formatAheadBehind,
|
|
7
|
-
summarizeDirty
|
|
8
|
-
|
|
9
|
-
} from "./chunk-HFYPTTCH.js";
|
|
7
|
+
summarizeDirty
|
|
8
|
+
} from "./chunk-V2ENBGUA.js";
|
|
10
9
|
import {
|
|
11
10
|
useMenuKeyboard
|
|
12
11
|
} from "./chunk-MRUK56JS.js";
|
|
12
|
+
import {
|
|
13
|
+
useGitContext
|
|
14
|
+
} from "./chunk-6E635KCJ.js";
|
|
13
15
|
import {
|
|
14
16
|
Dialog
|
|
15
17
|
} from "./chunk-LG6HAWCK.js";
|
|
@@ -1094,20 +1096,71 @@ function GitConflictsDialog({
|
|
|
1094
1096
|
);
|
|
1095
1097
|
}
|
|
1096
1098
|
|
|
1097
|
-
// src/Git/
|
|
1099
|
+
// src/Git/GitExpandedGrantDialog.tsx
|
|
1100
|
+
import { useState as useState7 } from "react";
|
|
1098
1101
|
import { Fragment as Fragment7, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1102
|
+
function GitExpandedGrantDialog({ onClose }) {
|
|
1103
|
+
const git = useGitContext();
|
|
1104
|
+
const [always, setAlways] = useState7(false);
|
|
1105
|
+
if (!git) return null;
|
|
1106
|
+
const repositoryRoot = git.pendingGrant?.repositoryRoot ?? null;
|
|
1107
|
+
return /* @__PURE__ */ jsxs10(
|
|
1108
|
+
Dialog,
|
|
1109
|
+
{
|
|
1110
|
+
title: "Enable Git for this folder?",
|
|
1111
|
+
onClose,
|
|
1112
|
+
footer: /* @__PURE__ */ jsxs10(Fragment7, { children: [
|
|
1113
|
+
/* @__PURE__ */ jsx10("button", { type: "button", className: "db-git-secondary-btn", onClick: onClose, children: "Not now" }),
|
|
1114
|
+
/* @__PURE__ */ jsx10(
|
|
1115
|
+
"button",
|
|
1116
|
+
{
|
|
1117
|
+
type: "button",
|
|
1118
|
+
className: "db-git-primary-btn",
|
|
1119
|
+
disabled: git.grantBusy,
|
|
1120
|
+
onClick: () => {
|
|
1121
|
+
void git.enableExpandedRepo({ always }).then(() => onClose());
|
|
1122
|
+
},
|
|
1123
|
+
children: git.grantBusy ? "Enabling\u2026" : "Enable Git"
|
|
1124
|
+
}
|
|
1125
|
+
)
|
|
1126
|
+
] }),
|
|
1127
|
+
children: [
|
|
1128
|
+
/* @__PURE__ */ jsx10("p", { className: "db-settings-hint", children: "This folder is part of a larger Git repository. Git operations such as pull, branch switching, and commit can change files outside the folder you opened." }),
|
|
1129
|
+
repositoryRoot && /* @__PURE__ */ jsxs10("p", { className: "db-git-hint", children: [
|
|
1130
|
+
"Repository: ",
|
|
1131
|
+
/* @__PURE__ */ jsx10("code", { children: repositoryRoot })
|
|
1132
|
+
] }),
|
|
1133
|
+
/* @__PURE__ */ jsxs10("label", { className: "db-git-grant-remember", children: [
|
|
1134
|
+
/* @__PURE__ */ jsx10(
|
|
1135
|
+
"input",
|
|
1136
|
+
{
|
|
1137
|
+
type: "checkbox",
|
|
1138
|
+
checked: always,
|
|
1139
|
+
onChange: (event) => setAlways(event.target.checked)
|
|
1140
|
+
}
|
|
1141
|
+
),
|
|
1142
|
+
/* @__PURE__ */ jsx10("span", { children: "Enable Git for every folder inside a repository, without asking" })
|
|
1143
|
+
] }),
|
|
1144
|
+
/* @__PURE__ */ jsx10("p", { className: "db-settings-hint", children: "DocBlocks remembers this repository either way. You can turn the choice back off by removing it from the desktop settings file." })
|
|
1145
|
+
]
|
|
1146
|
+
}
|
|
1147
|
+
);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// src/Git/GitUI.tsx
|
|
1151
|
+
import { Fragment as Fragment8, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1099
1152
|
function GitUI({ onOpenFile, onWorkspaceCloned }) {
|
|
1100
1153
|
const git = useGitContext();
|
|
1101
1154
|
if (!git || !git.available) return null;
|
|
1102
1155
|
const { dialog, closeDialog } = git;
|
|
1103
|
-
return /* @__PURE__ */
|
|
1104
|
-
/* @__PURE__ */
|
|
1105
|
-
git.repo && /* @__PURE__ */
|
|
1106
|
-
dialog.kind === "commit" && /* @__PURE__ */
|
|
1107
|
-
dialog.kind === "branches" && /* @__PURE__ */
|
|
1108
|
-
dialog.kind === "history" && /* @__PURE__ */
|
|
1109
|
-
dialog.kind === "diff" && /* @__PURE__ */
|
|
1110
|
-
dialog.kind === "clone" && /* @__PURE__ */
|
|
1156
|
+
return /* @__PURE__ */ jsxs11(Fragment8, { children: [
|
|
1157
|
+
/* @__PURE__ */ jsx11(GitStatusBar, {}),
|
|
1158
|
+
git.repo && /* @__PURE__ */ jsx11("span", { className: "db-git-inline-status", role: "status", "aria-live": "polite", children: git.lastResult?.message ?? "" }),
|
|
1159
|
+
dialog.kind === "commit" && /* @__PURE__ */ jsx11(GitCommitDialog, { onClose: closeDialog }),
|
|
1160
|
+
dialog.kind === "branches" && /* @__PURE__ */ jsx11(GitBranchesDialog, { createFocus: dialog.createFocus, onClose: closeDialog }),
|
|
1161
|
+
dialog.kind === "history" && /* @__PURE__ */ jsx11(GitHistoryDialog, { path: dialog.path, onClose: closeDialog }),
|
|
1162
|
+
dialog.kind === "diff" && /* @__PURE__ */ jsx11(GitDiffDialog, { path: dialog.path, revision: dialog.revision, onClose: closeDialog }),
|
|
1163
|
+
dialog.kind === "clone" && /* @__PURE__ */ jsx11(
|
|
1111
1164
|
GitCloneDialog,
|
|
1112
1165
|
{
|
|
1113
1166
|
onClose: closeDialog,
|
|
@@ -1117,7 +1170,7 @@ function GitUI({ onOpenFile, onWorkspaceCloned }) {
|
|
|
1117
1170
|
}
|
|
1118
1171
|
}
|
|
1119
1172
|
),
|
|
1120
|
-
dialog.kind === "auth-guidance" && /* @__PURE__ */
|
|
1173
|
+
dialog.kind === "auth-guidance" && /* @__PURE__ */ jsx11(
|
|
1121
1174
|
GitAuthGuidanceDialog,
|
|
1122
1175
|
{
|
|
1123
1176
|
operation: dialog.operation,
|
|
@@ -1125,7 +1178,8 @@ function GitUI({ onOpenFile, onWorkspaceCloned }) {
|
|
|
1125
1178
|
onClose: closeDialog
|
|
1126
1179
|
}
|
|
1127
1180
|
),
|
|
1128
|
-
dialog.kind === "
|
|
1181
|
+
dialog.kind === "expanded-grant" && /* @__PURE__ */ jsx11(GitExpandedGrantDialog, { onClose: closeDialog }),
|
|
1182
|
+
dialog.kind === "conflicts" && /* @__PURE__ */ jsx11(GitConflictsDialog, { paths: dialog.paths, onOpenFile, onClose: closeDialog })
|
|
1129
1183
|
] });
|
|
1130
1184
|
}
|
|
1131
1185
|
export {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
SHARED_DOCUMENT_LIMITS,
|
|
8
8
|
createSharedDocumentUrl
|
|
9
9
|
} from "@bendyline/docblocks/share";
|
|
10
|
-
var PUBLIC_DOCBLOCKS_SHARE_URL = "https://
|
|
10
|
+
var PUBLIC_DOCBLOCKS_SHARE_URL = "https://docblocks.com/";
|
|
11
11
|
function resolveSharedDocumentBaseUrl(currentUrl) {
|
|
12
12
|
try {
|
|
13
13
|
const current = new URL(currentUrl);
|
|
@@ -45,6 +45,45 @@ async function createSharedDocumentArchive(markdown, selectedFile) {
|
|
|
45
45
|
function buildSharedDocumentUrl(baseUrl, archive, mode) {
|
|
46
46
|
return createSharedDocumentUrl(resolveSharedDocumentBaseUrl(baseUrl), archive, mode);
|
|
47
47
|
}
|
|
48
|
+
function buildSharedDocumentQrUrl(archive, mode) {
|
|
49
|
+
const url = createSharedDocumentUrl(PUBLIC_DOCBLOCKS_SHARE_URL, archive, mode);
|
|
50
|
+
if (url.length > SHARED_DOCUMENT_LIMITS.qrUrlCharacters) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
"This document is too large for a reliable QR code (maximum " + SHARED_DOCUMENT_LIMITS.qrUrlCharacters.toLocaleString() + " URL characters). Copy the share link instead."
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return url;
|
|
56
|
+
}
|
|
57
|
+
function sharedDocumentQrFilename(selectedFile) {
|
|
58
|
+
return sharedDocumentFilename(selectedFile).replace(/\.md$/iu, "-qr.png");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/Export/share-qr.ts
|
|
62
|
+
import QRCode from "qrcode";
|
|
63
|
+
async function renderSharedDocumentQrPng(url) {
|
|
64
|
+
return QRCode.toDataURL(url, {
|
|
65
|
+
type: "image/png",
|
|
66
|
+
errorCorrectionLevel: "M",
|
|
67
|
+
margin: 4,
|
|
68
|
+
width: 1024,
|
|
69
|
+
color: {
|
|
70
|
+
dark: "#111111ff",
|
|
71
|
+
light: "#ffffffff"
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function qrPngDataUrlToBlob(dataUrl) {
|
|
76
|
+
const prefix = "data:image/png;base64,";
|
|
77
|
+
if (!dataUrl.startsWith(prefix)) {
|
|
78
|
+
throw new Error("The QR code renderer returned an unsupported image format.");
|
|
79
|
+
}
|
|
80
|
+
const binary = atob(dataUrl.slice(prefix.length));
|
|
81
|
+
const bytes = new Uint8Array(binary.length);
|
|
82
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
83
|
+
bytes[index] = binary.charCodeAt(index);
|
|
84
|
+
}
|
|
85
|
+
return new Blob([bytes], { type: "image/png" });
|
|
86
|
+
}
|
|
48
87
|
|
|
49
88
|
// src/Export/ShareDialog.tsx
|
|
50
89
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -56,11 +95,19 @@ var MODES = [
|
|
|
56
95
|
{ value: "document", label: "Document" },
|
|
57
96
|
{ value: "narrate", label: "Narrate" }
|
|
58
97
|
];
|
|
59
|
-
function ShareDialog({
|
|
98
|
+
function ShareDialog({
|
|
99
|
+
markdown,
|
|
100
|
+
selectedFile,
|
|
101
|
+
baseUrl,
|
|
102
|
+
onClose
|
|
103
|
+
}) {
|
|
60
104
|
const [mode, setMode] = useState("");
|
|
61
105
|
const [archive, setArchive] = useState(null);
|
|
62
106
|
const [archiveError, setArchiveError] = useState(null);
|
|
63
107
|
const [copyStatus, setCopyStatus] = useState("idle");
|
|
108
|
+
const [qrDataUrl, setQrDataUrl] = useState(null);
|
|
109
|
+
const [qrRenderError, setQrRenderError] = useState(null);
|
|
110
|
+
const [qrCopyStatus, setQrCopyStatus] = useState("idle");
|
|
64
111
|
const linkRef = useRef(null);
|
|
65
112
|
useEffect(() => {
|
|
66
113
|
let cancelled = false;
|
|
@@ -90,6 +137,36 @@ function ShareDialog({ markdown, selectedFile, baseUrl, onClose }) {
|
|
|
90
137
|
};
|
|
91
138
|
}
|
|
92
139
|
}, [archive, archiveError, baseUrl, mode]);
|
|
140
|
+
const qrLinkResult = useMemo(() => {
|
|
141
|
+
if (!archive) return { url: "", error: archiveError };
|
|
142
|
+
try {
|
|
143
|
+
return { url: buildSharedDocumentQrUrl(archive, mode || null), error: null };
|
|
144
|
+
} catch (error) {
|
|
145
|
+
return {
|
|
146
|
+
url: "",
|
|
147
|
+
error: error instanceof Error ? error.message : "DocBlocks could not create the QR code."
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}, [archive, archiveError, mode]);
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
let cancelled = false;
|
|
153
|
+
setQrDataUrl(null);
|
|
154
|
+
setQrRenderError(null);
|
|
155
|
+
setQrCopyStatus("idle");
|
|
156
|
+
if (!qrLinkResult.url) return;
|
|
157
|
+
void renderSharedDocumentQrPng(qrLinkResult.url).then((dataUrl) => {
|
|
158
|
+
if (!cancelled) setQrDataUrl(dataUrl);
|
|
159
|
+
}).catch((error) => {
|
|
160
|
+
if (!cancelled) {
|
|
161
|
+
setQrRenderError(
|
|
162
|
+
error instanceof Error ? error.message : "DocBlocks could not render the QR code."
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
return () => {
|
|
167
|
+
cancelled = true;
|
|
168
|
+
};
|
|
169
|
+
}, [qrLinkResult.url]);
|
|
93
170
|
useEffect(() => setCopyStatus("idle"), [linkResult.url]);
|
|
94
171
|
useEffect(() => {
|
|
95
172
|
const handleKeyDown = (event) => {
|
|
@@ -117,7 +194,31 @@ function ShareDialog({ markdown, selectedFile, baseUrl, onClose }) {
|
|
|
117
194
|
setCopyStatus("failed");
|
|
118
195
|
}
|
|
119
196
|
}, [linkResult.url]);
|
|
197
|
+
const copyQrImage = useCallback(async () => {
|
|
198
|
+
if (!qrDataUrl) return;
|
|
199
|
+
try {
|
|
200
|
+
if (!navigator.clipboard?.write || typeof ClipboardItem === "undefined") {
|
|
201
|
+
throw new Error("Image clipboard access is unavailable.");
|
|
202
|
+
}
|
|
203
|
+
const png = qrPngDataUrlToBlob(qrDataUrl);
|
|
204
|
+
await navigator.clipboard.write([new ClipboardItem({ "image/png": png })]);
|
|
205
|
+
setQrCopyStatus("copied");
|
|
206
|
+
} catch {
|
|
207
|
+
setQrCopyStatus("failed");
|
|
208
|
+
}
|
|
209
|
+
}, [qrDataUrl]);
|
|
210
|
+
const saveQrImage = useCallback(() => {
|
|
211
|
+
if (!qrDataUrl) return;
|
|
212
|
+
const download = document.createElement("a");
|
|
213
|
+
download.href = qrDataUrl;
|
|
214
|
+
download.download = sharedDocumentQrFilename(selectedFile);
|
|
215
|
+
download.style.display = "none";
|
|
216
|
+
document.body.append(download);
|
|
217
|
+
download.click();
|
|
218
|
+
download.remove();
|
|
219
|
+
}, [qrDataUrl, selectedFile]);
|
|
120
220
|
const isLong = linkResult.url.length > SHARED_DOCUMENT_LIMITS2.portableUrlCharacters;
|
|
221
|
+
const qrError = qrLinkResult.error ?? qrRenderError;
|
|
121
222
|
return /* @__PURE__ */ jsx(
|
|
122
223
|
"div",
|
|
123
224
|
{
|
|
@@ -134,7 +235,7 @@ function ShareDialog({ markdown, selectedFile, baseUrl, onClose }) {
|
|
|
134
235
|
"aria-labelledby": "db-share-dialog-title",
|
|
135
236
|
children: [
|
|
136
237
|
/* @__PURE__ */ jsxs("div", { className: "db-dialog-header", children: [
|
|
137
|
-
/* @__PURE__ */ jsx("h2", { className: "db-dialog-title", id: "db-share-dialog-title", children: "Share document
|
|
238
|
+
/* @__PURE__ */ jsx("h2", { className: "db-dialog-title", id: "db-share-dialog-title", children: "Share document" }),
|
|
138
239
|
/* @__PURE__ */ jsx("button", { className: "db-dialog-close", type: "button", onClick: onClose, "aria-label": "Close", children: "\xD7" })
|
|
139
240
|
] }),
|
|
140
241
|
/* @__PURE__ */ jsxs("div", { className: "db-dialog-body", children: [
|
|
@@ -178,6 +279,52 @@ function ShareDialog({ markdown, selectedFile, baseUrl, onClose }) {
|
|
|
178
279
|
}
|
|
179
280
|
)
|
|
180
281
|
] }),
|
|
282
|
+
/* @__PURE__ */ jsxs("section", { className: "db-share-qr", "aria-labelledby": "db-share-qr-title", children: [
|
|
283
|
+
/* @__PURE__ */ jsxs("div", { className: "db-share-qr-heading", children: [
|
|
284
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
285
|
+
/* @__PURE__ */ jsx("h3", { id: "db-share-qr-title", children: "QR code" }),
|
|
286
|
+
/* @__PURE__ */ jsx("span", { className: "db-export-hint", children: "A self-contained docblocks.com link. No document content is uploaded." })
|
|
287
|
+
] }),
|
|
288
|
+
/* @__PURE__ */ jsxs("div", { className: "db-share-qr-actions", children: [
|
|
289
|
+
/* @__PURE__ */ jsx(
|
|
290
|
+
"button",
|
|
291
|
+
{
|
|
292
|
+
className: "db-export-btn db-export-btn--secondary",
|
|
293
|
+
type: "button",
|
|
294
|
+
onClick: () => void copyQrImage(),
|
|
295
|
+
disabled: !qrDataUrl,
|
|
296
|
+
children: qrCopyStatus === "copied" ? "Copied QR" : qrCopyStatus === "failed" ? "Copy unavailable" : "Copy QR image"
|
|
297
|
+
}
|
|
298
|
+
),
|
|
299
|
+
/* @__PURE__ */ jsx(
|
|
300
|
+
"button",
|
|
301
|
+
{
|
|
302
|
+
className: "db-export-btn db-export-btn--secondary",
|
|
303
|
+
type: "button",
|
|
304
|
+
onClick: saveQrImage,
|
|
305
|
+
disabled: !qrDataUrl,
|
|
306
|
+
children: "Save QR PNG"
|
|
307
|
+
}
|
|
308
|
+
)
|
|
309
|
+
] })
|
|
310
|
+
] }),
|
|
311
|
+
qrDataUrl ? /* @__PURE__ */ jsx(
|
|
312
|
+
"img",
|
|
313
|
+
{
|
|
314
|
+
className: "db-share-qr-image",
|
|
315
|
+
src: qrDataUrl,
|
|
316
|
+
alt: "QR code for this shared DocBlocks document"
|
|
317
|
+
}
|
|
318
|
+
) : /* @__PURE__ */ jsx(
|
|
319
|
+
"div",
|
|
320
|
+
{
|
|
321
|
+
className: `db-share-qr-placeholder${qrError ? " db-share-qr-placeholder--error" : ""}`,
|
|
322
|
+
role: qrError ? "note" : "status",
|
|
323
|
+
children: qrError ?? "Rendering QR code..."
|
|
324
|
+
}
|
|
325
|
+
),
|
|
326
|
+
/* @__PURE__ */ jsx("span", { className: "db-export-hint db-share-qr-status", "aria-live": "polite", children: qrCopyStatus === "failed" ? "This browser could not copy the PNG. Save it instead." : qrDataUrl ? `${qrLinkResult.url.length.toLocaleString()} of ${SHARED_DOCUMENT_LIMITS2.qrUrlCharacters.toLocaleString()} supported QR characters.` : "" })
|
|
327
|
+
] }),
|
|
181
328
|
/* @__PURE__ */ jsx("p", { className: "db-share-temporary-note", children: "Opening the link creates a temporary workspace. Changes there do not alter this document or the link." })
|
|
182
329
|
] }),
|
|
183
330
|
/* @__PURE__ */ jsxs("div", { className: "db-export-footer", children: [
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { CalcEngineFactory } from '@bendyline/squisq-editor-react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Host wiring for Squisq's optional IronCalc spreadsheet engine.
|
|
5
|
+
*
|
|
6
|
+
* Creating the factory imports no engine code and downloads no bytes. Squisq
|
|
7
|
+
* calls it only when a formula session opens, at which point the IronCalc
|
|
8
|
+
* adapter and the surface's same-origin WASM asset load asynchronously. If the
|
|
9
|
+
* factory rejects, Squisq falls back to its in-house calculation tier.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
interface DocBlocksCalculationOptions {
|
|
13
|
+
/**
|
|
14
|
+
* `@ironcalc/wasm` binary source. Browser hosts normally pass the stable
|
|
15
|
+
* same-origin URL they publish; tests and non-browser hosts may pass bytes
|
|
16
|
+
* or a compiled module instead.
|
|
17
|
+
*/
|
|
18
|
+
wasmSource: string | URL | Response | BufferSource | WebAssembly.Module;
|
|
19
|
+
/** IronCalc workbook locale. Defaults to `en`. */
|
|
20
|
+
locale?: string;
|
|
21
|
+
/** IronCalc workbook timezone. Defaults to `UTC`. */
|
|
22
|
+
timezone?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Create the lazy IronCalc factory a DocBlocks surface passes to its shell. */
|
|
25
|
+
declare function createDocBlocksCalcEngineFactory(options: DocBlocksCalculationOptions): CalcEngineFactory;
|
|
26
|
+
|
|
27
|
+
export { type DocBlocksCalculationOptions, createDocBlocksCalcEngineFactory };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/Calculation/public-api.ts
|
|
2
|
+
function createDocBlocksCalcEngineFactory(options) {
|
|
3
|
+
const { wasmSource, locale, timezone } = options;
|
|
4
|
+
return async (config) => {
|
|
5
|
+
const { createIronCalcEngine } = await import("@bendyline/squisq-calc/ironcalc");
|
|
6
|
+
return createIronCalcEngine({
|
|
7
|
+
...config,
|
|
8
|
+
wasmSource,
|
|
9
|
+
locale,
|
|
10
|
+
timezone
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
createDocBlocksCalcEngineFactory
|
|
16
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// src/Proofing/proofing-ignores.ts
|
|
2
|
+
var STORAGE_KEY = "docblocks:proofingIgnores";
|
|
3
|
+
var MAX_ENTRY_CHARACTERS = 64 * 1024;
|
|
4
|
+
var MAX_DOCUMENTS = 200;
|
|
5
|
+
function resolveStorage() {
|
|
6
|
+
try {
|
|
7
|
+
const candidate = Reflect.get(globalThis, "localStorage");
|
|
8
|
+
if (typeof candidate !== "object" || candidate === null || typeof Reflect.get(candidate, "getItem") !== "function" || typeof Reflect.get(candidate, "setItem") !== "function") {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return candidate;
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function proofingIgnoreKey(workspaceId, documentPath) {
|
|
17
|
+
return `${workspaceId}\0${documentPath}`;
|
|
18
|
+
}
|
|
19
|
+
function readAll(storage) {
|
|
20
|
+
try {
|
|
21
|
+
const raw = storage.getItem(STORAGE_KEY);
|
|
22
|
+
if (!raw) return {};
|
|
23
|
+
const parsed = JSON.parse(raw);
|
|
24
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
|
|
25
|
+
const entries = {};
|
|
26
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
27
|
+
if (typeof value !== "object" || value === null) continue;
|
|
28
|
+
const json = Reflect.get(value, "json");
|
|
29
|
+
const savedAt = Reflect.get(value, "savedAt");
|
|
30
|
+
if (typeof json !== "string" || json.length > MAX_ENTRY_CHARACTERS) continue;
|
|
31
|
+
entries[key] = { json, savedAt: typeof savedAt === "number" ? savedAt : 0 };
|
|
32
|
+
}
|
|
33
|
+
return entries;
|
|
34
|
+
} catch {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function writeAll(storage, entries) {
|
|
39
|
+
const keys = Object.keys(entries);
|
|
40
|
+
if (keys.length > MAX_DOCUMENTS) {
|
|
41
|
+
const ordered = keys.sort((a, b) => (entries[a]?.savedAt ?? 0) - (entries[b]?.savedAt ?? 0));
|
|
42
|
+
for (const key of ordered.slice(0, keys.length - MAX_DOCUMENTS)) delete entries[key];
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
storage.setItem(STORAGE_KEY, JSON.stringify(entries));
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function createLocalProofingIgnoreStore(resolveWorkspaceId, storageOverride) {
|
|
50
|
+
const storage = storageOverride ?? resolveStorage();
|
|
51
|
+
const keyFor = (document) => {
|
|
52
|
+
const workspaceId = resolveWorkspaceId();
|
|
53
|
+
if (!workspaceId) return null;
|
|
54
|
+
const documentPath = document.fileName ?? document.articleId;
|
|
55
|
+
if (!documentPath) return null;
|
|
56
|
+
return proofingIgnoreKey(workspaceId, documentPath);
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
load(document) {
|
|
60
|
+
if (!storage) return void 0;
|
|
61
|
+
const key = keyFor(document);
|
|
62
|
+
if (!key) return void 0;
|
|
63
|
+
return readAll(storage)[key]?.json;
|
|
64
|
+
},
|
|
65
|
+
save(document, ignoredJson) {
|
|
66
|
+
if (!storage) return;
|
|
67
|
+
const key = keyFor(document);
|
|
68
|
+
if (!key) return;
|
|
69
|
+
const entries = readAll(storage);
|
|
70
|
+
if (ignoredJson.length > MAX_ENTRY_CHARACTERS) {
|
|
71
|
+
delete entries[key];
|
|
72
|
+
} else {
|
|
73
|
+
entries[key] = { json: ignoredJson, savedAt: Date.now() };
|
|
74
|
+
}
|
|
75
|
+
writeAll(storage, entries);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export {
|
|
81
|
+
proofingIgnoreKey,
|
|
82
|
+
createLocalProofingIgnoreStore
|
|
83
|
+
};
|
|
@@ -283,6 +283,35 @@ function AccentColorSettings({
|
|
|
283
283
|
)) })
|
|
284
284
|
] });
|
|
285
285
|
}
|
|
286
|
+
function ProofingSettingsControls({ value, onChange }) {
|
|
287
|
+
return /* @__PURE__ */ jsxs("fieldset", { className: "db-settings-fieldset", children: [
|
|
288
|
+
/* @__PURE__ */ jsx("legend", { className: "db-settings-legend", children: "Spelling and grammar" }),
|
|
289
|
+
/* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: "Checking runs on this device \u2014 nothing you write is sent anywhere." }),
|
|
290
|
+
/* @__PURE__ */ jsxs("label", { className: "db-settings-checkbox", children: [
|
|
291
|
+
/* @__PURE__ */ jsx(
|
|
292
|
+
"input",
|
|
293
|
+
{
|
|
294
|
+
type: "checkbox",
|
|
295
|
+
checked: value.spelling,
|
|
296
|
+
onChange: (event) => onChange({ ...value, spelling: event.currentTarget.checked })
|
|
297
|
+
}
|
|
298
|
+
),
|
|
299
|
+
"Show inline spell checking"
|
|
300
|
+
] }),
|
|
301
|
+
/* @__PURE__ */ jsxs("label", { className: "db-settings-checkbox", children: [
|
|
302
|
+
/* @__PURE__ */ jsx(
|
|
303
|
+
"input",
|
|
304
|
+
{
|
|
305
|
+
type: "checkbox",
|
|
306
|
+
checked: value.grammar,
|
|
307
|
+
onChange: (event) => onChange({ ...value, grammar: event.currentTarget.checked })
|
|
308
|
+
}
|
|
309
|
+
),
|
|
310
|
+
"Show inline grammar checking"
|
|
311
|
+
] }),
|
|
312
|
+
/* @__PURE__ */ jsx("p", { className: "db-settings-hint", children: "(Grammar checking is currently only available for English)" })
|
|
313
|
+
] });
|
|
314
|
+
}
|
|
286
315
|
function WriteCanvasSettingsControls({ value, onChange }) {
|
|
287
316
|
return /* @__PURE__ */ jsxs("fieldset", { className: "db-settings-fieldset", children: [
|
|
288
317
|
/* @__PURE__ */ jsx("legend", { className: "db-settings-legend", children: "Write canvas" }),
|
|
@@ -587,6 +616,36 @@ function formatLineSpacing(value) {
|
|
|
587
616
|
return `${value.toFixed(1).replace(/\.0$/, "")}\xD7`;
|
|
588
617
|
}
|
|
589
618
|
|
|
619
|
+
// src/preferences/proofing.ts
|
|
620
|
+
var DEFAULT_PROOFING_PREFERENCES = {
|
|
621
|
+
spelling: true,
|
|
622
|
+
grammar: true
|
|
623
|
+
};
|
|
624
|
+
var STORAGE_KEY = "docblocks:proofingPreferences";
|
|
625
|
+
function loadProofingPreferences() {
|
|
626
|
+
try {
|
|
627
|
+
const raw = localStorage.getItem(STORAGE_KEY);
|
|
628
|
+
if (!raw) return { ...DEFAULT_PROOFING_PREFERENCES };
|
|
629
|
+
const stored = JSON.parse(raw);
|
|
630
|
+
if (typeof stored !== "object" || stored === null) {
|
|
631
|
+
return { ...DEFAULT_PROOFING_PREFERENCES };
|
|
632
|
+
}
|
|
633
|
+
const record = stored;
|
|
634
|
+
return {
|
|
635
|
+
spelling: typeof record.spelling === "boolean" ? record.spelling : DEFAULT_PROOFING_PREFERENCES.spelling,
|
|
636
|
+
grammar: typeof record.grammar === "boolean" ? record.grammar : DEFAULT_PROOFING_PREFERENCES.grammar
|
|
637
|
+
};
|
|
638
|
+
} catch {
|
|
639
|
+
}
|
|
640
|
+
return { ...DEFAULT_PROOFING_PREFERENCES };
|
|
641
|
+
}
|
|
642
|
+
function saveProofingPreferences(value) {
|
|
643
|
+
try {
|
|
644
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
|
|
645
|
+
} catch {
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
590
649
|
export {
|
|
591
650
|
WRITE_CANVAS_FONT_SCHEMES,
|
|
592
651
|
DEFAULT_WRITE_CANVAS_FONT_SCHEME,
|
|
@@ -594,6 +653,9 @@ export {
|
|
|
594
653
|
DEFAULT_WRITE_CANVAS_PREFERENCES,
|
|
595
654
|
loadWriteCanvasPreferences,
|
|
596
655
|
saveWriteCanvasPreferences,
|
|
656
|
+
DEFAULT_PROOFING_PREFERENCES,
|
|
657
|
+
loadProofingPreferences,
|
|
658
|
+
saveProofingPreferences,
|
|
597
659
|
DB_CHROME_COLORS,
|
|
598
660
|
loadThemePreference,
|
|
599
661
|
saveThemePreference,
|
|
@@ -602,5 +664,6 @@ export {
|
|
|
602
664
|
SettingsDialog,
|
|
603
665
|
ThemeSettings,
|
|
604
666
|
AccentColorSettings,
|
|
667
|
+
ProofingSettingsControls,
|
|
605
668
|
WriteCanvasSettingsControls
|
|
606
669
|
};
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
// src/Git/GitContext.tsx
|
|
2
|
-
import { createContext, useContext } from "react";
|
|
3
|
-
var GitContext = createContext(null);
|
|
4
|
-
function useGitContext() {
|
|
5
|
-
return useContext(GitContext);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
1
|
// src/Git/git-status.ts
|
|
9
2
|
var BADGE_GLYPHS = {
|
|
10
3
|
modified: "M",
|
|
@@ -83,8 +76,6 @@ function summarizeDirty(status) {
|
|
|
83
76
|
}
|
|
84
77
|
|
|
85
78
|
export {
|
|
86
|
-
GitContext,
|
|
87
|
-
useGitContext,
|
|
88
79
|
BADGE_GLYPHS,
|
|
89
80
|
BADGE_LABELS,
|
|
90
81
|
badgeKindFor,
|