@bendyline/docblocks-react 2.6.2 → 2.7.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 +3 -10
- package/THIRD_PARTY_NOTICES.txt +4284 -3651
- package/dist/AiDiagrams-LFV4YU6W.js +13 -0
- package/dist/AiEditorAssistant-GN2KXKZD.js +786 -0
- package/dist/AudioExportDialog-F23QXNPB.js +253 -0
- package/dist/DocumentConflictDialog-5LRVIGXS.js +111 -0
- package/dist/ExportDialog-IMBVGRYG.js +9 -0
- package/dist/{ExportToolbarControls-QYLBRWM7.js → ExportToolbarControls-MUM6HM3K.js} +117 -49
- package/dist/{GitToolbarControl-O5AXBC6T.js → GitToolbarControl-B7KG4MFP.js} +6 -6
- package/dist/{GitUI-L5T3XHZG.js → GitUI-RCWUZVS6.js} +6 -6
- package/dist/PresentationMaker-W2JIBHRN.js +9 -0
- package/dist/QuickOpenDialog-2KK4SEBU.js +356 -0
- package/dist/Settings-DuXk6baH.d.ts +144 -0
- package/dist/ShareDialog-XUA2OVGI.js +292 -0
- package/dist/SpeechToolbarControl-OSQS7NVY.js +434 -0
- package/dist/TextFromNarration-XYRAB6O2.js +598 -0
- package/dist/WorkspaceSearchPanel-BKZJRPMY.js +334 -0
- package/dist/chunk-2IYBBFQX.js +201 -0
- package/dist/{chunk-LG6HAWCK.js → chunk-56KO2LYN.js} +35 -4
- 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-FMDLZ4ZG.js → chunk-BD54Z5XP.js} +12 -3
- package/dist/chunk-EA4BO6E4.js +73 -0
- package/dist/chunk-EPOLZNFD.js +518 -0
- package/dist/chunk-G4MFB3IO.js +208 -0
- package/dist/{chunk-MRUK56JS.js → chunk-GMA4KGGO.js} +7 -3
- 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-NAH52736.js +1884 -0
- package/dist/chunk-RP3DVNTI.js +62 -0
- package/dist/chunk-SPUPWCSI.js +111 -0
- 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-W55E6TE2.js +1714 -0
- package/dist/chunk-X3DDTJKR.js +574 -0
- package/dist/{chunk-EBWYGTN7.js → chunk-X437UAF7.js} +6 -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 +3927 -1638
- package/dist/proofing/index.js +11 -1
- 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 +2344 -657
- package/dist/ExportDialog-Q4VWI43H.js +0 -9
- package/dist/ShareDialog-4OX3UPJ4.js +0 -359
- package/dist/chunk-JDJVRDOP.js +0 -92
- package/dist/chunk-Q6XNIKDG.js +0 -669
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HighlightedText
|
|
3
|
+
} from "./chunk-TBLZBNQF.js";
|
|
4
|
+
import {
|
|
5
|
+
displayFileName
|
|
6
|
+
} from "./chunk-ARATARVJ.js";
|
|
7
|
+
import {
|
|
8
|
+
Dialog
|
|
9
|
+
} from "./chunk-56KO2LYN.js";
|
|
10
|
+
|
|
11
|
+
// src/QuickOpen/QuickOpenDialog.tsx
|
|
12
|
+
import { useEffect, useId, useMemo, useRef, useState } from "react";
|
|
13
|
+
import { tryParseWorkspacePath } from "@bendyline/docblocks/filesystem";
|
|
14
|
+
|
|
15
|
+
// src/QuickOpen/quick-open-ranking.ts
|
|
16
|
+
import { fuzzyMatch, fuzzyTokens } from "@bendyline/docblocks/workspace-index";
|
|
17
|
+
var DEFAULT_LIMIT = 50;
|
|
18
|
+
var EMPTY_QUERY_LIMIT = 20;
|
|
19
|
+
var RECENCY_HORIZON = 50;
|
|
20
|
+
var RECENCY_WEIGHT = 0.25;
|
|
21
|
+
var PINNED_WEIGHT = 0.05;
|
|
22
|
+
var DOCUMENT_WEIGHT = 0.03;
|
|
23
|
+
function splitPath(path) {
|
|
24
|
+
const slash = path.lastIndexOf("/");
|
|
25
|
+
return slash < 0 ? { folder: "", base: path } : { folder: path.slice(0, slash), base: path.slice(slash + 1) };
|
|
26
|
+
}
|
|
27
|
+
function stemOf(name) {
|
|
28
|
+
const dot = name.lastIndexOf(".");
|
|
29
|
+
return dot > 0 ? name.slice(0, dot) : name;
|
|
30
|
+
}
|
|
31
|
+
function compareCodeUnits(left, right) {
|
|
32
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
33
|
+
}
|
|
34
|
+
function item(candidate, ranges) {
|
|
35
|
+
return {
|
|
36
|
+
key: `${candidate.workspaceId}\0${candidate.path}`,
|
|
37
|
+
workspaceId: candidate.workspaceId,
|
|
38
|
+
workspaceName: candidate.workspaceName,
|
|
39
|
+
path: candidate.path,
|
|
40
|
+
name: candidate.name,
|
|
41
|
+
folder: candidate.folder,
|
|
42
|
+
title: candidate.title,
|
|
43
|
+
nameRanges: ranges?.nameRanges ?? [],
|
|
44
|
+
folderRanges: ranges?.folderRanges ?? [],
|
|
45
|
+
titleRanges: ranges?.titleRanges ?? [],
|
|
46
|
+
recent: candidate.recentRank >= 0,
|
|
47
|
+
pinned: candidate.pinned
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function buildCandidates(input) {
|
|
51
|
+
const titles = new Map(
|
|
52
|
+
input.documents.map((document2) => [document2.path, document2.title])
|
|
53
|
+
);
|
|
54
|
+
const recentRank = new Map(input.recent.map((path, rank) => [path, rank]));
|
|
55
|
+
const pinnedHere = new Set(
|
|
56
|
+
input.pins.filter((pin) => pin.workspaceId === input.workspaceId).map((pin) => pin.path)
|
|
57
|
+
);
|
|
58
|
+
const candidates = input.files.map((file) => {
|
|
59
|
+
const { folder } = splitPath(file.path);
|
|
60
|
+
const name = displayFileName(file.name);
|
|
61
|
+
const title = titles.get(file.path) ?? null;
|
|
62
|
+
return {
|
|
63
|
+
workspaceId: input.workspaceId,
|
|
64
|
+
workspaceName: null,
|
|
65
|
+
path: file.path,
|
|
66
|
+
name,
|
|
67
|
+
folder,
|
|
68
|
+
title: title && title !== stemOf(file.name) && title !== name ? title : null,
|
|
69
|
+
isDocument: file.kind !== "other",
|
|
70
|
+
recentRank: recentRank.get(file.path) ?? -1,
|
|
71
|
+
pinned: pinnedHere.has(file.path)
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
for (const pin of input.pins) {
|
|
75
|
+
if (pin.workspaceId === input.workspaceId) continue;
|
|
76
|
+
const { folder, base } = splitPath(pin.path);
|
|
77
|
+
candidates.push({
|
|
78
|
+
workspaceId: pin.workspaceId,
|
|
79
|
+
workspaceName: pin.workspaceName,
|
|
80
|
+
path: pin.path,
|
|
81
|
+
name: displayFileName(base),
|
|
82
|
+
folder,
|
|
83
|
+
title: null,
|
|
84
|
+
isDocument: true,
|
|
85
|
+
recentRank: -1,
|
|
86
|
+
pinned: true
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return candidates;
|
|
90
|
+
}
|
|
91
|
+
function emptyQuery(input, candidates) {
|
|
92
|
+
const byPath = new Map(
|
|
93
|
+
candidates.filter((candidate) => candidate.workspaceId === input.workspaceId).map((candidate) => [candidate.path, candidate])
|
|
94
|
+
);
|
|
95
|
+
const shown = /* @__PURE__ */ new Set();
|
|
96
|
+
const items = [];
|
|
97
|
+
const add = (candidate) => {
|
|
98
|
+
if (!candidate) return;
|
|
99
|
+
const key = `${candidate.workspaceId}\0${candidate.path}`;
|
|
100
|
+
const active = candidate.workspaceId === input.workspaceId && candidate.path === input.activePath;
|
|
101
|
+
if (shown.has(key) || active) return;
|
|
102
|
+
shown.add(key);
|
|
103
|
+
items.push(item(candidate));
|
|
104
|
+
};
|
|
105
|
+
for (const path of input.recent) add(byPath.get(path));
|
|
106
|
+
for (const candidate of candidates) if (candidate.pinned) add(candidate);
|
|
107
|
+
const lastModified = new Map(input.files.map((file) => [file.path, file.lastModified]));
|
|
108
|
+
const modified = [...byPath.values()].sort(
|
|
109
|
+
(left, right) => compareCodeUnits(lastModified.get(right.path) ?? "", lastModified.get(left.path) ?? "") || compareCodeUnits(left.path, right.path)
|
|
110
|
+
);
|
|
111
|
+
for (const candidate of modified) {
|
|
112
|
+
if (items.length >= EMPTY_QUERY_LIMIT) break;
|
|
113
|
+
add(candidate);
|
|
114
|
+
}
|
|
115
|
+
return items;
|
|
116
|
+
}
|
|
117
|
+
var FIELD_WEIGHTS = { name: 1, title: 0.9, folder: 0.6, path: 1 };
|
|
118
|
+
function bestField(token, candidate) {
|
|
119
|
+
const fields = token.includes("/") ? [["path", candidate.folder ? `${candidate.folder}/${candidate.name}` : candidate.name]] : [
|
|
120
|
+
["name", candidate.name],
|
|
121
|
+
["title", candidate.title],
|
|
122
|
+
["folder", candidate.folder]
|
|
123
|
+
];
|
|
124
|
+
let best = null;
|
|
125
|
+
for (const [field, text] of fields) {
|
|
126
|
+
if (!text) continue;
|
|
127
|
+
const match = fuzzyMatch(token, text);
|
|
128
|
+
if (!match) continue;
|
|
129
|
+
const score = match.score * FIELD_WEIGHTS[field];
|
|
130
|
+
if (!best || score > best.score) best = { score, field, ranges: match.ranges };
|
|
131
|
+
}
|
|
132
|
+
return best;
|
|
133
|
+
}
|
|
134
|
+
function mergeRanges(ranges) {
|
|
135
|
+
const sorted = [...ranges].sort((left, right) => left[0] - right[0]);
|
|
136
|
+
const merged = [];
|
|
137
|
+
for (const [start, end] of sorted) {
|
|
138
|
+
const last = merged[merged.length - 1];
|
|
139
|
+
if (last && start <= last[1]) last[1] = Math.max(last[1], end);
|
|
140
|
+
else merged.push([start, end]);
|
|
141
|
+
}
|
|
142
|
+
return merged;
|
|
143
|
+
}
|
|
144
|
+
function rankQuickOpen(input) {
|
|
145
|
+
const candidates = buildCandidates(input);
|
|
146
|
+
const tokens = fuzzyTokens(input.query);
|
|
147
|
+
if (tokens.length === 0) return emptyQuery(input, candidates);
|
|
148
|
+
const perfect = tokens.reduce(
|
|
149
|
+
(total, token) => total + (fuzzyMatch(token, token)?.score ?? 0),
|
|
150
|
+
0
|
|
151
|
+
);
|
|
152
|
+
const scored = [];
|
|
153
|
+
for (const candidate of candidates) {
|
|
154
|
+
let score = 0;
|
|
155
|
+
const ranges = {
|
|
156
|
+
name: [],
|
|
157
|
+
title: [],
|
|
158
|
+
folder: []
|
|
159
|
+
};
|
|
160
|
+
let matched = true;
|
|
161
|
+
for (const token of tokens) {
|
|
162
|
+
const best = bestField(token, candidate);
|
|
163
|
+
if (!best) {
|
|
164
|
+
matched = false;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
score += best.score;
|
|
168
|
+
if (best.field === "path") {
|
|
169
|
+
const offset = candidate.folder ? candidate.folder.length + 1 : 0;
|
|
170
|
+
for (const [start, end] of best.ranges) {
|
|
171
|
+
if (end <= candidate.folder.length) ranges.folder.push([start, end]);
|
|
172
|
+
else if (start >= offset) ranges.name.push([start - offset, end - offset]);
|
|
173
|
+
else {
|
|
174
|
+
ranges.folder.push([start, candidate.folder.length]);
|
|
175
|
+
ranges.name.push([0, end - offset]);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
ranges[best.field].push(...best.ranges);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (!matched) continue;
|
|
183
|
+
if (candidate.recentRank >= 0 && candidate.recentRank < RECENCY_HORIZON) {
|
|
184
|
+
score += perfect * RECENCY_WEIGHT * (1 - candidate.recentRank / RECENCY_HORIZON);
|
|
185
|
+
}
|
|
186
|
+
if (candidate.pinned) score += perfect * PINNED_WEIGHT;
|
|
187
|
+
if (candidate.isDocument) score += perfect * DOCUMENT_WEIGHT;
|
|
188
|
+
scored.push({
|
|
189
|
+
score,
|
|
190
|
+
item: item(candidate, {
|
|
191
|
+
nameRanges: mergeRanges(ranges.name),
|
|
192
|
+
titleRanges: mergeRanges(ranges.title),
|
|
193
|
+
folderRanges: mergeRanges(ranges.folder)
|
|
194
|
+
})
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
scored.sort(
|
|
198
|
+
(left, right) => right.score - left.score || left.item.path.length - right.item.path.length || compareCodeUnits(left.item.path, right.item.path)
|
|
199
|
+
);
|
|
200
|
+
return scored.slice(0, input.limit ?? DEFAULT_LIMIT).map((entry) => entry.item);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/QuickOpen/QuickOpenDialog.tsx
|
|
204
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
205
|
+
var PAGE = 10;
|
|
206
|
+
function statusMessage(status, query, count) {
|
|
207
|
+
if (status.error) return status.error;
|
|
208
|
+
if (!status.listed) return "Listing workspace\u2026";
|
|
209
|
+
if (query.trim() && count === 0) return "No matching documents";
|
|
210
|
+
if (status.truncated) return "Large workspace: some files are not listed.";
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
function QuickOpenDialog({
|
|
214
|
+
index,
|
|
215
|
+
status,
|
|
216
|
+
workspaceId,
|
|
217
|
+
activePath,
|
|
218
|
+
recent,
|
|
219
|
+
pins,
|
|
220
|
+
focusRequest,
|
|
221
|
+
onOpen,
|
|
222
|
+
onClose
|
|
223
|
+
}) {
|
|
224
|
+
const inputRef = useRef(null);
|
|
225
|
+
const listId = useId();
|
|
226
|
+
const optionPrefix = useId();
|
|
227
|
+
const [query, setQuery] = useState("");
|
|
228
|
+
const [active, setActive] = useState(0);
|
|
229
|
+
const canonicalActive = activePath === null ? null : tryParseWorkspacePath(activePath);
|
|
230
|
+
const items = useMemo(
|
|
231
|
+
() => rankQuickOpen({
|
|
232
|
+
query,
|
|
233
|
+
workspaceId,
|
|
234
|
+
files: index?.getFiles() ?? [],
|
|
235
|
+
documents: index?.getDocuments() ?? [],
|
|
236
|
+
recent,
|
|
237
|
+
pins,
|
|
238
|
+
activePath: canonicalActive
|
|
239
|
+
}),
|
|
240
|
+
// `status.generation` stands in for the index's contents.
|
|
241
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
242
|
+
[query, workspaceId, index, status.generation, recent, pins, canonicalActive]
|
|
243
|
+
);
|
|
244
|
+
useEffect(() => {
|
|
245
|
+
const first = items[0];
|
|
246
|
+
const skipActive = items.length > 1 && first?.workspaceId === workspaceId && first.path === canonicalActive;
|
|
247
|
+
setActive(skipActive ? 1 : 0);
|
|
248
|
+
}, [query]);
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
inputRef.current?.focus();
|
|
251
|
+
inputRef.current?.select();
|
|
252
|
+
}, [focusRequest]);
|
|
253
|
+
const activeIndex = Math.min(active, Math.max(0, items.length - 1));
|
|
254
|
+
const activeId = items.length > 0 ? `${optionPrefix}-${activeIndex}` : void 0;
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (activeId) document.getElementById(activeId)?.scrollIntoView({ block: "nearest" });
|
|
257
|
+
}, [activeId]);
|
|
258
|
+
const move = (delta) => {
|
|
259
|
+
if (items.length === 0) return;
|
|
260
|
+
setActive(Math.max(0, Math.min(items.length - 1, activeIndex + delta)));
|
|
261
|
+
};
|
|
262
|
+
const onKeyDown = (event) => {
|
|
263
|
+
switch (event.key) {
|
|
264
|
+
case "ArrowDown":
|
|
265
|
+
event.preventDefault();
|
|
266
|
+
move(1);
|
|
267
|
+
break;
|
|
268
|
+
case "ArrowUp":
|
|
269
|
+
event.preventDefault();
|
|
270
|
+
move(-1);
|
|
271
|
+
break;
|
|
272
|
+
case "PageDown":
|
|
273
|
+
event.preventDefault();
|
|
274
|
+
move(PAGE);
|
|
275
|
+
break;
|
|
276
|
+
case "PageUp":
|
|
277
|
+
event.preventDefault();
|
|
278
|
+
move(-PAGE);
|
|
279
|
+
break;
|
|
280
|
+
case "Enter": {
|
|
281
|
+
event.preventDefault();
|
|
282
|
+
const chosen = items[activeIndex];
|
|
283
|
+
if (chosen) onOpen(chosen);
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
default:
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
const message = statusMessage(status, query, items.length);
|
|
291
|
+
return /* @__PURE__ */ jsxs(
|
|
292
|
+
Dialog,
|
|
293
|
+
{
|
|
294
|
+
title: "Go to document",
|
|
295
|
+
onClose,
|
|
296
|
+
size: "wide",
|
|
297
|
+
placement: "top",
|
|
298
|
+
titleHidden: true,
|
|
299
|
+
initialFocusRef: inputRef,
|
|
300
|
+
className: "db-quick-open",
|
|
301
|
+
bodyClassName: "db-quick-open-body",
|
|
302
|
+
children: [
|
|
303
|
+
/* @__PURE__ */ jsx(
|
|
304
|
+
"input",
|
|
305
|
+
{
|
|
306
|
+
ref: inputRef,
|
|
307
|
+
className: "db-quick-open-input",
|
|
308
|
+
type: "text",
|
|
309
|
+
role: "combobox",
|
|
310
|
+
"aria-label": "Go to document",
|
|
311
|
+
"aria-expanded": items.length > 0,
|
|
312
|
+
"aria-controls": listId,
|
|
313
|
+
"aria-activedescendant": activeId,
|
|
314
|
+
"aria-autocomplete": "list",
|
|
315
|
+
autoComplete: "off",
|
|
316
|
+
spellCheck: false,
|
|
317
|
+
placeholder: "Search documents by name or title",
|
|
318
|
+
value: query,
|
|
319
|
+
onChange: (event) => setQuery(event.target.value),
|
|
320
|
+
onKeyDown
|
|
321
|
+
}
|
|
322
|
+
),
|
|
323
|
+
/* @__PURE__ */ jsx("ul", { id: listId, role: "listbox", "aria-label": "Documents", className: "db-quick-open-list", children: items.map((item2, position) => /* @__PURE__ */ jsxs(
|
|
324
|
+
"li",
|
|
325
|
+
{
|
|
326
|
+
id: `${optionPrefix}-${position}`,
|
|
327
|
+
role: "option",
|
|
328
|
+
"aria-selected": position === activeIndex,
|
|
329
|
+
className: position === activeIndex ? "db-quick-open-option db-quick-open-option--active" : "db-quick-open-option",
|
|
330
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
331
|
+
onMouseMove: () => {
|
|
332
|
+
if (position !== activeIndex) setActive(position);
|
|
333
|
+
},
|
|
334
|
+
onClick: () => onOpen(item2),
|
|
335
|
+
children: [
|
|
336
|
+
/* @__PURE__ */ jsx("span", { className: "db-quick-open-name", children: /* @__PURE__ */ jsx(HighlightedText, { text: item2.name, ranges: item2.nameRanges }) }),
|
|
337
|
+
item2.title && /* @__PURE__ */ jsx("span", { className: "db-quick-open-title", children: /* @__PURE__ */ jsx(HighlightedText, { text: item2.title, ranges: item2.titleRanges }) }),
|
|
338
|
+
/* @__PURE__ */ jsxs("span", { className: "db-quick-open-folder", children: [
|
|
339
|
+
item2.workspaceName && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
340
|
+
item2.workspaceName,
|
|
341
|
+
" \xB7 "
|
|
342
|
+
] }),
|
|
343
|
+
/* @__PURE__ */ jsx(HighlightedText, { text: item2.folder, ranges: item2.folderRanges })
|
|
344
|
+
] })
|
|
345
|
+
]
|
|
346
|
+
},
|
|
347
|
+
item2.key
|
|
348
|
+
)) }),
|
|
349
|
+
/* @__PURE__ */ jsx("p", { className: "db-quick-open-status", role: "status", children: message })
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
export {
|
|
355
|
+
QuickOpenDialog
|
|
356
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { DocBlocksHostAiAPI } from '@bendyline/docblocks/host';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import { WriteCanvasSettings } from '@bendyline/squisq-editor-react';
|
|
5
|
+
|
|
6
|
+
/** Appearance preferences shared by the shell and settings UI. */
|
|
7
|
+
type ThemePreference = 'auto' | 'light' | 'dark';
|
|
8
|
+
declare const ACCENT_COLORS: readonly ["brown", "green", "blue", "purple", "maroon", "orange", "gray"];
|
|
9
|
+
type AccentColor = (typeof ACCENT_COLORS)[number];
|
|
10
|
+
/**
|
|
11
|
+
* Which typeface the shell chrome uses.
|
|
12
|
+
*
|
|
13
|
+
* `system` resolves `system-ui`, so DocBlocks looks native on each platform —
|
|
14
|
+
* the right default, and what almost everyone should keep. `fixed` pins the
|
|
15
|
+
* chrome to the bundled `DocBlocks Fixed UI` face (the Roboto variable binary
|
|
16
|
+
* already shipped for the document theme of that name) so the interface renders
|
|
17
|
+
* identically everywhere.
|
|
18
|
+
*
|
|
19
|
+
* Two things want that. A user working across machines gets typography that
|
|
20
|
+
* does not shift between them. And the visual-regression suite gets a rendering
|
|
21
|
+
* it can compare across operating systems at all: under `system` the same
|
|
22
|
+
* screenshot differs on every platform, which is why those baselines are
|
|
23
|
+
* otherwise captured on one OS and compared only there.
|
|
24
|
+
*/
|
|
25
|
+
type InterfaceFontPreference = 'system' | 'fixed';
|
|
26
|
+
declare const DEFAULT_INTERFACE_FONT: InterfaceFontPreference;
|
|
27
|
+
declare function loadInterfaceFont(): InterfaceFontPreference;
|
|
28
|
+
declare function saveInterfaceFont(value: InterfaceFontPreference): void;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Stable ids for the Write-canvas font schemes offered in Settings. This list
|
|
32
|
+
* mirrors `DOCBLOCKS_WRITE_CANVAS_FONT_SCHEMES` in `@bendyline/docblocks/vscode`
|
|
33
|
+
* (the wire/persisted contract) and the `docblocks.writeCanvasFontScheme` enum
|
|
34
|
+
* in the VS Code `package.json`; a guard test keeps the three in sync.
|
|
35
|
+
*/
|
|
36
|
+
type WriteCanvasFontScheme = 'theme' | 'serif-sans' | 'sans-sans' | 'serif-serif' | 'pt-serif' | 'hanken' | 'playfair-pt-serif' | 'hanken-lora' | 'dm-serif-dm-sans' | 'inter';
|
|
37
|
+
type WriteCanvasFontSchemeGroup = 'theme' | 'system' | 'curated';
|
|
38
|
+
interface WriteCanvasFontSchemeOption {
|
|
39
|
+
id: WriteCanvasFontScheme;
|
|
40
|
+
label: string;
|
|
41
|
+
group: WriteCanvasFontSchemeGroup;
|
|
42
|
+
/** CSS font-family for headings. Omitted for `'theme'` (inherit). */
|
|
43
|
+
headerFont?: string;
|
|
44
|
+
/** CSS font-family for body text. Omitted for `'theme'` (inherit). */
|
|
45
|
+
bodyFont?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Curated Write-canvas font schemes, in picker order. A named scheme is an
|
|
49
|
+
* explicit user preference and overrides the active theme in Write mode through
|
|
50
|
+
* the DocBlocks host stylesheet. `'theme'` sets no fonts, i.e. inherits the
|
|
51
|
+
* active theme / host as before.
|
|
52
|
+
*/
|
|
53
|
+
declare const WRITE_CANVAS_FONT_SCHEMES: readonly WriteCanvasFontSchemeOption[];
|
|
54
|
+
declare const DEFAULT_WRITE_CANVAS_FONT_SCHEME: WriteCanvasFontScheme;
|
|
55
|
+
/** Resolve a scheme id to the header/body CSS font-family strings (empty for `'theme'`). */
|
|
56
|
+
declare function resolveWriteCanvasFonts(scheme: WriteCanvasFontScheme): Pick<WriteCanvasSettings, 'headerFont' | 'bodyFont'>;
|
|
57
|
+
/** Persisted Write-canvas preferences. Stores the font scheme id, not resolved fonts. */
|
|
58
|
+
interface WriteCanvasPreferences {
|
|
59
|
+
textSize: number;
|
|
60
|
+
lineSpacing: number;
|
|
61
|
+
fontScheme: WriteCanvasFontScheme;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Inline proofing preferences — which squiggles the editor draws.
|
|
66
|
+
*
|
|
67
|
+
* Two independent switches rather than one, because they fail
|
|
68
|
+
* differently: spell checking is language-agnostic enough to leave on
|
|
69
|
+
* everywhere, while the grammar rules harper ships are English-only and
|
|
70
|
+
* are noise in a document written in anything else. The engine itself is
|
|
71
|
+
* still all-or-nothing (harper lints once and reports a category per
|
|
72
|
+
* finding), so these filter what surfaces; turning both off is what
|
|
73
|
+
* turns proofing — and the ~30 MiB engine download — off entirely.
|
|
74
|
+
*
|
|
75
|
+
* Stored per browser/profile, never in the document: a reader's tolerance
|
|
76
|
+
* for green underlines is not content. The per-document opt-out lives in
|
|
77
|
+
* `squisq-proofing` frontmatter and is separate from this.
|
|
78
|
+
*/
|
|
79
|
+
interface ProofingPreferences {
|
|
80
|
+
/** Draw red squiggles under misspellings. */
|
|
81
|
+
spelling: boolean;
|
|
82
|
+
/** Draw green/blue squiggles under grammar and style findings. */
|
|
83
|
+
grammar: boolean;
|
|
84
|
+
}
|
|
85
|
+
declare const DEFAULT_PROOFING_PREFERENCES: Readonly<ProofingPreferences>;
|
|
86
|
+
declare function loadProofingPreferences(): ProofingPreferences;
|
|
87
|
+
declare function saveProofingPreferences(value: ProofingPreferences): void;
|
|
88
|
+
|
|
89
|
+
interface AiSettingsControlsProps {
|
|
90
|
+
ai: DocBlocksHostAiAPI;
|
|
91
|
+
}
|
|
92
|
+
declare function AiSettingsControls({ ai }: AiSettingsControlsProps): react_jsx_runtime.JSX.Element | null;
|
|
93
|
+
|
|
94
|
+
interface SettingsDialogProps {
|
|
95
|
+
title?: string;
|
|
96
|
+
onClose: () => void;
|
|
97
|
+
children: ReactNode;
|
|
98
|
+
}
|
|
99
|
+
declare function SettingsDialog({ title, onClose, children }: SettingsDialogProps): react_jsx_runtime.JSX.Element;
|
|
100
|
+
interface ThemeSettingsProps {
|
|
101
|
+
value: ThemePreference;
|
|
102
|
+
onChange: (theme: ThemePreference) => void;
|
|
103
|
+
name?: string;
|
|
104
|
+
}
|
|
105
|
+
declare function ThemeSettings({ value, onChange, name }: ThemeSettingsProps): react_jsx_runtime.JSX.Element;
|
|
106
|
+
interface InterfaceFontSettingsProps {
|
|
107
|
+
value: InterfaceFontPreference;
|
|
108
|
+
onChange: (font: InterfaceFontPreference) => void;
|
|
109
|
+
name?: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Choose the typeface for the app's own chrome, not for documents.
|
|
113
|
+
*
|
|
114
|
+
* The default follows the operating system, which is what almost everyone
|
|
115
|
+
* should keep. The bundled option exists for two reasons worth stating in the
|
|
116
|
+
* UI: identical typography across machines, and a rendering that is the same
|
|
117
|
+
* everywhere — which is what lets the visual-regression suite compare one set
|
|
118
|
+
* of baselines across operating systems at all.
|
|
119
|
+
*/
|
|
120
|
+
declare function InterfaceFontSettings({ value, onChange, name, }: InterfaceFontSettingsProps): react_jsx_runtime.JSX.Element;
|
|
121
|
+
interface AccentColorSettingsProps {
|
|
122
|
+
value: AccentColor;
|
|
123
|
+
onChange: (color: AccentColor) => void;
|
|
124
|
+
name?: string;
|
|
125
|
+
}
|
|
126
|
+
declare function AccentColorSettings({ value, onChange, name, }: AccentColorSettingsProps): react_jsx_runtime.JSX.Element;
|
|
127
|
+
interface ProofingSettingsControlsProps {
|
|
128
|
+
value: ProofingPreferences;
|
|
129
|
+
onChange: (settings: ProofingPreferences) => void;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Spelling and grammar squiggles, as two switches. Grammar is separable
|
|
133
|
+
* because harper's grammar rules are English-only — a writer working in
|
|
134
|
+
* another language wants the spell checker and none of the green
|
|
135
|
+
* underlines. With both off no checking engine is ever downloaded.
|
|
136
|
+
*/
|
|
137
|
+
declare function ProofingSettingsControls({ value, onChange }: ProofingSettingsControlsProps): react_jsx_runtime.JSX.Element;
|
|
138
|
+
interface WriteCanvasSettingsControlsProps {
|
|
139
|
+
value: WriteCanvasPreferences;
|
|
140
|
+
onChange: (settings: WriteCanvasPreferences) => void;
|
|
141
|
+
}
|
|
142
|
+
declare function WriteCanvasSettingsControls({ value, onChange }: WriteCanvasSettingsControlsProps): react_jsx_runtime.JSX.Element;
|
|
143
|
+
|
|
144
|
+
export { type AccentColor as A, DEFAULT_INTERFACE_FONT as D, type InterfaceFontPreference as I, type ProofingPreferences as P, SettingsDialog as S, type ThemePreference as T, WRITE_CANVAS_FONT_SCHEMES as W, AccentColorSettings as a, type AccentColorSettingsProps as b, AiSettingsControls as c, type AiSettingsControlsProps as d, DEFAULT_PROOFING_PREFERENCES as e, DEFAULT_WRITE_CANVAS_FONT_SCHEME as f, InterfaceFontSettings as g, type InterfaceFontSettingsProps as h, ProofingSettingsControls as i, type ProofingSettingsControlsProps as j, type SettingsDialogProps as k, ThemeSettings as l, type ThemeSettingsProps as m, type WriteCanvasFontScheme as n, type WriteCanvasFontSchemeGroup as o, type WriteCanvasFontSchemeOption as p, type WriteCanvasPreferences as q, WriteCanvasSettingsControls as r, type WriteCanvasSettingsControlsProps as s, loadInterfaceFont as t, loadProofingPreferences as u, resolveWriteCanvasFonts as v, saveInterfaceFont as w, saveProofingPreferences as x };
|