@bendyline/docblocks-react 2.7.0 → 2.7.2
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 +1 -1
- package/THIRD_PARTY_NOTICES.txt +98 -48
- package/dist/{AiDiagrams-XWOM3YZX.js → AiDiagrams-LFV4YU6W.js} +2 -2
- package/dist/{AiEditorAssistant-M4LI2CRY.js → AiEditorAssistant-GN2KXKZD.js} +21 -6
- package/dist/{ExportDialog-L6FG6W3H.js → ExportDialog-JRVZCG3J.js} +2 -2
- package/dist/{ExportToolbarControls-BRCPZ7H3.js → ExportToolbarControls-2FEIHNMW.js} +28 -18
- package/dist/{GitToolbarControl-J4UYZDV6.js → GitToolbarControl-B7KG4MFP.js} +4 -4
- package/dist/{GitUI-LZW3IUXO.js → GitUI-RCWUZVS6.js} +2 -2
- package/dist/KeyboardShortcutsDialog-NOD4P25G.js +145 -0
- package/dist/{PresentationMaker-622NHMIN.js → PresentationMaker-ITNP5SDO.js} +2 -2
- package/dist/{Settings-DuXk6baH.d.ts → Settings-RDYvDDI0.d.ts} +13 -11
- package/dist/ShareDialog-XUA2OVGI.js +292 -0
- package/dist/{SpeechToolbarControl-UZQKGQWD.js → SpeechToolbarControl-CLU7RB2G.js} +2 -2
- package/dist/{TextFromNarration-XYRAB6O2.js → TextFromNarration-NITJQ4IB.js} +1 -1
- package/dist/{WorkspaceSearchPanel-OUQQ5DOM.js → WorkspaceSearchPanel-J6BKEZQJ.js} +8 -2
- package/dist/{chunk-UG4G7PJ4.js → chunk-5O5YTOXG.js} +1 -1
- package/dist/{chunk-VO2JYYQZ.js → chunk-6JJOGV6M.js} +5 -13
- package/dist/{chunk-X437UAF7.js → chunk-6MSHXQNB.js} +7 -2
- package/dist/{chunk-Q5ZVP5LV.js → chunk-BLUEZG7T.js} +40 -32
- package/dist/chunk-DICE7VBJ.js +77 -0
- package/dist/{chunk-MRUK56JS.js → chunk-GMA4KGGO.js} +7 -3
- package/dist/{chunk-BCQZTWE5.js → chunk-HRWEGPTY.js} +18 -4
- package/dist/chunk-K7XJDJUJ.js +126 -0
- package/dist/{chunk-5OZBGIIT.js → chunk-NAH52736.js} +86 -28
- package/dist/{chunk-YS4HVWIO.js → chunk-SPUPWCSI.js} +49 -1
- package/dist/{chunk-MMOTEQK6.js → chunk-SSB43524.js} +165 -70
- package/dist/{chunk-G4MFB3IO.js → chunk-VG434562.js} +2 -70
- package/dist/{chunk-OINKNX26.js → chunk-X3DDTJKR.js} +1 -1
- package/dist/{chunk-SGQKTKDX.js → chunk-Y5OE3HJC.js} +14 -4
- package/dist/editor.js +7 -5
- package/dist/export/index.d.ts +17 -6
- package/dist/export/index.js +4 -4
- package/dist/index.d.ts +24 -6
- package/dist/index.js +452 -247
- package/dist/proofing/index.js +11 -1
- package/dist/run-export-CS3HRNAZ.js +13 -0
- package/dist/settings/index.d.ts +1 -1
- package/dist/settings/index.js +1 -1
- package/package.json +9 -8
- package/src/styles/docblocks.css +481 -271
- package/dist/ShareDialog-N7GPM4SB.js +0 -310
- package/dist/chunk-EA4BO6E4.js +0 -73
- package/dist/run-export-47X5FTYZ.js +0 -11
|
@@ -22,8 +22,56 @@ function sharedDocumentFilename(selectedFile) {
|
|
|
22
22
|
const bounded = stem.replace(/^-+|-+$/gu, "").slice(0, 80) || "shared";
|
|
23
23
|
return `${bounded}.md`;
|
|
24
24
|
}
|
|
25
|
+
async function omitSharedImages(markdown) {
|
|
26
|
+
const { parseMarkdown, rewriteMarkdownReferences, splitFrontmatterBlock, walkMarkdownTree } = await import("@bendyline/squisq/markdown");
|
|
27
|
+
const { frontmatter, body } = splitFrontmatterBlock(markdown);
|
|
28
|
+
const imageReferences = /* @__PURE__ */ new Set();
|
|
29
|
+
const linkReferences = /* @__PURE__ */ new Set();
|
|
30
|
+
walkMarkdownTree(parseMarkdown(body, { frontmatter: false }), (node) => {
|
|
31
|
+
if (node.type === "imageReference") imageReferences.add(node.identifier);
|
|
32
|
+
if (node.type === "linkReference") linkReferences.add(node.identifier);
|
|
33
|
+
});
|
|
34
|
+
let sharedBody = rewriteMarkdownReferences(body, { images: "omit" });
|
|
35
|
+
let sharedDocument = parseMarkdown(sharedBody, { frontmatter: false });
|
|
36
|
+
let descriptionContainsImage = false;
|
|
37
|
+
walkMarkdownTree(sharedDocument, (node) => {
|
|
38
|
+
if (node.type === "image" || node.type === "imageReference") descriptionContainsImage = true;
|
|
39
|
+
if (node.type === "imageReference") imageReferences.add(node.identifier);
|
|
40
|
+
if (node.type === "linkReference") linkReferences.add(node.identifier);
|
|
41
|
+
});
|
|
42
|
+
if (descriptionContainsImage) {
|
|
43
|
+
sharedBody = rewriteMarkdownReferences(sharedBody, { images: "omit" });
|
|
44
|
+
sharedDocument = parseMarkdown(sharedBody, { frontmatter: false });
|
|
45
|
+
walkMarkdownTree(sharedDocument, (node) => {
|
|
46
|
+
if (node.type === "image" || node.type === "imageReference") {
|
|
47
|
+
throw new Error(
|
|
48
|
+
"An image description contains image markup that cannot be shared as text."
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (imageReferences.size > 0) {
|
|
54
|
+
const removals = [];
|
|
55
|
+
walkMarkdownTree(sharedDocument, (node) => {
|
|
56
|
+
if (node.type !== "definition" || !imageReferences.has(node.identifier) || linkReferences.has(node.identifier)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const start = node.position?.start.offset;
|
|
60
|
+
const end = node.position?.end.offset;
|
|
61
|
+
if (start === void 0 || end === void 0) {
|
|
62
|
+
throw new Error("Cannot locate an image reference in the shared document.");
|
|
63
|
+
}
|
|
64
|
+
removals.push({ start, end });
|
|
65
|
+
});
|
|
66
|
+
for (const { start, end } of removals.sort((a, b) => b.start - a.start)) {
|
|
67
|
+
sharedBody = sharedBody.slice(0, start) + sharedBody.slice(end);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return (frontmatter ?? "") + sharedBody;
|
|
71
|
+
}
|
|
25
72
|
async function createSharedDocumentArchive(markdown, selectedFile) {
|
|
26
|
-
const
|
|
73
|
+
const sharedMarkdown = await omitSharedImages(markdown);
|
|
74
|
+
const encoded = new TextEncoder().encode(sharedMarkdown);
|
|
27
75
|
if (encoded.byteLength > SHARED_DOCUMENT_LIMITS.markdownBytes) {
|
|
28
76
|
throw new Error(
|
|
29
77
|
`This document is too large for a shared URL (maximum ${SHARED_DOCUMENT_LIMITS.markdownBytes.toLocaleString()} UTF-8 bytes).`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
chatOnce
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NAH52736.js";
|
|
4
4
|
import {
|
|
5
5
|
unavailableSentence,
|
|
6
6
|
useAiStatus
|
|
@@ -78,6 +78,7 @@ async function refinePresentationPlan(ai, plan, options = {}) {
|
|
|
78
78
|
const passage = plan.sourceText.slice(beat.sourceStart, beat.sourceEnd);
|
|
79
79
|
if (passage.length > 2400) {
|
|
80
80
|
retained++;
|
|
81
|
+
options.onBeat?.(index, null);
|
|
81
82
|
continue;
|
|
82
83
|
}
|
|
83
84
|
let replacement = null;
|
|
@@ -117,6 +118,7 @@ async function refinePresentationPlan(ai, plan, options = {}) {
|
|
|
117
118
|
beats[index] = replacement;
|
|
118
119
|
refined.push(index);
|
|
119
120
|
} else retained++;
|
|
121
|
+
options.onBeat?.(index, replacement);
|
|
120
122
|
}
|
|
121
123
|
options.onProgress?.(plan.beats.length, plan.beats.length);
|
|
122
124
|
return {
|
|
@@ -136,6 +138,26 @@ var LABELS = {
|
|
|
136
138
|
steps: "Steps diagram",
|
|
137
139
|
image: "Image"
|
|
138
140
|
};
|
|
141
|
+
function sectionAt(sections, offset) {
|
|
142
|
+
return sections.find((item) => offset >= item.sourceStart && offset < item.sourceEnd);
|
|
143
|
+
}
|
|
144
|
+
function withSuggestion(current, sections, sourceText, item) {
|
|
145
|
+
const parent = sectionAt(sections, item.sourceStart);
|
|
146
|
+
if (!parent) return current;
|
|
147
|
+
const source = sourceText.slice(item.sourceStart, item.sourceEnd);
|
|
148
|
+
const existing = current.blocks.find((block) => block.blockId === parent.blockId);
|
|
149
|
+
const target = {
|
|
150
|
+
...existing ?? { blockId: parent.blockId },
|
|
151
|
+
ai: [
|
|
152
|
+
...(existing?.ai ?? []).filter((entry) => entry.source !== source),
|
|
153
|
+
{ source, layout: item.layout, headline: item.headline, points: [...item.points] }
|
|
154
|
+
].slice(-80)
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
...current,
|
|
158
|
+
blocks: [...current.blocks.filter((block) => block.blockId !== parent.blockId), target]
|
|
159
|
+
};
|
|
160
|
+
}
|
|
139
161
|
function PresentationMaker({
|
|
140
162
|
ai,
|
|
141
163
|
onClose
|
|
@@ -145,6 +167,7 @@ function PresentationMaker({
|
|
|
145
167
|
function AiRefineButton({
|
|
146
168
|
ai,
|
|
147
169
|
disabled,
|
|
170
|
+
buttonRef,
|
|
148
171
|
onRefine
|
|
149
172
|
}) {
|
|
150
173
|
const status = useAiStatus(ai);
|
|
@@ -152,6 +175,7 @@ function AiRefineButton({
|
|
|
152
175
|
return /* @__PURE__ */ jsx(
|
|
153
176
|
"button",
|
|
154
177
|
{
|
|
178
|
+
ref: buttonRef,
|
|
155
179
|
type: "button",
|
|
156
180
|
disabled: disabled || !ready,
|
|
157
181
|
title: ready ? "Suggest layouts and shorter slide wording from the current text." : unavailableSentence(status),
|
|
@@ -173,6 +197,9 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
173
197
|
const [notice, setNotice] = useState("");
|
|
174
198
|
const [progress, setProgress] = useState(null);
|
|
175
199
|
const controller = useRef(null);
|
|
200
|
+
const follow = useRef(false);
|
|
201
|
+
const suggestButton = useRef(null);
|
|
202
|
+
const stopButton = useRef(null);
|
|
176
203
|
useEffect(() => {
|
|
177
204
|
let disposed = false;
|
|
178
205
|
const parsed = markdownToDoc(parseMarkdown(markdownSource));
|
|
@@ -187,6 +214,14 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
187
214
|
controller.current?.abort();
|
|
188
215
|
};
|
|
189
216
|
}, [markdownSource, workspaceContainer]);
|
|
217
|
+
const running = progress !== null;
|
|
218
|
+
const wasRunning = useRef(false);
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
if (wasRunning.current === running) return;
|
|
221
|
+
wasRunning.current = running;
|
|
222
|
+
if (document.activeElement === null || document.activeElement === document.body)
|
|
223
|
+
(running ? stopButton.current : suggestButton.current)?.focus();
|
|
224
|
+
}, [running]);
|
|
190
225
|
const doc = loaded?.source === markdownSource ? loaded.doc : null;
|
|
191
226
|
const generated = useMemo(() => {
|
|
192
227
|
if (!doc) return null;
|
|
@@ -219,6 +254,15 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
219
254
|
};
|
|
220
255
|
}
|
|
221
256
|
}, [doc, plan, preview?.activeTheme]);
|
|
257
|
+
const aiEntries = useMemo(() => {
|
|
258
|
+
const entries = /* @__PURE__ */ new Map();
|
|
259
|
+
for (const block of hints.blocks)
|
|
260
|
+
entries.set(
|
|
261
|
+
block.blockId,
|
|
262
|
+
new Map((block.ai ?? []).map((entry) => [entry.source, entry.layout]))
|
|
263
|
+
);
|
|
264
|
+
return entries;
|
|
265
|
+
}, [hints]);
|
|
222
266
|
const selectedIndex = Math.max(
|
|
223
267
|
0,
|
|
224
268
|
plan?.beats.findIndex(
|
|
@@ -226,9 +270,7 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
226
270
|
) ?? -1
|
|
227
271
|
);
|
|
228
272
|
const beat = plan?.beats[selectedIndex];
|
|
229
|
-
const section = sections.
|
|
230
|
-
(item) => beat && beat.sourceStart >= item.sourceStart && beat.sourceStart < item.sourceEnd
|
|
231
|
-
);
|
|
273
|
+
const section = beat && sectionAt(sections, beat.sourceStart);
|
|
232
274
|
const hint = hints.blocks.find((item) => item.blockId === section?.blockId);
|
|
233
275
|
const visual = projection?.blocks.find((block) => block.id === beat?.id);
|
|
234
276
|
const updateHint = (patch) => {
|
|
@@ -250,52 +292,47 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
250
292
|
setHints(next);
|
|
251
293
|
};
|
|
252
294
|
const refine = async () => {
|
|
253
|
-
if (!ai || !plan ||
|
|
295
|
+
if (!ai || !plan || controller.current) return;
|
|
254
296
|
const run = new AbortController();
|
|
255
297
|
controller.current = run;
|
|
298
|
+
follow.current = true;
|
|
299
|
+
const total = plan.beats.length;
|
|
300
|
+
const outcome = { done: 0, refined: 0, retained: 0 };
|
|
256
301
|
setError(null);
|
|
257
302
|
setNotice("");
|
|
258
303
|
try {
|
|
259
|
-
|
|
304
|
+
await refinePresentationPlan(ai, plan, {
|
|
260
305
|
signal: run.signal,
|
|
261
|
-
onProgress: (done
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
})
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
target = { blockId: parent.blockId, ai: void 0 };
|
|
278
|
-
blocks.push(target);
|
|
279
|
-
}
|
|
280
|
-
const source = plan.sourceText.slice(item.sourceStart, item.sourceEnd);
|
|
281
|
-
target.ai = [
|
|
282
|
-
...(target.ai ?? []).filter((v) => v.source !== source),
|
|
283
|
-
{
|
|
284
|
-
source,
|
|
285
|
-
layout: item.layout,
|
|
286
|
-
headline: item.headline,
|
|
287
|
-
points: item.points
|
|
288
|
-
}
|
|
289
|
-
].slice(-80);
|
|
306
|
+
onProgress: (done) => {
|
|
307
|
+
outcome.done = done;
|
|
308
|
+
const next = plan.beats[done];
|
|
309
|
+
setProgress({
|
|
310
|
+
done,
|
|
311
|
+
total,
|
|
312
|
+
active: next ? { sourceStart: next.sourceStart, sourceEnd: next.sourceEnd } : null
|
|
313
|
+
});
|
|
314
|
+
if (next && follow.current) setSelectedSourceStart(next.sourceStart);
|
|
315
|
+
},
|
|
316
|
+
// Each accepted slide reaches the list and preview as soon as it
|
|
317
|
+
// resolves, so stopping early keeps everything suggested so far.
|
|
318
|
+
onBeat: (_index, item) => {
|
|
319
|
+
if (!item) {
|
|
320
|
+
outcome.retained++;
|
|
321
|
+
return;
|
|
290
322
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
323
|
+
outcome.refined++;
|
|
324
|
+
setHints((current) => withSuggestion(current, sections, plan.sourceText, item));
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
setNotice(
|
|
328
|
+
outcome.retained ? `Kept automatic summaries for ${outcome.retained} slides because the AI suggestions could not be validated.` : "AI summaries are ready to review. They will be saved with their source passages."
|
|
329
|
+
);
|
|
297
330
|
} catch (cause) {
|
|
298
331
|
if (!run.signal.aborted) setError(cause instanceof Error ? cause.message : String(cause));
|
|
332
|
+
else if (controller.current === run)
|
|
333
|
+
setNotice(
|
|
334
|
+
`Stopped after ${outcome.done} of ${total} slides. ${outcome.refined === 0 ? "No slides changed." : outcome.refined === 1 ? "The one AI suggestion is kept." : `The ${outcome.refined} AI suggestions are kept.`}`
|
|
335
|
+
);
|
|
299
336
|
} finally {
|
|
300
337
|
if (controller.current === run) {
|
|
301
338
|
controller.current = null;
|
|
@@ -304,7 +341,7 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
304
341
|
}
|
|
305
342
|
};
|
|
306
343
|
const apply = () => {
|
|
307
|
-
if (!doc || !plan ||
|
|
344
|
+
if (!doc || !plan || running) return;
|
|
308
345
|
try {
|
|
309
346
|
const next = setFrontmatterValues(markdownSource, {
|
|
310
347
|
[PRESENTATION_HINTS_KEY]: serializePresentationHints(hints),
|
|
@@ -328,10 +365,11 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
328
365
|
onClose,
|
|
329
366
|
closeOnBackdrop: false,
|
|
330
367
|
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
331
|
-
|
|
368
|
+
/* @__PURE__ */ jsx(
|
|
332
369
|
"button",
|
|
333
370
|
{
|
|
334
371
|
type: "button",
|
|
372
|
+
disabled: running,
|
|
335
373
|
onClick: () => {
|
|
336
374
|
setHints(defaultPresentationHints());
|
|
337
375
|
setSelectedSourceStart(0);
|
|
@@ -341,8 +379,46 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
341
379
|
children: "Reset design"
|
|
342
380
|
}
|
|
343
381
|
),
|
|
344
|
-
ai && /* @__PURE__ */ jsx(
|
|
345
|
-
|
|
382
|
+
ai && !progress && /* @__PURE__ */ jsx(
|
|
383
|
+
AiRefineButton,
|
|
384
|
+
{
|
|
385
|
+
ai,
|
|
386
|
+
buttonRef: suggestButton,
|
|
387
|
+
disabled: !plan,
|
|
388
|
+
onRefine: () => void refine()
|
|
389
|
+
}
|
|
390
|
+
),
|
|
391
|
+
ai && progress && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
392
|
+
/* @__PURE__ */ jsxs("div", { className: "db-presentation-progress", role: "status", children: [
|
|
393
|
+
/* @__PURE__ */ jsx("span", { className: "db-ai-spinner", "aria-hidden": "true" }),
|
|
394
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
395
|
+
"Suggesting slide ",
|
|
396
|
+
Math.min(progress.done + 1, progress.total),
|
|
397
|
+
" of ",
|
|
398
|
+
progress.total,
|
|
399
|
+
"\u2026"
|
|
400
|
+
] }),
|
|
401
|
+
/* @__PURE__ */ jsx(
|
|
402
|
+
"progress",
|
|
403
|
+
{
|
|
404
|
+
max: progress.total,
|
|
405
|
+
value: progress.done,
|
|
406
|
+
"aria-label": "Slides suggested so far"
|
|
407
|
+
}
|
|
408
|
+
)
|
|
409
|
+
] }),
|
|
410
|
+
/* @__PURE__ */ jsx(
|
|
411
|
+
"button",
|
|
412
|
+
{
|
|
413
|
+
ref: stopButton,
|
|
414
|
+
type: "button",
|
|
415
|
+
title: "Stop suggesting. Slides already suggested keep their new wording.",
|
|
416
|
+
onClick: () => controller.current?.abort(),
|
|
417
|
+
children: "Stop"
|
|
418
|
+
}
|
|
419
|
+
)
|
|
420
|
+
] }),
|
|
421
|
+
/* @__PURE__ */ jsx("button", { type: "button", disabled: !plan || running || !!error, onClick: apply, children: "Use dynamic slides" })
|
|
346
422
|
] }),
|
|
347
423
|
children: [
|
|
348
424
|
/* @__PURE__ */ jsx("p", { className: "db-presentation-intro", children: "Design how your text is summarized for presentation in slides and video. Note that your document text and narration will remain unchanged." }),
|
|
@@ -353,7 +429,7 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
353
429
|
"select",
|
|
354
430
|
{
|
|
355
431
|
value: hints.density,
|
|
356
|
-
disabled:
|
|
432
|
+
disabled: running,
|
|
357
433
|
onChange: (event) => setHints({ ...hints, density: event.target.value }),
|
|
358
434
|
children: [
|
|
359
435
|
/* @__PURE__ */ jsx("option", { value: "concise", children: "Concise \u2014 shorter passages per slide" }),
|
|
@@ -369,7 +445,7 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
369
445
|
{
|
|
370
446
|
type: "checkbox",
|
|
371
447
|
checked: hints.inbetweens,
|
|
372
|
-
disabled:
|
|
448
|
+
disabled: running,
|
|
373
449
|
onChange: (event) => setHints({ ...hints, inbetweens: event.target.checked })
|
|
374
450
|
}
|
|
375
451
|
),
|
|
@@ -377,28 +453,47 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
377
453
|
"Add supporting visual slides where useful"
|
|
378
454
|
] })
|
|
379
455
|
] }),
|
|
380
|
-
/* @__PURE__ */ jsx("p", { role: "status", "aria-live": "polite", children:
|
|
456
|
+
/* @__PURE__ */ jsx("p", { role: "status", "aria-live": "polite", children: plan && projection?.doc ? `${plan.beats.length} slides \xB7 ${projection.doc.duration.toFixed(1)} seconds \xB7 ${doc?.presentationNarration ? "Follows narration" : "Estimated pacing \u2014 add narration to synchronize"}` : "Preparing dynamic slides\u2026" }),
|
|
381
457
|
(error || generated?.error || projection?.error) && /* @__PURE__ */ jsx("p", { role: "alert", children: error ?? generated?.error ?? projection?.error }),
|
|
382
458
|
notice && /* @__PURE__ */ jsx("p", { role: "status", children: notice }),
|
|
383
459
|
plan && beat && section && /* @__PURE__ */ jsxs("div", { className: "db-presentation-workspace", children: [
|
|
384
|
-
/* @__PURE__ */ jsx("nav", { className: "db-presentation-beats", "aria-label": "Presentation slides", children: plan.beats.map((item, index) =>
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
460
|
+
/* @__PURE__ */ jsx("nav", { className: "db-presentation-beats", "aria-label": "Presentation slides", children: plan.beats.map((item, index) => {
|
|
461
|
+
const owner = sectionAt(sections, item.sourceStart);
|
|
462
|
+
const layout = owner && aiEntries.get(owner.blockId)?.get(plan.sourceText.slice(item.sourceStart, item.sourceEnd));
|
|
463
|
+
const suggested = layout !== void 0 && (layout !== "image" || !!item.imageSrc);
|
|
464
|
+
const active = progress?.active;
|
|
465
|
+
const pending = !!active && active.sourceStart === item.sourceStart && active.sourceEnd === item.sourceEnd;
|
|
466
|
+
return /* @__PURE__ */ jsxs(
|
|
467
|
+
"button",
|
|
468
|
+
{
|
|
469
|
+
type: "button",
|
|
470
|
+
"aria-current": index === selectedIndex ? "step" : void 0,
|
|
471
|
+
title: item.headline,
|
|
472
|
+
onClick: () => {
|
|
473
|
+
follow.current = false;
|
|
474
|
+
setSelectedSourceStart(item.sourceStart);
|
|
475
|
+
},
|
|
476
|
+
children: [
|
|
477
|
+
/* @__PURE__ */ jsxs("span", { className: "db-presentation-beat-title", children: [
|
|
478
|
+
index + 1,
|
|
479
|
+
". ",
|
|
480
|
+
item.headline
|
|
481
|
+
] }),
|
|
482
|
+
/* @__PURE__ */ jsxs("span", { className: "db-presentation-beat-tags", children: [
|
|
483
|
+
/* @__PURE__ */ jsx("small", { children: LABELS[item.layout] }),
|
|
484
|
+
pending ? /* @__PURE__ */ jsxs("small", { className: "db-presentation-beat-ai", children: [
|
|
485
|
+
/* @__PURE__ */ jsx("span", { className: "db-ai-spinner", "aria-hidden": "true" }),
|
|
486
|
+
"Suggesting\u2026"
|
|
487
|
+
] }) : suggested ? /* @__PURE__ */ jsxs("small", { className: "db-presentation-beat-ai", children: [
|
|
488
|
+
/* @__PURE__ */ jsx("span", { className: "db-visually-hidden", children: "Suggested by " }),
|
|
489
|
+
"AI"
|
|
490
|
+
] }) : null
|
|
491
|
+
] })
|
|
492
|
+
]
|
|
493
|
+
},
|
|
494
|
+
item.id
|
|
495
|
+
);
|
|
496
|
+
}) }),
|
|
402
497
|
/* @__PURE__ */ jsxs("div", { className: "db-presentation-detail", children: [
|
|
403
498
|
/* @__PURE__ */ jsx(
|
|
404
499
|
"div",
|
|
@@ -425,7 +520,7 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
425
520
|
"select",
|
|
426
521
|
{
|
|
427
522
|
value: hint?.layout ?? "",
|
|
428
|
-
disabled:
|
|
523
|
+
disabled: running,
|
|
429
524
|
onChange: (event) => updateHint({
|
|
430
525
|
layout: event.target.value || void 0
|
|
431
526
|
}),
|
|
@@ -444,7 +539,7 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
444
539
|
"select",
|
|
445
540
|
{
|
|
446
541
|
value: hint?.inbetweens === void 0 ? "" : String(hint.inbetweens),
|
|
447
|
-
disabled:
|
|
542
|
+
disabled: running,
|
|
448
543
|
onChange: (event) => updateHint({
|
|
449
544
|
inbetweens: event.target.value === "" ? void 0 : event.target.value === "true"
|
|
450
545
|
}),
|
|
@@ -474,7 +569,7 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
474
569
|
{
|
|
475
570
|
defaultValue: beat.headline,
|
|
476
571
|
maxLength: 110,
|
|
477
|
-
disabled:
|
|
572
|
+
disabled: running,
|
|
478
573
|
onBlur: (event) => updateHint({
|
|
479
574
|
wording: {
|
|
480
575
|
...hint?.wording?.source === section.text ? hint.wording : {},
|
|
@@ -493,7 +588,7 @@ function PresentationDialog({ ai, onClose }) {
|
|
|
493
588
|
{
|
|
494
589
|
rows: 3,
|
|
495
590
|
defaultValue: beat.points.join("\n"),
|
|
496
|
-
disabled:
|
|
591
|
+
disabled: running,
|
|
497
592
|
onBlur: (event) => updateHint({
|
|
498
593
|
wording: {
|
|
499
594
|
...hint?.wording?.source === section.text ? hint.wording : {},
|
|
@@ -3,8 +3,8 @@ import { useEffect, useState } from "react";
|
|
|
3
3
|
|
|
4
4
|
// src/components/FindButton.tsx
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
-
function FindButton({ active, onActiveChange, shortcutLabel
|
|
7
|
-
const tooltip =
|
|
6
|
+
function FindButton({ active, onActiveChange, shortcutLabel }) {
|
|
7
|
+
const tooltip = shortcutLabel ? `Find in document (${shortcutLabel})` : "Find in document";
|
|
8
8
|
return /* @__PURE__ */ jsx(
|
|
9
9
|
"button",
|
|
10
10
|
{
|
|
@@ -45,69 +45,6 @@ function focusFindInput(scope = document) {
|
|
|
45
45
|
input?.select();
|
|
46
46
|
}
|
|
47
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
48
|
// src/editor.ts
|
|
112
49
|
var PORTRAIT_FORM_FACTOR_QUERY = "(orientation: portrait)";
|
|
113
50
|
function previewViewportPresetForOrientation(isPortrait) {
|
|
@@ -195,11 +132,6 @@ function pickEmptyDocumentPrompt(random = Math.random) {
|
|
|
195
132
|
export {
|
|
196
133
|
FindButton,
|
|
197
134
|
focusFindInput,
|
|
198
|
-
matchShortcut,
|
|
199
|
-
isFindShortcut,
|
|
200
|
-
findShortcutLabel,
|
|
201
|
-
isApplePlatform,
|
|
202
|
-
shortcutLabel,
|
|
203
135
|
PORTRAIT_FORM_FACTOR_QUERY,
|
|
204
136
|
previewViewportPresetForOrientation,
|
|
205
137
|
useResponsivePreviewViewportPreset,
|
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
} from "./chunk-YBEYTVU2.js";
|
|
4
4
|
import {
|
|
5
5
|
FORMAT_LABELS,
|
|
6
|
+
exportThemeChoices,
|
|
6
7
|
saveExportOptions
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6MSHXQNB.js";
|
|
8
9
|
import {
|
|
9
10
|
Dialog
|
|
10
11
|
} from "./chunk-56KO2LYN.js";
|
|
11
12
|
|
|
12
13
|
// src/Export/ExportDialog.tsx
|
|
13
14
|
import { useState, useCallback, useEffect, useMemo } from "react";
|
|
14
|
-
import { getThemeSummaries } from "@bendyline/squisq/schemas";
|
|
15
15
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
16
16
|
var FORMATS = ["pdf", "docx", "pptx", "epub", "html", "md"];
|
|
17
17
|
var FORMAT_CHIP_LABELS = {
|
|
@@ -52,7 +52,7 @@ function ChipRadioGroup({
|
|
|
52
52
|
options,
|
|
53
53
|
onChange
|
|
54
54
|
}) {
|
|
55
|
-
return /* @__PURE__ */ jsx("div", { className: "db-export-chips", role: "radiogroup", "aria-label": name, children: options.map((opt) => {
|
|
55
|
+
return /* @__PURE__ */ jsx("div", { className: "db-export-chips", role: "radiogroup", "aria-label": name, children: options.map((opt, index) => {
|
|
56
56
|
const active = opt.key === value;
|
|
57
57
|
return /* @__PURE__ */ jsx(
|
|
58
58
|
"button",
|
|
@@ -60,8 +60,17 @@ function ChipRadioGroup({
|
|
|
60
60
|
type: "button",
|
|
61
61
|
role: "radio",
|
|
62
62
|
"aria-checked": active,
|
|
63
|
+
tabIndex: active ? 0 : -1,
|
|
63
64
|
className: `db-export-chip${active ? " db-export-chip--active" : ""}`,
|
|
64
65
|
onClick: () => onChange(opt.key),
|
|
66
|
+
onKeyDown: (event) => {
|
|
67
|
+
const delta = event.key === "ArrowRight" || event.key === "ArrowDown" ? 1 : event.key === "ArrowLeft" || event.key === "ArrowUp" ? -1 : 0;
|
|
68
|
+
if (!delta) return;
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
const next = (index + delta + options.length) % options.length;
|
|
71
|
+
onChange(options[next].key);
|
|
72
|
+
event.currentTarget.parentElement?.querySelectorAll('[role="radio"]')[next]?.focus();
|
|
73
|
+
},
|
|
65
74
|
title: opt.title,
|
|
66
75
|
children: opt.label
|
|
67
76
|
},
|
|
@@ -71,6 +80,7 @@ function ChipRadioGroup({
|
|
|
71
80
|
}
|
|
72
81
|
function ExportDialog({
|
|
73
82
|
initial,
|
|
83
|
+
documentThemes,
|
|
74
84
|
exporting,
|
|
75
85
|
error,
|
|
76
86
|
destination,
|
|
@@ -88,7 +98,7 @@ function ExportDialog({
|
|
|
88
98
|
const [includeLinkedDocs, setIncludeLinkedDocs] = useState(initial.includeLinkedDocs);
|
|
89
99
|
const [entryAsIndex, setEntryAsIndex] = useState(initial.entryAsIndex);
|
|
90
100
|
const [transforms, setTransforms] = useState([]);
|
|
91
|
-
const themes =
|
|
101
|
+
const themes = useMemo(() => exportThemeChoices(documentThemes), [documentThemes]);
|
|
92
102
|
const showTheme = format === "docx" || format === "pdf" || format === "pptx" || format === "epub" || format === "html";
|
|
93
103
|
const showTransform = format === "pptx";
|
|
94
104
|
const showPageSize = format === "pdf";
|
package/dist/editor.js
CHANGED
|
@@ -2,17 +2,19 @@ import {
|
|
|
2
2
|
EMPTY_DOCUMENT_PROMPTS,
|
|
3
3
|
FindButton,
|
|
4
4
|
PORTRAIT_FORM_FACTOR_QUERY,
|
|
5
|
-
findShortcutLabel,
|
|
6
5
|
focusFindInput,
|
|
7
|
-
isFindShortcut,
|
|
8
6
|
pickEmptyDocumentPrompt,
|
|
9
7
|
previewViewportPresetForOrientation,
|
|
10
8
|
useResponsivePreviewViewportPreset
|
|
11
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VG434562.js";
|
|
10
|
+
import {
|
|
11
|
+
findShortcutLabel,
|
|
12
|
+
isFindShortcut
|
|
13
|
+
} from "./chunk-K7XJDJUJ.js";
|
|
12
14
|
import {
|
|
13
15
|
PresentationMaker
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-SSB43524.js";
|
|
17
|
+
import "./chunk-NAH52736.js";
|
|
16
18
|
import "./chunk-K4I3NJFL.js";
|
|
17
19
|
import "./chunk-56KO2LYN.js";
|
|
18
20
|
export {
|