@bendyline/docblocks-react 2.2.1 → 2.2.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.
@@ -1,3 +1,6 @@
1
+ import {
2
+ useMenuKeyboard
3
+ } from "./chunk-MRUK56JS.js";
1
4
  import {
2
5
  loadTransformStyleSummaries
3
6
  } from "./chunk-YBEYTVU2.js";
@@ -36,6 +39,8 @@ function loadRunExportModule() {
36
39
  runExportModulePromise ?? (runExportModulePromise = import("./run-export-Z5BVFLIR.js"));
37
40
  return runExportModulePromise;
38
41
  }
42
+ var ExportCancelledError = class extends Error {
43
+ };
39
44
  var SHARED_USE_MODES = Object.freeze({
40
45
  slideshow: "slideshow",
41
46
  video: "video",
@@ -69,10 +74,10 @@ function loadVideoExportModules() {
69
74
  return videoExportModulesPromise;
70
75
  }
71
76
  function exportErrorMessage(caught) {
72
- const detail = caught instanceof Error ? caught.message.trim() : "";
77
+ const detail = caught instanceof Error ? caught.message.replace(/^Error invoking remote method '[^']+': Error:\s*/, "").trim() : "";
73
78
  return detail ? `Export failed: ${detail}` : "Export failed. The document could not be exported.";
74
79
  }
75
- function quickLabel(opts, transformSummaries) {
80
+ function quickLabel(opts, transformSummaries, destinationPath) {
76
81
  const baseExt = FORMAT_EXTENSIONS[opts.format].toUpperCase().replace(".", "");
77
82
  const isRecursiveHtml = opts.format === "html" && opts.includeLinkedDocs;
78
83
  const ext = opts.format === "html" && (opts.htmlBundle === "zip" || isRecursiveHtml) ? "ZIP" : baseExt;
@@ -92,9 +97,11 @@ function quickLabel(opts, transformSummaries) {
92
97
  if (transform) parts.push(transform.name);
93
98
  }
94
99
  if (parts.length > 0) {
95
- return `Export ${ext} with ${parts.join(" + ")}`;
100
+ const label2 = `Export ${ext} with ${parts.join(" + ")}`;
101
+ return destinationPath ? `${label2} to ${destinationPath}` : label2;
96
102
  }
97
- return `Export ${ext}`;
103
+ const label = `Export ${ext}`;
104
+ return destinationPath ? `${label} to ${destinationPath}` : label;
98
105
  }
99
106
  function ExportToolbarControls({
100
107
  selectedFile,
@@ -123,9 +130,14 @@ function ExportToolbarControls({
123
130
  const [exporting, setExporting] = useState(false);
124
131
  const [exportError, setExportError] = useState(null);
125
132
  const [destinationTarget, setDestinationTarget] = useState(null);
133
+ const [quickDestination, setQuickDestination] = useState(null);
134
+ const [quickDestinationPending, setQuickDestinationPending] = useState(false);
126
135
  const destinationRequestRef = useRef(0);
127
- const menuRef = useRef(null);
136
+ const menuContainerRef = useRef(null);
137
+ const { menuRef, triggerRef, handleMenuKeyDown, handleTriggerKeyDown, closeMenu } = useMenuKeyboard(menuOpen, setMenuOpen);
128
138
  const lastOptions = loadLastExportOptions();
139
+ const quickDestinationKey = lastOptions ? JSON.stringify([selectedFile, lastOptions]) : null;
140
+ const quickDestinationTarget = quickDestination?.key === quickDestinationKey ? quickDestination.target : null;
129
141
  const docThemeId = useMemo(() => {
130
142
  const fm = markdownDoc?.frontmatter;
131
143
  if (!fm) return null;
@@ -142,12 +154,17 @@ function ExportToolbarControls({
142
154
  useEffect(() => {
143
155
  if (!menuOpen) return;
144
156
  const onPointerDown = (e) => {
145
- if (menuRef.current && !menuRef.current.contains(e.target)) {
146
- setMenuOpen(false);
157
+ if (menuContainerRef.current && !menuContainerRef.current.contains(e.target)) {
158
+ closeMenu(false);
147
159
  }
148
160
  };
149
161
  document.addEventListener("pointerdown", onPointerDown);
150
162
  return () => document.removeEventListener("pointerdown", onPointerDown);
163
+ }, [closeMenu, menuOpen]);
164
+ useEffect(() => {
165
+ if (menuOpen) return;
166
+ setQuickDestination(null);
167
+ setQuickDestinationPending(false);
151
168
  }, [menuOpen]);
152
169
  useEffect(() => {
153
170
  if (!menuOpen || lastOptions?.format !== "pptx" || !lastOptions.transformStyle || transformSummaries.length > 0) {
@@ -163,9 +180,33 @@ function ExportToolbarControls({
163
180
  cancelled = true;
164
181
  };
165
182
  }, [lastOptions?.format, lastOptions?.transformStyle, menuOpen, transformSummaries.length]);
183
+ useEffect(() => {
184
+ if (!menuOpen || !destinationAdapter || !quickDestinationKey) return;
185
+ const quickOptions = loadLastExportOptions();
186
+ if (!quickOptions) return;
187
+ let cancelled = false;
188
+ setQuickDestination(null);
189
+ setQuickDestinationPending(true);
190
+ void loadRunExportModule().then(
191
+ ({ buildExportFilename }) => destinationAdapter.resolveTarget(buildExportFilename(selectedFile, quickOptions))
192
+ ).then((target) => {
193
+ if (!cancelled) setQuickDestination({ key: quickDestinationKey, target });
194
+ }).catch(() => {
195
+ if (!cancelled) setQuickDestination(null);
196
+ }).finally(() => {
197
+ if (!cancelled) setQuickDestinationPending(false);
198
+ });
199
+ return () => {
200
+ cancelled = true;
201
+ };
202
+ }, [destinationAdapter, menuOpen, quickDestinationKey, selectedFile]);
166
203
  const handleToggleMenu = useCallback(() => {
204
+ if (!menuOpen && destinationAdapter) {
205
+ setQuickDestination(null);
206
+ setQuickDestinationPending(true);
207
+ }
167
208
  setMenuOpen((prev) => !prev);
168
- }, []);
209
+ }, [destinationAdapter, menuOpen]);
169
210
  const refreshDestination = useCallback(
170
211
  async (options) => {
171
212
  if (!destinationAdapter) return;
@@ -245,6 +286,7 @@ function ExportToolbarControls({
245
286
  const pickedTarget = await destinationAdapter.pickTarget(filename, destinationTarget);
246
287
  if (pickedTarget === null) return;
247
288
  setDestinationTarget(pickedTarget);
289
+ setQuickDestination(null);
248
290
  } catch {
249
291
  }
250
292
  },
@@ -254,7 +296,8 @@ function ExportToolbarControls({
254
296
  async (blob, filename, target) => {
255
297
  if (!destinationAdapter) return;
256
298
  const savedTarget = await destinationAdapter.saveBlob(blob, filename, target);
257
- if (savedTarget) setDestinationTarget(savedTarget);
299
+ if (!savedTarget) throw new ExportCancelledError();
300
+ setDestinationTarget(savedTarget);
258
301
  },
259
302
  [destinationAdapter]
260
303
  );
@@ -279,7 +322,7 @@ function ExportToolbarControls({
279
322
  );
280
323
  setDialogOpen(false);
281
324
  } catch (caught) {
282
- setExportError(exportErrorMessage(caught));
325
+ if (!(caught instanceof ExportCancelledError)) setExportError(exportErrorMessage(caught));
283
326
  } finally {
284
327
  setExporting(false);
285
328
  }
@@ -303,10 +346,8 @@ function ExportToolbarControls({
303
346
  const { runExport } = await loadRunExportModule();
304
347
  let quickTarget = null;
305
348
  if (destinationAdapter) {
306
- const { buildExportFilename } = await loadRunExportModule();
307
- quickTarget = await destinationAdapter.resolveTarget(
308
- buildExportFilename(selectedFile, lastOptions)
309
- );
349
+ if (!quickDestinationTarget) return;
350
+ quickTarget = quickDestinationTarget;
310
351
  }
311
352
  await runExport(
312
353
  markdownSource,
@@ -316,7 +357,7 @@ function ExportToolbarControls({
316
357
  destinationAdapter ? async (blob, filename) => saveToDestination(blob, filename, quickTarget) : saveBlob
317
358
  );
318
359
  } catch (caught) {
319
- setExportError(exportErrorMessage(caught));
360
+ if (!(caught instanceof ExportCancelledError)) setExportError(exportErrorMessage(caught));
320
361
  } finally {
321
362
  setExporting(false);
322
363
  }
@@ -327,7 +368,8 @@ function ExportToolbarControls({
327
368
  mediaContainer,
328
369
  saveBlob,
329
370
  saveToDestination,
330
- selectedFile
371
+ selectedFile,
372
+ quickDestinationTarget
331
373
  ]);
332
374
  const handleDismissExportError = useCallback(() => {
333
375
  setExportError(null);
@@ -347,13 +389,15 @@ function ExportToolbarControls({
347
389
  "data-tooltip": exporting ? "Exporting..." : "Export document",
348
390
  children: /* @__PURE__ */ jsx(ExportGlyph, {})
349
391
  }
350
- ) : /* @__PURE__ */ jsxs("div", { className: "db-toolbar-menu", ref: menuRef, children: [
392
+ ) : /* @__PURE__ */ jsxs("div", { className: "db-toolbar-menu", ref: menuContainerRef, children: [
351
393
  /* @__PURE__ */ jsxs(
352
394
  "button",
353
395
  {
396
+ ref: triggerRef,
354
397
  type: "button",
355
398
  className: "db-toolbar-menu-trigger",
356
399
  onClick: handleToggleMenu,
400
+ onKeyDown: handleTriggerKeyDown,
357
401
  "aria-label": "Export and share",
358
402
  "aria-haspopup": "menu",
359
403
  "aria-expanded": menuOpen,
@@ -364,62 +408,85 @@ function ExportToolbarControls({
364
408
  ]
365
409
  }
366
410
  ),
367
- menuOpen && /* @__PURE__ */ jsxs("div", { className: "db-toolbar-menu-dropdown", role: "menu", children: [
368
- lastOptions && /* @__PURE__ */ jsx(
369
- "button",
370
- {
371
- type: "button",
372
- role: "menuitem",
373
- className: "db-toolbar-menu-item",
374
- onClick: handleQuickExport,
375
- disabled: exporting,
376
- children: quickLabel(lastOptions, transformSummaries)
377
- }
378
- ),
379
- /* @__PURE__ */ jsx(
380
- "button",
381
- {
382
- type: "button",
383
- role: "menuitem",
384
- className: "db-toolbar-menu-item",
385
- onClick: handleOpenDialog,
386
- children: "Export..."
387
- }
388
- ),
389
- /* @__PURE__ */ jsx(
390
- "button",
391
- {
392
- type: "button",
393
- role: "menuitem",
394
- className: "db-toolbar-menu-item",
395
- onClick: handleOpenShareDialog,
396
- children: "Share link with content embedded..."
397
- }
398
- ),
399
- showVideoExport && /* @__PURE__ */ jsxs(Fragment, { children: [
400
- /* @__PURE__ */ jsx("div", { className: "db-toolbar-menu-divider", role: "separator" }),
401
- /* @__PURE__ */ jsx(
402
- "button",
403
- {
404
- type: "button",
405
- role: "menuitem",
406
- className: "db-toolbar-menu-item",
407
- onClick: () => void handleOpenVideoModal("mp4"),
408
- children: "Export video..."
409
- }
410
- ),
411
- showAnimatedGifExport && /* @__PURE__ */ jsx(
412
- "button",
413
- {
414
- type: "button",
415
- role: "menuitem",
416
- className: "db-toolbar-menu-item",
417
- onClick: () => void handleOpenVideoModal("gif"),
418
- children: "Export animated gif..."
419
- }
420
- )
421
- ] })
422
- ] })
411
+ menuOpen && /* @__PURE__ */ jsxs(
412
+ "div",
413
+ {
414
+ ref: menuRef,
415
+ className: "db-toolbar-menu-dropdown db-export-toolbar-menu-dropdown",
416
+ role: "menu",
417
+ onKeyDown: handleMenuKeyDown,
418
+ children: [
419
+ lastOptions && /* @__PURE__ */ jsx(
420
+ "button",
421
+ {
422
+ type: "button",
423
+ role: "menuitem",
424
+ tabIndex: -1,
425
+ className: "db-toolbar-menu-item",
426
+ onClick: handleQuickExport,
427
+ disabled: exporting || Boolean(destinationAdapter) && !quickDestinationTarget,
428
+ title: quickDestinationTarget ? quickLabel(
429
+ lastOptions,
430
+ transformSummaries,
431
+ quickDestinationTarget.displayPath
432
+ ) : void 0,
433
+ children: quickDestinationTarget ? quickLabel(
434
+ lastOptions,
435
+ transformSummaries,
436
+ quickDestinationTarget.displayPath
437
+ ) : quickLabel(lastOptions, transformSummaries) + (destinationAdapter ? quickDestinationPending ? " (finding destination...)" : " (destination unavailable)" : "")
438
+ }
439
+ ),
440
+ /* @__PURE__ */ jsx(
441
+ "button",
442
+ {
443
+ type: "button",
444
+ role: "menuitem",
445
+ tabIndex: -1,
446
+ className: "db-toolbar-menu-item",
447
+ onClick: handleOpenDialog,
448
+ children: "Export..."
449
+ }
450
+ ),
451
+ /* @__PURE__ */ jsx(
452
+ "button",
453
+ {
454
+ type: "button",
455
+ role: "menuitem",
456
+ tabIndex: -1,
457
+ className: "db-toolbar-menu-item",
458
+ onClick: handleOpenShareDialog,
459
+ children: "Share link with content embedded..."
460
+ }
461
+ ),
462
+ showVideoExport && /* @__PURE__ */ jsxs(Fragment, { children: [
463
+ /* @__PURE__ */ jsx("div", { className: "db-toolbar-menu-divider", role: "separator" }),
464
+ /* @__PURE__ */ jsx(
465
+ "button",
466
+ {
467
+ type: "button",
468
+ role: "menuitem",
469
+ tabIndex: -1,
470
+ className: "db-toolbar-menu-item",
471
+ onClick: () => void handleOpenVideoModal("mp4"),
472
+ children: "Export video..."
473
+ }
474
+ ),
475
+ showAnimatedGifExport && /* @__PURE__ */ jsx(
476
+ "button",
477
+ {
478
+ type: "button",
479
+ role: "menuitem",
480
+ tabIndex: -1,
481
+ className: "db-toolbar-menu-item",
482
+ onClick: () => void handleOpenVideoModal("gif"),
483
+ children: "Export animated gif..."
484
+ }
485
+ )
486
+ ] })
487
+ ]
488
+ }
489
+ )
423
490
  ] }),
424
491
  dialogOpen && /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
425
492
  ExportDialog,
@@ -1,10 +1,11 @@
1
- import {
2
- useMenuKeyboard
3
- } from "./chunk-TFMO7EVO.js";
1
+ import "./chunk-APC4KI4B.js";
4
2
  import {
5
3
  isFileDirty,
6
4
  useGitContext
7
5
  } from "./chunk-HFYPTTCH.js";
6
+ import {
7
+ useMenuKeyboard
8
+ } from "./chunk-MRUK56JS.js";
8
9
 
9
10
  // src/Git/GitToolbarControl.tsx
10
11
  import { useEffect, useRef, useState } from "react";
@@ -1,6 +1,4 @@
1
- import {
2
- useMenuKeyboard
3
- } from "./chunk-TFMO7EVO.js";
1
+ import "./chunk-APC4KI4B.js";
4
2
  import {
5
3
  BADGE_GLYPHS,
6
4
  BADGE_LABELS,
@@ -9,6 +7,9 @@ import {
9
7
  summarizeDirty,
10
8
  useGitContext
11
9
  } from "./chunk-HFYPTTCH.js";
10
+ import {
11
+ useMenuKeyboard
12
+ } from "./chunk-MRUK56JS.js";
12
13
  import {
13
14
  Dialog
14
15
  } from "./chunk-LG6HAWCK.js";
File without changes
@@ -1,4 +1,24 @@
1
1
  // src/editor.ts
2
+ import { useEffect, useState } from "react";
3
+ var PORTRAIT_FORM_FACTOR_QUERY = "(orientation: portrait)";
4
+ function previewViewportPresetForOrientation(isPortrait) {
5
+ return isPortrait ? "portrait" : "landscape";
6
+ }
7
+ function useResponsivePreviewViewportPreset() {
8
+ const [isPortrait, setIsPortrait] = useState(() => {
9
+ if (typeof globalThis.matchMedia !== "function") return false;
10
+ return globalThis.matchMedia(PORTRAIT_FORM_FACTOR_QUERY).matches;
11
+ });
12
+ useEffect(() => {
13
+ if (typeof globalThis.matchMedia !== "function") return;
14
+ const query = globalThis.matchMedia(PORTRAIT_FORM_FACTOR_QUERY);
15
+ const update = () => setIsPortrait(query.matches);
16
+ update();
17
+ query.addEventListener("change", update);
18
+ return () => query.removeEventListener("change", update);
19
+ }, []);
20
+ return previewViewportPresetForOrientation(isPortrait);
21
+ }
2
22
  var EMPTY_DOCUMENT_PROMPTS = [
3
23
  "Start typing your content, or drop images on top of me...",
4
24
  "Write anything -- paste markdown, drag in images, or just start typing...",
@@ -64,6 +84,9 @@ function pickEmptyDocumentPrompt(random = Math.random) {
64
84
  }
65
85
 
66
86
  export {
87
+ PORTRAIT_FORM_FACTOR_QUERY,
88
+ previewViewportPresetForOrientation,
89
+ useResponsivePreviewViewportPreset,
67
90
  EMPTY_DOCUMENT_PROMPTS,
68
91
  pickEmptyDocumentPrompt
69
92
  };
@@ -1,5 +1,9 @@
1
- // src/Git/useMenuKeyboard.ts
2
- import { useCallback, useEffect, useRef } from "react";
1
+ // src/components/useMenuKeyboard.ts
2
+ import {
3
+ useCallback,
4
+ useEffect,
5
+ useRef
6
+ } from "react";
3
7
  function useMenuKeyboard(open, setOpen) {
4
8
  const menuRef = useRef(null);
5
9
  const triggerRef = useRef(null);
@@ -22,7 +26,7 @@ function useMenuKeyboard(open, setOpen) {
22
26
  (returnFocus) => {
23
27
  pendingFocusRef.current = "none";
24
28
  setOpen(false);
25
- if (returnFocus) triggerRef.current?.focus();
29
+ if (returnFocus) triggerRef.current?.focus({ preventScroll: true });
26
30
  },
27
31
  [setOpen]
28
32
  );
@@ -32,6 +36,17 @@ function useMenuKeyboard(open, setOpen) {
32
36
  pendingFocusRef.current = "none";
33
37
  focusItem(where === "last" ? items().length - 1 : 0);
34
38
  }, [open, focusItem, items]);
39
+ useEffect(() => {
40
+ if (!open) return;
41
+ const handleDocumentKeyDown = (event) => {
42
+ if (event.key !== "Escape" || event.defaultPrevented) return;
43
+ event.preventDefault();
44
+ event.stopPropagation();
45
+ closeMenu(true);
46
+ };
47
+ document.addEventListener("keydown", handleDocumentKeyDown);
48
+ return () => document.removeEventListener("keydown", handleDocumentKeyDown);
49
+ }, [closeMenu, open]);
35
50
  const handleTriggerKeyDown = useCallback(
36
51
  (event) => {
37
52
  if (event.key === "ArrowDown" || event.key === "ArrowUp") {
@@ -48,12 +63,16 @@ function useMenuKeyboard(open, setOpen) {
48
63
  );
49
64
  const handleMenuKeyDown = useCallback(
50
65
  (event) => {
51
- if (event.key === "Escape" || event.key === "Tab") {
66
+ if (event.key === "Escape") {
52
67
  event.preventDefault();
53
68
  event.stopPropagation();
54
69
  closeMenu(true);
55
70
  return;
56
71
  }
72
+ if (event.key === "Tab") {
73
+ closeMenu(false);
74
+ return;
75
+ }
57
76
  const all = items();
58
77
  if (all.length === 0) return;
59
78
  const current = all.indexOf(document.activeElement);