@bendyline/docblocks-react 2.6.2 → 2.7.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 +3 -10
- package/THIRD_PARTY_NOTICES.txt +4284 -3651
- package/dist/AiDiagrams-XWOM3YZX.js +13 -0
- package/dist/AiEditorAssistant-M4LI2CRY.js +771 -0
- package/dist/AudioExportDialog-F23QXNPB.js +253 -0
- package/dist/DocumentConflictDialog-5LRVIGXS.js +111 -0
- package/dist/ExportDialog-L6FG6W3H.js +9 -0
- package/dist/{ExportToolbarControls-QYLBRWM7.js → ExportToolbarControls-BRCPZ7H3.js} +108 -42
- package/dist/{GitUI-L5T3XHZG.js → GitUI-LZW3IUXO.js} +5 -5
- package/dist/PresentationMaker-622NHMIN.js +9 -0
- package/dist/QuickOpenDialog-2KK4SEBU.js +356 -0
- package/dist/Settings-DuXk6baH.d.ts +144 -0
- package/dist/{ShareDialog-4OX3UPJ4.js → ShareDialog-N7GPM4SB.js} +10 -59
- package/dist/SpeechToolbarControl-UZQKGQWD.js +434 -0
- package/dist/TextFromNarration-XYRAB6O2.js +598 -0
- package/dist/WorkspaceSearchPanel-OUQQ5DOM.js +328 -0
- package/dist/chunk-2IYBBFQX.js +201 -0
- package/dist/{chunk-LG6HAWCK.js → chunk-56KO2LYN.js} +35 -4
- package/dist/chunk-5OZBGIIT.js +1826 -0
- package/dist/chunk-6B7G33D5.js +88 -0
- package/dist/chunk-ARATARVJ.js +40 -0
- package/dist/{chunk-ODYNOPC3.js → chunk-BCQZTWE5.js} +57 -17
- package/dist/chunk-EA4BO6E4.js +73 -0
- package/dist/chunk-G4MFB3IO.js +208 -0
- package/dist/chunk-I44HKDQX.js +314 -0
- package/dist/chunk-K4I3NJFL.js +49 -0
- package/dist/chunk-KBDZDFPU.js +61 -0
- package/dist/{chunk-FNSRCCBC.js → chunk-KWG6UP5O.js} +0 -10
- package/dist/chunk-MMOTEQK6.js +518 -0
- package/dist/chunk-OINKNX26.js +574 -0
- package/dist/chunk-Q5ZVP5LV.js +1711 -0
- package/dist/chunk-RP3DVNTI.js +62 -0
- package/dist/{chunk-FMDLZ4ZG.js → chunk-SGQKTKDX.js} +2 -2
- package/dist/chunk-TBLZBNQF.js +25 -0
- package/dist/{chunk-M5Y5WO7Z.js → chunk-UG4G7PJ4.js} +1 -1
- package/dist/chunk-UONFWKJ7.js +22 -0
- package/dist/chunk-VO2JYYQZ.js +40 -0
- package/dist/{chunk-EBWYGTN7.js → chunk-X437UAF7.js} +6 -0
- package/dist/chunk-YS4HVWIO.js +63 -0
- package/dist/editor.d.ts +36 -1
- package/dist/editor.js +16 -1
- package/dist/export/index.d.ts +27 -11
- package/dist/export/index.js +11 -7
- package/dist/index.d.ts +100 -13
- package/dist/index.js +3916 -1633
- package/dist/{run-export-I2XOVGG4.js → run-export-47X5FTYZ.js} +3 -3
- package/dist/settings/index.d.ts +32 -101
- package/dist/settings/index.js +14 -2
- package/package.json +9 -9
- package/src/styles/docblocks.css +2332 -656
- package/dist/ExportDialog-Q4VWI43H.js +0 -9
- package/dist/chunk-JDJVRDOP.js +0 -92
- package/dist/chunk-Q6XNIKDG.js +0 -669
- package/dist/{GitToolbarControl-O5AXBC6T.js → GitToolbarControl-J4UYZDV6.js} +3 -3
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Dialog
|
|
3
|
+
} from "./chunk-56KO2LYN.js";
|
|
4
|
+
|
|
5
|
+
// src/components/useConfirmDialog.ts
|
|
6
|
+
import React2, { useCallback as useCallback2, useEffect, useRef as useRef2, useState } from "react";
|
|
7
|
+
|
|
8
|
+
// src/components/ConfirmDialog.tsx
|
|
9
|
+
import { useCallback, useRef } from "react";
|
|
10
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
function ConfirmDialog({ request, onSettle }) {
|
|
12
|
+
const acknowledge = request.kind === "acknowledge";
|
|
13
|
+
const destructive = request.kind === "confirm" && request.destructive === true;
|
|
14
|
+
const cancelRef = useRef(null);
|
|
15
|
+
const confirmRef = useRef(null);
|
|
16
|
+
const accept = useCallback(() => onSettle(true), [onSettle]);
|
|
17
|
+
const reject = useCallback(() => onSettle(false), [onSettle]);
|
|
18
|
+
const close = acknowledge ? accept : reject;
|
|
19
|
+
return /* @__PURE__ */ jsx(
|
|
20
|
+
Dialog,
|
|
21
|
+
{
|
|
22
|
+
title: request.title,
|
|
23
|
+
onClose: close,
|
|
24
|
+
initialFocusRef: destructive ? cancelRef : confirmRef,
|
|
25
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
26
|
+
!acknowledge && /* @__PURE__ */ jsx("button", { ref: cancelRef, type: "button", className: "db-git-secondary-btn", onClick: reject, children: request.cancelLabel ?? "Cancel" }),
|
|
27
|
+
/* @__PURE__ */ jsx(
|
|
28
|
+
"button",
|
|
29
|
+
{
|
|
30
|
+
ref: confirmRef,
|
|
31
|
+
type: "button",
|
|
32
|
+
className: destructive ? "db-git-primary-btn db-git-primary-btn--danger" : "db-git-primary-btn",
|
|
33
|
+
onClick: accept,
|
|
34
|
+
children: request.confirmLabel ?? "OK"
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
] }),
|
|
38
|
+
children: /* @__PURE__ */ jsx("p", { className: "db-dialog-message", children: request.message })
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/components/useConfirmDialog.ts
|
|
44
|
+
function useConfirmDialog() {
|
|
45
|
+
const [pending, setPending] = useState(null);
|
|
46
|
+
const pendingRef = useRef2(null);
|
|
47
|
+
const nextIdRef = useRef2(0);
|
|
48
|
+
const settlePending = useCallback2((value) => {
|
|
49
|
+
const current = pendingRef.current;
|
|
50
|
+
if (!current) return;
|
|
51
|
+
pendingRef.current = null;
|
|
52
|
+
setPending((open2) => open2?.id === current.id ? null : open2);
|
|
53
|
+
current.settle(value);
|
|
54
|
+
}, []);
|
|
55
|
+
const open = useCallback2(
|
|
56
|
+
(request) => new Promise((resolve) => {
|
|
57
|
+
settlePending(false);
|
|
58
|
+
const next = { id: ++nextIdRef.current, request, settle: resolve };
|
|
59
|
+
pendingRef.current = next;
|
|
60
|
+
setPending(next);
|
|
61
|
+
}),
|
|
62
|
+
[settlePending]
|
|
63
|
+
);
|
|
64
|
+
const confirm = useCallback2(
|
|
65
|
+
(request) => open({ kind: "confirm", ...request }),
|
|
66
|
+
[open]
|
|
67
|
+
);
|
|
68
|
+
const acknowledge = useCallback2(
|
|
69
|
+
async (request) => {
|
|
70
|
+
await open({ kind: "acknowledge", ...request });
|
|
71
|
+
},
|
|
72
|
+
[open]
|
|
73
|
+
);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
return () => settlePending(false);
|
|
76
|
+
}, [settlePending]);
|
|
77
|
+
const confirmDialog = pending ? React2.createElement(ConfirmDialog, {
|
|
78
|
+
// Remount on a superseding request so focus re-seeds from it.
|
|
79
|
+
key: pending.id,
|
|
80
|
+
request: pending.request,
|
|
81
|
+
onSettle: settlePending
|
|
82
|
+
}) : null;
|
|
83
|
+
return { confirm, acknowledge, confirmDialog };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
useConfirmDialog
|
|
88
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// src/FileExplorer/file-names.ts
|
|
2
|
+
var HIDDEN_EXTENSION = ".md";
|
|
3
|
+
var EXTENSION = /\.(?=[A-Za-z0-9]*[A-Za-z])[A-Za-z0-9]{1,10}$/;
|
|
4
|
+
function hidesExtension(name) {
|
|
5
|
+
return name.endsWith(HIDDEN_EXTENSION) && name.length > HIDDEN_EXTENSION.length;
|
|
6
|
+
}
|
|
7
|
+
function extensionStart(name) {
|
|
8
|
+
const match = EXTENSION.exec(name);
|
|
9
|
+
return match && match.index > 0 ? match.index : -1;
|
|
10
|
+
}
|
|
11
|
+
function displayFileName(name) {
|
|
12
|
+
return hidesExtension(name) ? name.slice(0, -HIDDEN_EXTENSION.length) : name;
|
|
13
|
+
}
|
|
14
|
+
function renameDraft(name, kind) {
|
|
15
|
+
if (kind === "file" && hidesExtension(name)) {
|
|
16
|
+
const value = displayFileName(name);
|
|
17
|
+
return { value, selectionEnd: value.length };
|
|
18
|
+
}
|
|
19
|
+
const start = kind === "file" ? extensionStart(name) : -1;
|
|
20
|
+
return { value: name, selectionEnd: start >= 0 ? start : name.length };
|
|
21
|
+
}
|
|
22
|
+
function renamedFileName(name, typed, kind) {
|
|
23
|
+
let next = typed.trim();
|
|
24
|
+
if (!next) return null;
|
|
25
|
+
if (kind === "file") {
|
|
26
|
+
if (hidesExtension(name)) {
|
|
27
|
+
if (!next.toLowerCase().endsWith(HIDDEN_EXTENSION)) next += HIDDEN_EXTENSION;
|
|
28
|
+
} else {
|
|
29
|
+
const start = extensionStart(name);
|
|
30
|
+
if (start >= 0 && extensionStart(next) < 0) next += name.slice(start);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return next === name ? null : next;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
displayFileName,
|
|
38
|
+
renameDraft,
|
|
39
|
+
renamedFileName
|
|
40
|
+
};
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FORMAT_EXTENSIONS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-X437UAF7.js";
|
|
4
4
|
|
|
5
5
|
// src/Export/run-export.ts
|
|
6
6
|
import { parseMarkdown } from "@bendyline/squisq/markdown";
|
|
7
|
+
async function pictureDiagrams(doc, overrides, kinds) {
|
|
8
|
+
try {
|
|
9
|
+
const [{ rasterizeDiagrams }, render] = await Promise.all([
|
|
10
|
+
import("@bendyline/squisq-formats/diagrams"),
|
|
11
|
+
overrides.diagramRenderer ?? import("@bendyline/squisq-react/diagram-pictures").then(
|
|
12
|
+
(module) => module.createDiagramPictureRenderer()
|
|
13
|
+
)
|
|
14
|
+
]);
|
|
15
|
+
return await rasterizeDiagrams(doc, render, { kinds, urlPrefix: "docblocks-diagram" });
|
|
16
|
+
} catch {
|
|
17
|
+
return { markdownDoc: doc, images: /* @__PURE__ */ new Map(), mermaid: /* @__PURE__ */ new Map() };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
7
20
|
var MIME_TYPES = {
|
|
8
21
|
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
9
22
|
pdf: "application/pdf",
|
|
@@ -45,24 +58,40 @@ async function runExport(markdown, selectedFile, options, mediaContainer, saveBl
|
|
|
45
58
|
const doc = parseMarkdown(markdown);
|
|
46
59
|
if (options.format === "docx") {
|
|
47
60
|
const { markdownDocToDocx } = await import("@bendyline/squisq-formats/docx");
|
|
48
|
-
const
|
|
49
|
-
const
|
|
61
|
+
const pictured = await pictureDiagrams(doc, converterOverrides);
|
|
62
|
+
const images = new Map([
|
|
63
|
+
...mediaContainer ? await resolveImages(doc, mediaContainer) : [],
|
|
64
|
+
...pictured.images
|
|
65
|
+
]);
|
|
66
|
+
const buf = await markdownDocToDocx(pictured.markdownDoc, { themeId, images });
|
|
50
67
|
await saveExportBlob(new Blob([buf], { type: MIME_TYPES.docx }), filename, saveBlob);
|
|
51
68
|
return;
|
|
52
69
|
}
|
|
53
70
|
if (options.format === "pdf") {
|
|
54
71
|
const { markdownDocToPdf } = await import("@bendyline/squisq-formats/pdf");
|
|
55
|
-
const
|
|
72
|
+
const pictured = await pictureDiagrams(doc, converterOverrides);
|
|
73
|
+
const images = new Map([
|
|
74
|
+
...mediaContainer ? await resolveImages(doc, mediaContainer) : [],
|
|
75
|
+
...pictured.images
|
|
76
|
+
]);
|
|
77
|
+
const buf = await markdownDocToPdf(pictured.markdownDoc, {
|
|
56
78
|
themeId,
|
|
57
|
-
pageSize: options.pageSize
|
|
79
|
+
pageSize: options.pageSize,
|
|
80
|
+
images
|
|
58
81
|
});
|
|
59
82
|
await saveExportBlob(new Blob([buf], { type: MIME_TYPES.pdf }), filename, saveBlob);
|
|
60
83
|
return;
|
|
61
84
|
}
|
|
62
85
|
if (options.format === "epub") {
|
|
63
86
|
const { markdownDocToEpub } = await import("@bendyline/squisq-formats/epub");
|
|
64
|
-
const
|
|
65
|
-
const
|
|
87
|
+
const pictured = await pictureDiagrams(doc, converterOverrides);
|
|
88
|
+
const images = new Map([
|
|
89
|
+
...mediaContainer ? await resolveImageData(doc, mediaContainer) : [],
|
|
90
|
+
...[...pictured.images].map(
|
|
91
|
+
([url, picture]) => [url, picture.data.slice().buffer]
|
|
92
|
+
)
|
|
93
|
+
]);
|
|
94
|
+
const buf = await markdownDocToEpub(pictured.markdownDoc, { themeId, images });
|
|
66
95
|
await saveExportBlob(new Blob([buf], { type: MIME_TYPES.epub }), filename, saveBlob);
|
|
67
96
|
return;
|
|
68
97
|
}
|
|
@@ -81,11 +110,21 @@ async function runExport(markdown, selectedFile, options, mediaContainer, saveBl
|
|
|
81
110
|
enrichedDoc.themeId = themeId;
|
|
82
111
|
}
|
|
83
112
|
const images = mediaContainer ? await resolveImageData(doc, mediaContainer) : void 0;
|
|
84
|
-
const
|
|
113
|
+
const { mermaid } = await pictureDiagrams(doc, converterOverrides, ["mermaid"]);
|
|
114
|
+
const buf = await docToPptx(enrichedDoc, { themeId, images, diagramImages: mermaid });
|
|
85
115
|
await saveExportBlob(new Blob([buf], { type: MIME_TYPES.pptx }), filename, saveBlob);
|
|
86
116
|
return;
|
|
87
117
|
}
|
|
88
118
|
}
|
|
119
|
+
var MERMAID_FENCE = /^ {0,3}(?:```|~~~)[ \t]*mermaid\b/imu;
|
|
120
|
+
async function playerScriptFor(markdown) {
|
|
121
|
+
if (MERMAID_FENCE.test(markdown)) {
|
|
122
|
+
const { PLAYER_BUNDLE_FULL } = await import("@bendyline/squisq-react/standalone-source/full");
|
|
123
|
+
return PLAYER_BUNDLE_FULL;
|
|
124
|
+
}
|
|
125
|
+
const { PLAYER_BUNDLE } = await import("@bendyline/squisq-react/standalone-source");
|
|
126
|
+
return PLAYER_BUNDLE;
|
|
127
|
+
}
|
|
89
128
|
async function runHtmlExport(markdown, htmlFilename, options, mediaContainer, selectedFile, saveBlob) {
|
|
90
129
|
const baseName = htmlFilename.replace(/\.html$/, "");
|
|
91
130
|
const zipName = `${baseName}.zip`;
|
|
@@ -93,16 +132,17 @@ async function runHtmlExport(markdown, htmlFilename, options, mediaContainer, se
|
|
|
93
132
|
const themeId = options.themeId !== "standard" ? options.themeId : void 0;
|
|
94
133
|
if (options.includeLinkedDocs && mediaContainer && selectedFile) {
|
|
95
134
|
const entryPath = basenameForBundle(selectedFile);
|
|
135
|
+
const readDocument = (path) => path === entryPath ? Promise.resolve(markdown) : readDocumentFromContainer(mediaContainer, path);
|
|
96
136
|
if (options.htmlStyle === "rendered") {
|
|
97
|
-
const [{ markdownDocsToHtmlBundle },
|
|
137
|
+
const [{ markdownDocsToHtmlBundle }, playerScript] = await Promise.all([
|
|
98
138
|
import("@bendyline/squisq-formats/html"),
|
|
99
|
-
|
|
139
|
+
playerScriptFor(markdown)
|
|
100
140
|
]);
|
|
101
141
|
const blob2 = await markdownDocsToHtmlBundle({
|
|
102
142
|
entryPath,
|
|
103
|
-
readDocument
|
|
143
|
+
readDocument,
|
|
104
144
|
readBinary: (path) => mediaContainer.readFile(path),
|
|
105
|
-
playerScript
|
|
145
|
+
playerScript,
|
|
106
146
|
title: baseName,
|
|
107
147
|
themeId,
|
|
108
148
|
mode: "static",
|
|
@@ -115,7 +155,7 @@ async function runHtmlExport(markdown, htmlFilename, options, mediaContainer, se
|
|
|
115
155
|
const { markdownDocsToPlainHtmlBundle } = await import("@bendyline/squisq-formats/html");
|
|
116
156
|
const blob = await markdownDocsToPlainHtmlBundle({
|
|
117
157
|
entryPath,
|
|
118
|
-
readDocument
|
|
158
|
+
readDocument,
|
|
119
159
|
readBinary: (path) => mediaContainer.readFile(path),
|
|
120
160
|
title: baseName,
|
|
121
161
|
themeId,
|
|
@@ -125,10 +165,10 @@ async function runHtmlExport(markdown, htmlFilename, options, mediaContainer, se
|
|
|
125
165
|
return;
|
|
126
166
|
}
|
|
127
167
|
if (options.htmlStyle === "rendered") {
|
|
128
|
-
const [{ markdownToDoc }, { docToHtml, docToHtmlZip, collectImagePaths },
|
|
168
|
+
const [{ markdownToDoc }, { docToHtml, docToHtmlZip, collectImagePaths }, playerScript] = await Promise.all([
|
|
129
169
|
import("@bendyline/squisq/doc"),
|
|
130
170
|
import("@bendyline/squisq-formats/html"),
|
|
131
|
-
|
|
171
|
+
playerScriptFor(markdown)
|
|
132
172
|
]);
|
|
133
173
|
const mdDoc2 = parseMarkdown(markdown);
|
|
134
174
|
const baseDoc = markdownToDoc(mdDoc2);
|
|
@@ -136,7 +176,7 @@ async function runHtmlExport(markdown, htmlFilename, options, mediaContainer, se
|
|
|
136
176
|
const images = mediaContainer ? await resolveDocImages(baseDoc, mediaContainer, collectImagePaths) : void 0;
|
|
137
177
|
if (options.htmlBundle === "zip") {
|
|
138
178
|
const blob = await docToHtmlZip(baseDoc, {
|
|
139
|
-
playerScript
|
|
179
|
+
playerScript,
|
|
140
180
|
images,
|
|
141
181
|
mode: "static",
|
|
142
182
|
title: baseName,
|
|
@@ -146,7 +186,7 @@ async function runHtmlExport(markdown, htmlFilename, options, mediaContainer, se
|
|
|
146
186
|
return;
|
|
147
187
|
}
|
|
148
188
|
const html2 = docToHtml(baseDoc, {
|
|
149
|
-
playerScript
|
|
189
|
+
playerScript,
|
|
150
190
|
images,
|
|
151
191
|
mode: "static",
|
|
152
192
|
title: baseName,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/icons.tsx
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
function FontAwesomeIcon({ icon }) {
|
|
4
|
+
return /* @__PURE__ */ jsx("i", { className: icon, "aria-hidden": "true" });
|
|
5
|
+
}
|
|
6
|
+
function NewFileIcon() {
|
|
7
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-file-circle-plus" });
|
|
8
|
+
}
|
|
9
|
+
function NewFolderIcon() {
|
|
10
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-folder-plus" });
|
|
11
|
+
}
|
|
12
|
+
function OpenFolderIcon() {
|
|
13
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-folder-open" });
|
|
14
|
+
}
|
|
15
|
+
function SortByNameIcon() {
|
|
16
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-arrow-down-a-z" });
|
|
17
|
+
}
|
|
18
|
+
function SortByLastModifiedIcon() {
|
|
19
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-clock" });
|
|
20
|
+
}
|
|
21
|
+
function FolderIcon() {
|
|
22
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-folder" });
|
|
23
|
+
}
|
|
24
|
+
function MoreIcon() {
|
|
25
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-ellipsis" });
|
|
26
|
+
}
|
|
27
|
+
function PinIcon() {
|
|
28
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-thumbtack" });
|
|
29
|
+
}
|
|
30
|
+
function WorkspaceIcon() {
|
|
31
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-gear" });
|
|
32
|
+
}
|
|
33
|
+
function SplitViewIcon() {
|
|
34
|
+
return /* @__PURE__ */ jsxs(
|
|
35
|
+
"svg",
|
|
36
|
+
{
|
|
37
|
+
width: "16",
|
|
38
|
+
height: "16",
|
|
39
|
+
viewBox: "0 0 16 16",
|
|
40
|
+
fill: "none",
|
|
41
|
+
stroke: "currentColor",
|
|
42
|
+
strokeWidth: "1.5",
|
|
43
|
+
strokeLinecap: "round",
|
|
44
|
+
strokeLinejoin: "round",
|
|
45
|
+
"aria-hidden": "true",
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsx("rect", { x: "1.5", y: "2.5", width: "13", height: "11", rx: "1" }),
|
|
48
|
+
/* @__PURE__ */ jsx("line", { x1: "6", y1: "2.5", x2: "6", y2: "13.5" })
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
function SearchIcon() {
|
|
54
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-magnifying-glass" });
|
|
55
|
+
}
|
|
56
|
+
function FilesIcon() {
|
|
57
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-folder-tree" });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export {
|
|
61
|
+
NewFileIcon,
|
|
62
|
+
NewFolderIcon,
|
|
63
|
+
OpenFolderIcon,
|
|
64
|
+
SortByNameIcon,
|
|
65
|
+
SortByLastModifiedIcon,
|
|
66
|
+
FolderIcon,
|
|
67
|
+
MoreIcon,
|
|
68
|
+
PinIcon,
|
|
69
|
+
WorkspaceIcon,
|
|
70
|
+
SplitViewIcon,
|
|
71
|
+
SearchIcon,
|
|
72
|
+
FilesIcon
|
|
73
|
+
};
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// src/editor.ts
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
|
|
4
|
+
// src/components/FindButton.tsx
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
function FindButton({ active, onActiveChange, shortcutLabel: shortcutLabel2 }) {
|
|
7
|
+
const tooltip = shortcutLabel2 ? `Find in document (${shortcutLabel2})` : "Find in document";
|
|
8
|
+
return /* @__PURE__ */ jsx(
|
|
9
|
+
"button",
|
|
10
|
+
{
|
|
11
|
+
type: "button",
|
|
12
|
+
className: `squisq-toolbar-button${active ? " squisq-toolbar-button--active" : ""}`,
|
|
13
|
+
onClick: () => onActiveChange(!active),
|
|
14
|
+
"aria-label": "Find in document",
|
|
15
|
+
"aria-pressed": active,
|
|
16
|
+
"data-tooltip": tooltip,
|
|
17
|
+
children: /* @__PURE__ */ jsx(FindGlyph, {})
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function FindGlyph() {
|
|
22
|
+
return /* @__PURE__ */ jsxs(
|
|
23
|
+
"svg",
|
|
24
|
+
{
|
|
25
|
+
width: "16",
|
|
26
|
+
height: "16",
|
|
27
|
+
viewBox: "0 0 16 16",
|
|
28
|
+
fill: "none",
|
|
29
|
+
stroke: "currentColor",
|
|
30
|
+
strokeWidth: "1.5",
|
|
31
|
+
strokeLinecap: "round",
|
|
32
|
+
"aria-hidden": "true",
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ jsx("circle", { cx: "6.75", cy: "6.75", r: "4.25" }),
|
|
35
|
+
/* @__PURE__ */ jsx("path", { d: "m10 10 3.5 3.5" })
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/components/find-input.ts
|
|
42
|
+
function focusFindInput(scope = document) {
|
|
43
|
+
const input = scope.querySelector(".squisq-find-input");
|
|
44
|
+
input?.focus();
|
|
45
|
+
input?.select();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/DocBlocksShell/keyboard-shortcuts.ts
|
|
49
|
+
var SHELL_SHORTCUTS = Object.freeze([
|
|
50
|
+
// Must work mid-sentence; that is the entire point of a save shortcut.
|
|
51
|
+
{ id: "save", key: "s", accel: true, label: "Ctrl+S", whileTyping: true },
|
|
52
|
+
// Find is mostly invoked from inside the document being searched.
|
|
53
|
+
{ id: "find", key: "f", accel: true, label: "Ctrl+F", whileTyping: true },
|
|
54
|
+
// Jumping elsewhere is as likely mid-sentence as from the tree.
|
|
55
|
+
{ id: "quick-open", key: "p", accel: true, label: "Ctrl+P", whileTyping: true },
|
|
56
|
+
{
|
|
57
|
+
id: "workspace-search",
|
|
58
|
+
key: "f",
|
|
59
|
+
accel: true,
|
|
60
|
+
shift: true,
|
|
61
|
+
label: "Ctrl+Shift+F",
|
|
62
|
+
whileTyping: true
|
|
63
|
+
},
|
|
64
|
+
// Deliberately NOT Cmd+B — Squisq owns that for Bold. Cmd+\ is the VS Code
|
|
65
|
+
// convention for toggling the side bar.
|
|
66
|
+
{ id: "toggle-sidebar", key: "\\", accel: true, label: "Ctrl+\\", whileTyping: true },
|
|
67
|
+
{ id: "focus-files", key: "e", accel: true, shift: true, label: "Ctrl+Shift+E" },
|
|
68
|
+
{ id: "new-document", key: "n", accel: true, label: "Ctrl+N" },
|
|
69
|
+
{ id: "new-folder", key: "n", accel: true, shift: true, label: "Ctrl+Shift+N" },
|
|
70
|
+
// Ctrl+, (settings) is deliberately absent: AppMenu owns that dialog's state
|
|
71
|
+
// internally and exposes no way to open it. Binding the key without first
|
|
72
|
+
// giving AppMenu a controlled `settingsOpen` prop would ship a dead shortcut.
|
|
73
|
+
{ id: "close-overlay", key: "Escape", accel: false, label: "Esc", whileTyping: true }
|
|
74
|
+
]);
|
|
75
|
+
function isTypingTarget(target) {
|
|
76
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
77
|
+
if (target.isContentEditable) return true;
|
|
78
|
+
const tag = target.tagName;
|
|
79
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
80
|
+
return target.closest(".monaco-editor") !== null;
|
|
81
|
+
}
|
|
82
|
+
function matchShortcut(event, _layoutMode) {
|
|
83
|
+
return SHELL_SHORTCUTS.find((binding) => bindingMatches(binding, event))?.id ?? null;
|
|
84
|
+
}
|
|
85
|
+
function bindingMatches(binding, event) {
|
|
86
|
+
if (event.altKey) return false;
|
|
87
|
+
const accel = event.ctrlKey || event.metaKey;
|
|
88
|
+
const key = event.key.length === 1 ? event.key.toLowerCase() : event.key;
|
|
89
|
+
if (binding.accel !== accel) return false;
|
|
90
|
+
if ((binding.shift ?? false) !== event.shiftKey) return false;
|
|
91
|
+
if (binding.key !== key) return false;
|
|
92
|
+
return binding.whileTyping === true || !isTypingTarget(event.target);
|
|
93
|
+
}
|
|
94
|
+
function isFindShortcut(event) {
|
|
95
|
+
const binding = SHELL_SHORTCUTS.find((candidate) => candidate.id === "find");
|
|
96
|
+
return binding !== void 0 && bindingMatches(binding, event);
|
|
97
|
+
}
|
|
98
|
+
function findShortcutLabel() {
|
|
99
|
+
return shortcutLabel("find", isApplePlatform());
|
|
100
|
+
}
|
|
101
|
+
function isApplePlatform() {
|
|
102
|
+
if (typeof navigator === "undefined") return false;
|
|
103
|
+
return /Mac|iPhone|iPad|iPod/u.test(navigator.platform || navigator.userAgent);
|
|
104
|
+
}
|
|
105
|
+
function shortcutLabel(id, isApple) {
|
|
106
|
+
const binding = SHELL_SHORTCUTS.find((candidate) => candidate.id === id);
|
|
107
|
+
if (!binding) return "";
|
|
108
|
+
return isApple ? binding.label.replace("Ctrl+", "\u2318") : binding.label;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/editor.ts
|
|
112
|
+
var PORTRAIT_FORM_FACTOR_QUERY = "(orientation: portrait)";
|
|
113
|
+
function previewViewportPresetForOrientation(isPortrait) {
|
|
114
|
+
return isPortrait ? "portrait" : "landscape";
|
|
115
|
+
}
|
|
116
|
+
function useResponsivePreviewViewportPreset() {
|
|
117
|
+
const [isPortrait, setIsPortrait] = useState(() => {
|
|
118
|
+
if (typeof globalThis.matchMedia !== "function") return false;
|
|
119
|
+
return globalThis.matchMedia(PORTRAIT_FORM_FACTOR_QUERY).matches;
|
|
120
|
+
});
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (typeof globalThis.matchMedia !== "function") return;
|
|
123
|
+
const query = globalThis.matchMedia(PORTRAIT_FORM_FACTOR_QUERY);
|
|
124
|
+
const update = () => setIsPortrait(query.matches);
|
|
125
|
+
update();
|
|
126
|
+
query.addEventListener("change", update);
|
|
127
|
+
return () => query.removeEventListener("change", update);
|
|
128
|
+
}, []);
|
|
129
|
+
return previewViewportPresetForOrientation(isPortrait);
|
|
130
|
+
}
|
|
131
|
+
var EMPTY_DOCUMENT_PROMPTS = [
|
|
132
|
+
"Start typing your content, or drop images on top of me...",
|
|
133
|
+
"Write anything -- paste markdown, drag in images, or just start typing...",
|
|
134
|
+
"Type away. Markdown syntax works too...",
|
|
135
|
+
"Chapter 1 begins here...",
|
|
136
|
+
"Once upon a time...",
|
|
137
|
+
"A blank page. Exciting, isn't it?",
|
|
138
|
+
"The first word is always the hardest...",
|
|
139
|
+
"Plot twist: this is where it all starts...",
|
|
140
|
+
"Write something the future you will thank you for...",
|
|
141
|
+
"Begin at the beginning...",
|
|
142
|
+
"Let's begin.",
|
|
143
|
+
"We can be heroes...",
|
|
144
|
+
"Here comes the sun...",
|
|
145
|
+
"And so it begins...",
|
|
146
|
+
"Let it be, let it be...",
|
|
147
|
+
"Don't stop believing...",
|
|
148
|
+
"Started from the bottom...",
|
|
149
|
+
"This is the start of something new...",
|
|
150
|
+
"Ground control to Major Tom...",
|
|
151
|
+
"Come as you are...",
|
|
152
|
+
"Every new beginning...",
|
|
153
|
+
"Hello, is it me you're looking for?",
|
|
154
|
+
"Imagine all the people...",
|
|
155
|
+
"Anything you want, you got it...",
|
|
156
|
+
"Rise above...",
|
|
157
|
+
"Do you have the time...",
|
|
158
|
+
"Here we are now, entertain us...",
|
|
159
|
+
"All the small things...",
|
|
160
|
+
"Should I stay or should I go?",
|
|
161
|
+
"I am a patient boy -- I wait, I wait, I wait...",
|
|
162
|
+
"Destination unknown...",
|
|
163
|
+
"Easy like Sunday morning...",
|
|
164
|
+
"Dance, dance, dance to the radio...",
|
|
165
|
+
"New day rising...",
|
|
166
|
+
"Visit the world...",
|
|
167
|
+
"Positive mental attitude...",
|
|
168
|
+
"Better I sing than I cry...",
|
|
169
|
+
"Disconnect for a minute...",
|
|
170
|
+
"We need new noise...",
|
|
171
|
+
"Shoot the moon...",
|
|
172
|
+
"I'll surprise you sometime -- I'll come around...",
|
|
173
|
+
"Coming out of my cage, and doing just fine...",
|
|
174
|
+
"Throw me to the wolves -- I'll come back, leading the pack...",
|
|
175
|
+
"There comes a time -- no excuses...",
|
|
176
|
+
"It's up to me now, turn on the bright lights...",
|
|
177
|
+
"Do what you want...",
|
|
178
|
+
"Fingers crossed...",
|
|
179
|
+
"This is the start of how it all ends...",
|
|
180
|
+
"It has to start somewhere, it has to start sometime -- what better place than here? what better time than now?",
|
|
181
|
+
"I know myself, and I'll begin again...",
|
|
182
|
+
"Dig me out, dig me in...",
|
|
183
|
+
"Everybody's full of sugar, honey, ice and tea...",
|
|
184
|
+
"Take time with a wounded hand, 'cause it likes to heal...",
|
|
185
|
+
"Grab a brush and put on a little makeup...",
|
|
186
|
+
"Amber is the color of your energy...",
|
|
187
|
+
"Wait -- they don't love it like I love it...",
|
|
188
|
+
"A world's been buried, where love is the law; a you-topia..."
|
|
189
|
+
];
|
|
190
|
+
function pickEmptyDocumentPrompt(random = Math.random) {
|
|
191
|
+
const index = Math.floor(random() * EMPTY_DOCUMENT_PROMPTS.length);
|
|
192
|
+
return EMPTY_DOCUMENT_PROMPTS[index] ?? EMPTY_DOCUMENT_PROMPTS[0];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export {
|
|
196
|
+
FindButton,
|
|
197
|
+
focusFindInput,
|
|
198
|
+
matchShortcut,
|
|
199
|
+
isFindShortcut,
|
|
200
|
+
findShortcutLabel,
|
|
201
|
+
isApplePlatform,
|
|
202
|
+
shortcutLabel,
|
|
203
|
+
PORTRAIT_FORM_FACTOR_QUERY,
|
|
204
|
+
previewViewportPresetForOrientation,
|
|
205
|
+
useResponsivePreviewViewportPreset,
|
|
206
|
+
EMPTY_DOCUMENT_PROMPTS,
|
|
207
|
+
pickEmptyDocumentPrompt
|
|
208
|
+
};
|