@bendyline/docblocks-react 2.3.0 → 2.3.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.
@@ -15,12 +15,12 @@ This notice is included in the published npm tarball. Transitive packages instal
15
15
  | Package | Version | License | Source |
16
16
  | --- | --- | --- | --- |
17
17
  | @antfu/install-pkg | 1.1.0 | MIT | https://github.com/antfu/install-pkg |
18
- | @bendyline/squisq | 2.4.3 | MIT | https://github.com/bendyline/squisq |
19
- | @bendyline/squisq-editor-react | 2.4.5 | MIT | https://github.com/bendyline/squisq |
20
- | @bendyline/squisq-formats | 2.3.7 | MIT | https://github.com/bendyline/squisq |
21
- | @bendyline/squisq-react | 2.4.5 | MIT | https://github.com/bendyline/squisq |
22
- | @bendyline/squisq-video | 2.2.7 | MIT | https://github.com/bendyline/squisq |
23
- | @bendyline/squisq-video-react | 2.2.9 | MIT | https://github.com/bendyline/squisq |
18
+ | @bendyline/squisq | 2.4.4 | MIT | https://github.com/bendyline/squisq |
19
+ | @bendyline/squisq-editor-react | 2.4.7 | MIT | https://github.com/bendyline/squisq |
20
+ | @bendyline/squisq-formats | 2.3.9 | MIT | https://github.com/bendyline/squisq |
21
+ | @bendyline/squisq-react | 2.4.7 | MIT | https://github.com/bendyline/squisq |
22
+ | @bendyline/squisq-video | 2.2.8 | MIT | https://github.com/bendyline/squisq |
23
+ | @bendyline/squisq-video-react | 2.2.11 | MIT | https://github.com/bendyline/squisq |
24
24
  | @braintree/sanitize-url | 7.1.2 | MIT | https://github.com/braintree/sanitize-url |
25
25
  | @chevrotain/types | 11.1.2 | Apache-2.0 | https://github.com/Chevrotain/chevrotain |
26
26
  | @ffmpeg/core | 0.12.9 | GPL-2.0-or-later | https://github.com/ffmpegwasm/ffmpeg.wasm |
@@ -398,7 +398,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
398
398
  SOFTWARE.
399
399
 
400
400
  ==============================================================================
401
- Components: @bendyline/squisq-editor-react@2.4.5, @bendyline/squisq-formats@2.3.7, @bendyline/squisq-react@2.4.5, @bendyline/squisq-video-react@2.2.9, @bendyline/squisq-video@2.2.7, @bendyline/squisq@2.4.3
401
+ Components: @bendyline/squisq-editor-react@2.4.7, @bendyline/squisq-formats@2.3.9, @bendyline/squisq-react@2.4.7, @bendyline/squisq-video-react@2.2.11, @bendyline/squisq-video@2.2.8, @bendyline/squisq@2.4.4
402
402
  Source files: node_modules/@bendyline/squisq-editor-react/LICENSE, node_modules/@bendyline/squisq-formats/LICENSE, node_modules/@bendyline/squisq-react/LICENSE, node_modules/@bendyline/squisq-video-react/LICENSE, node_modules/@bendyline/squisq-video/LICENSE, node_modules/@bendyline/squisq/LICENSE
403
403
  ==============================================================================
404
404
  MIT License
@@ -564,7 +564,7 @@ The above copyright notice and this permission notice shall be included in all c
564
564
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
565
565
 
566
566
  ==============================================================================
567
- Components: @bendyline/squisq-editor-react@2.4.5
567
+ Components: @bendyline/squisq-editor-react@2.4.7
568
568
  Source files: node_modules/@bendyline/squisq-editor-react/NOTICE.md
569
569
  ==============================================================================
570
570
  # Third-Party Notices for @bendyline/squisq-editor-react
@@ -611,7 +611,7 @@ Exact third-party license texts for the bundled adapter, loader, state helper,
611
611
  and Font Awesome assets are shipped in THIRD_PARTY_LICENSES.txt.
612
612
 
613
613
  ==============================================================================
614
- Components: @bendyline/squisq-editor-react@2.4.5, @tiptap/core@2.27.2, @tiptap/extension-blockquote@2.27.2, @tiptap/extension-bold@2.27.2, @tiptap/extension-bubble-menu@2.27.2, @tiptap/extension-bullet-list@2.27.2, @tiptap/extension-code-block@2.27.2, @tiptap/extension-code@2.27.2, @tiptap/extension-document@2.27.2, @tiptap/extension-dropcursor@2.27.2, @tiptap/extension-floating-menu@2.27.2, @tiptap/extension-gapcursor@2.27.2, @tiptap/extension-hard-break@2.27.2, @tiptap/extension-heading@2.27.2, @tiptap/extension-history@2.27.2, @tiptap/extension-horizontal-rule@2.27.2, @tiptap/extension-image@2.27.2, @tiptap/extension-italic@2.27.2, @tiptap/extension-link@2.27.2, @tiptap/extension-list-item@2.27.2, @tiptap/extension-mention@2.27.2, @tiptap/extension-ordered-list@2.27.2, @tiptap/extension-paragraph@2.27.2, @tiptap/extension-placeholder@2.27.2, @tiptap/extension-strike@2.27.2, @tiptap/extension-table-cell@2.27.2, @tiptap/extension-table-header@2.27.2, @tiptap/extension-table-row@2.27.2, @tiptap/extension-table@2.27.2, @tiptap/extension-task-item@2.27.2, @tiptap/extension-task-list@2.27.2, @tiptap/extension-text-style@2.27.2, @tiptap/extension-text@2.27.2, @tiptap/pm@2.27.2, @tiptap/react@2.27.2, @tiptap/starter-kit@2.27.2, @tiptap/suggestion@2.27.2
614
+ Components: @bendyline/squisq-editor-react@2.4.7, @tiptap/core@2.27.2, @tiptap/extension-blockquote@2.27.2, @tiptap/extension-bold@2.27.2, @tiptap/extension-bubble-menu@2.27.2, @tiptap/extension-bullet-list@2.27.2, @tiptap/extension-code-block@2.27.2, @tiptap/extension-code@2.27.2, @tiptap/extension-document@2.27.2, @tiptap/extension-dropcursor@2.27.2, @tiptap/extension-floating-menu@2.27.2, @tiptap/extension-gapcursor@2.27.2, @tiptap/extension-hard-break@2.27.2, @tiptap/extension-heading@2.27.2, @tiptap/extension-history@2.27.2, @tiptap/extension-horizontal-rule@2.27.2, @tiptap/extension-image@2.27.2, @tiptap/extension-italic@2.27.2, @tiptap/extension-link@2.27.2, @tiptap/extension-list-item@2.27.2, @tiptap/extension-mention@2.27.2, @tiptap/extension-ordered-list@2.27.2, @tiptap/extension-paragraph@2.27.2, @tiptap/extension-placeholder@2.27.2, @tiptap/extension-strike@2.27.2, @tiptap/extension-table-cell@2.27.2, @tiptap/extension-table-header@2.27.2, @tiptap/extension-table-row@2.27.2, @tiptap/extension-table@2.27.2, @tiptap/extension-task-item@2.27.2, @tiptap/extension-task-list@2.27.2, @tiptap/extension-text-style@2.27.2, @tiptap/extension-text@2.27.2, @tiptap/pm@2.27.2, @tiptap/react@2.27.2, @tiptap/starter-kit@2.27.2, @tiptap/suggestion@2.27.2
615
615
  Source files: node_modules/@bendyline/squisq-editor-react/THIRD_PARTY_LICENSES.txt
616
616
  ==============================================================================
617
617
  THIRD-PARTY LICENSES FOR @bendyline/squisq-editor-react
@@ -884,7 +884,7 @@ The above copyright notice and this permission notice shall be included in all c
884
884
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
885
885
 
886
886
  ==============================================================================
887
- Components: @bendyline/squisq-formats@2.3.7
887
+ Components: @bendyline/squisq-formats@2.3.9
888
888
  Source files: node_modules/@bendyline/squisq-formats/NOTICE.md
889
889
  ==============================================================================
890
890
  # Third-Party Notices for @bendyline/squisq-formats
@@ -909,7 +909,7 @@ texts for these dependencies are included in their respective npm
909
909
  distributions and source repositories.
910
910
 
911
911
  ==============================================================================
912
- Components: @bendyline/squisq-formats@2.3.7
912
+ Components: @bendyline/squisq-formats@2.3.9
913
913
  Source files: node_modules/@bendyline/squisq-formats/THIRD_PARTY_LICENSES.txt
914
914
  ==============================================================================
915
915
  THIRD-PARTY LICENSES FOR @bendyline/squisq-formats
@@ -1091,7 +1091,7 @@ Awesome, nor vice versa. **Please do not use brand logos for any purpose except
1091
1091
  to represent the company, product, or service to which they refer.**
1092
1092
 
1093
1093
  ==============================================================================
1094
- Components: @bendyline/squisq-react@2.4.5
1094
+ Components: @bendyline/squisq-react@2.4.7
1095
1095
  Source files: node_modules/@bendyline/squisq-react/NOTICE.md
1096
1096
  ==============================================================================
1097
1097
  # Third-Party Notices for @bendyline/squisq-react
@@ -1102,12 +1102,13 @@ Third-party components remain under their respective license terms.
1102
1102
 
1103
1103
  ## Runtime, peer, and bundled dependencies
1104
1104
 
1105
- | Package | Version | License | Repository |
1106
- | ------------------ | -------------------- | ------- | ------------------------------------- |
1107
- | mermaid | 11.16.0 | MIT | https://github.com/mermaid-js/mermaid |
1108
- | preact _(bundled)_ | 10.29.0 | MIT | https://github.com/preactjs/preact |
1109
- | react _(peer)_ | ^18.0.0 \|\| ^19.0.0 | MIT | https://github.com/facebook/react |
1110
- | react-dom _(peer)_ | ^18.0.0 \|\| ^19.0.0 | MIT | https://github.com/facebook/react |
1105
+ | Package | Version | License | Repository |
1106
+ | ----------------------------- | -------------------- | ----------------------------- | ------------------------------------------- |
1107
+ | @fortawesome/fontawesome-free | 7.2.0 | CC-BY-4.0 AND OFL-1.1 AND MIT | https://github.com/FortAwesome/Font-Awesome |
1108
+ | mermaid | 11.16.0 | MIT | https://github.com/mermaid-js/mermaid |
1109
+ | preact _(bundled)_ | 10.29.0 | MIT | https://github.com/preactjs/preact |
1110
+ | react _(peer)_ | ^18.0.0 \|\| ^19.0.0 | MIT | https://github.com/facebook/react |
1111
+ | react-dom _(peer)_ | ^18.0.0 \|\| ^19.0.0 | MIT | https://github.com/facebook/react |
1111
1112
 
1112
1113
  Mermaid is Copyright (c) 2014-2022 Knut Sveidqvist and is distributed under
1113
1114
  the MIT License. Preact is used by the standalone browser bundles. Exact
@@ -1115,7 +1116,7 @@ third-party license texts for the complete standalone bundle graph are shipped
1115
1116
  in THIRD_PARTY_LICENSES.txt.
1116
1117
 
1117
1118
  ==============================================================================
1118
- Components: @bendyline/squisq-react@2.4.5
1119
+ Components: @bendyline/squisq-react@2.4.7
1119
1120
  Source files: node_modules/@bendyline/squisq-react/THIRD_PARTY_LICENSES.txt
1120
1121
  ==============================================================================
1121
1122
  THIRD-PARTY LICENSES FOR @bendyline/squisq-react
@@ -5588,7 +5589,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
5588
5589
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5589
5590
 
5590
5591
  ==============================================================================
5591
- Components: @bendyline/squisq-video-react@2.2.9, @ffmpeg/core@0.12.9
5592
+ Components: @bendyline/squisq-video-react@2.2.11, @ffmpeg/core@0.12.9
5592
5593
  Source files: node_modules/@bendyline/squisq-video-react/COPYING.GPL-2.0.txt
5593
5594
  ==============================================================================
5594
5595
  GNU GENERAL PUBLIC LICENSE
@@ -5931,7 +5932,7 @@ library. If this is what you want to do, use the GNU Lesser General
5931
5932
  Public License instead of this License.
5932
5933
 
5933
5934
  ==============================================================================
5934
- Components: @bendyline/squisq-video-react@2.2.9, @ffmpeg/core@0.12.9
5935
+ Components: @bendyline/squisq-video-react@2.2.11, @ffmpeg/core@0.12.9
5935
5936
  Source files: node_modules/@bendyline/squisq-video-react/NOTICE.md
5936
5937
  ==============================================================================
5937
5938
  # Third-Party Notices for @bendyline/squisq-video-react
@@ -5976,7 +5977,7 @@ global WebCodecs declaration dependencies are not installed for consumers. Its
5976
5977
  exact license text is shipped in THIRD_PARTY_LICENSES.txt.
5977
5978
 
5978
5979
  ==============================================================================
5979
- Components: @bendyline/squisq-video-react@2.2.9, @ffmpeg/core@0.12.9, @ffmpeg/ffmpeg@0.12.15, @ffmpeg/types@0.12.4, @ffmpeg/util@0.12.2
5980
+ Components: @bendyline/squisq-video-react@2.2.11, @ffmpeg/core@0.12.9, @ffmpeg/ffmpeg@0.12.15, @ffmpeg/types@0.12.4, @ffmpeg/util@0.12.2
5980
5981
  Source files: node_modules/@bendyline/squisq-video-react/THIRD_PARTY_LICENSES.txt
5981
5982
  ==============================================================================
5982
5983
  THIRD-PARTY LICENSES FOR @bendyline/squisq-video-react
@@ -6040,7 +6041,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
6040
6041
  SOFTWARE.
6041
6042
 
6042
6043
  ==============================================================================
6043
- Components: @bendyline/squisq-video@2.2.7
6044
+ Components: @bendyline/squisq-video@2.2.8
6044
6045
  Source files: node_modules/@bendyline/squisq-video/NOTICE.md
6045
6046
  ==============================================================================
6046
6047
  # Third-Party Notices for @bendyline/squisq-video
@@ -6065,7 +6066,7 @@ Copyright and complete license texts for the listed dependencies are included
6065
6066
  in their respective npm distributions and source repositories.
6066
6067
 
6067
6068
  ==============================================================================
6068
- Components: @bendyline/squisq-video@2.2.7
6069
+ Components: @bendyline/squisq-video@2.2.8
6069
6070
  Source files: node_modules/@bendyline/squisq-video/THIRD_PARTY_LICENSES.txt
6070
6071
  ==============================================================================
6071
6072
  THIRD-PARTY LICENSES FOR @bendyline/squisq-video
@@ -6077,7 +6078,7 @@ repository license, the pinned upstream copy is vendored and identified below.
6077
6078
  COMPONENTS
6078
6079
 
6079
6080
  ==============================================================================
6080
- Components: @bendyline/squisq@2.4.3
6081
+ Components: @bendyline/squisq@2.4.4
6081
6082
  Source files: node_modules/@bendyline/squisq/NOTICE.md
6082
6083
  ==============================================================================
6083
6084
  # Third-Party Notices for @bendyline/squisq
@@ -6108,7 +6109,7 @@ third-party license texts for bundled code and data are shipped in
6108
6109
  THIRD_PARTY_LICENSES.txt.
6109
6110
 
6110
6111
  ==============================================================================
6111
- Components: @bendyline/squisq@2.4.3
6112
+ Components: @bendyline/squisq@2.4.4
6112
6113
  Source files: node_modules/@bendyline/squisq/THIRD_PARTY_LICENSES.txt
6113
6114
  ==============================================================================
6114
6115
  THIRD-PARTY LICENSES FOR @bendyline/squisq
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ExportDialog
3
- } from "./chunk-MHTQORMH.js";
3
+ } from "./chunk-SIIEGOHY.js";
4
4
  import "./chunk-YBEYTVU2.js";
5
5
  import "./chunk-LG6HAWCK.js";
6
6
  import "./chunk-EBWYGTN7.js";
@@ -1,3 +1,7 @@
1
+ import {
2
+ browserSaveMode,
3
+ saveActionLabel
4
+ } from "./chunk-UMEDHMT7.js";
1
5
  import {
2
6
  useMenuKeyboard
3
7
  } from "./chunk-MRUK56JS.js";
@@ -7,6 +11,9 @@ import {
7
11
  import {
8
12
  Dialog
9
13
  } from "./chunk-LG6HAWCK.js";
14
+ import {
15
+ buildExportFilename
16
+ } from "./chunk-M5Y5WO7Z.js";
10
17
  import {
11
18
  DEFAULT_OPTIONS,
12
19
  FORMAT_EXTENSIONS,
@@ -29,14 +36,14 @@ import { getThemeSummaries } from "@bendyline/squisq/schemas";
29
36
  import { parseMarkdown } from "@bendyline/squisq/markdown";
30
37
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
31
38
  var ExportDialog = lazy(
32
- () => import("./ExportDialog-HPFPXELL.js").then((module) => ({ default: module.ExportDialog }))
39
+ () => import("./ExportDialog-VBWHFJ2R.js").then((module) => ({ default: module.ExportDialog }))
33
40
  );
34
41
  var ShareDialog = lazy(
35
42
  () => import("./ShareDialog-PAMOQQFB.js").then((module) => ({ default: module.ShareDialog }))
36
43
  );
37
44
  var runExportModulePromise = null;
38
45
  function loadRunExportModule() {
39
- runExportModulePromise ?? (runExportModulePromise = import("./run-export-Z5BVFLIR.js"));
46
+ runExportModulePromise ?? (runExportModulePromise = import("./run-export-UYR5USUJ.js"));
40
47
  return runExportModulePromise;
41
48
  }
42
49
  var ExportCancelledError = class extends Error {
@@ -77,7 +84,7 @@ function exportErrorMessage(caught) {
77
84
  const detail = caught instanceof Error ? caught.message.replace(/^Error invoking remote method '[^']+': Error:\s*/, "").trim() : "";
78
85
  return detail ? `Export failed: ${detail}` : "Export failed. The document could not be exported.";
79
86
  }
80
- function quickLabel(opts, transformSummaries, destinationPath) {
87
+ function quickLabel(opts, transformSummaries, saveMode, destinationPath) {
81
88
  const baseExt = FORMAT_EXTENSIONS[opts.format].toUpperCase().replace(".", "");
82
89
  const isRecursiveHtml = opts.format === "html" && opts.includeLinkedDocs;
83
90
  const ext = opts.format === "html" && (opts.htmlBundle === "zip" || isRecursiveHtml) ? "ZIP" : baseExt;
@@ -96,11 +103,13 @@ function quickLabel(opts, transformSummaries, destinationPath) {
96
103
  const transform = transformSummaries.find((t) => t.id === opts.transformStyle);
97
104
  if (transform) parts.push(transform.name);
98
105
  }
106
+ const prefix = `Save ${ext}`;
107
+ let label = prefix;
99
108
  if (parts.length > 0) {
100
- const label2 = `Export ${ext} with ${parts.join(" + ")}`;
101
- return destinationPath ? `${label2} to ${destinationPath}` : label2;
109
+ label = `${prefix} with ${parts.join(" + ")}`;
102
110
  }
103
- const label = `Export ${ext}`;
111
+ if (saveMode === "save-as") return `${label} as...`;
112
+ if (saveMode === "downloads") return `${label} to Downloads`;
104
113
  return destinationPath ? `${label} to ${destinationPath}` : label;
105
114
  }
106
115
  function ExportToolbarControls({
@@ -188,9 +197,7 @@ function ExportToolbarControls({
188
197
  let cancelled = false;
189
198
  setQuickDestination(null);
190
199
  setQuickDestinationPending(true);
191
- void loadRunExportModule().then(
192
- ({ buildExportFilename }) => destinationAdapter.resolveTarget(buildExportFilename(selectedFile, quickOptions))
193
- ).then((target) => {
200
+ void destinationAdapter.resolveTarget(buildExportFilename(selectedFile, quickOptions)).then((target) => {
194
201
  if (!cancelled) setQuickDestination({ key: quickDestinationKey, target });
195
202
  }).catch(() => {
196
203
  if (!cancelled) setQuickDestination(null);
@@ -214,7 +221,6 @@ function ExportToolbarControls({
214
221
  const requestId = destinationRequestRef.current + 1;
215
222
  destinationRequestRef.current = requestId;
216
223
  try {
217
- const { buildExportFilename } = await loadRunExportModule();
218
224
  const filename = buildExportFilename(selectedFile, options);
219
225
  const target = await destinationAdapter.resolveTarget(filename);
220
226
  if (destinationRequestRef.current === requestId) setDestinationTarget(target);
@@ -282,7 +288,6 @@ function ExportToolbarControls({
282
288
  async (options) => {
283
289
  if (!destinationAdapter) return;
284
290
  try {
285
- const { buildExportFilename } = await loadRunExportModule();
286
291
  const filename = buildExportFilename(selectedFile, options);
287
292
  const pickedTarget = await destinationAdapter.pickTarget(filename, destinationTarget);
288
293
  if (pickedTarget === null) return;
@@ -302,24 +307,25 @@ function ExportToolbarControls({
302
307
  },
303
308
  [destinationAdapter]
304
309
  );
305
- const handleDestinationSaveBlob = useCallback(
306
- async (blob, filename) => {
307
- await saveToDestination(blob, filename, destinationTarget);
308
- },
309
- [destinationTarget, saveToDestination]
310
- );
311
310
  const handleExport = useCallback(
312
311
  async (opts) => {
313
312
  setExporting(true);
314
313
  setExportError(null);
315
314
  try {
315
+ let exportTarget = destinationTarget;
316
+ if (destinationAdapter?.pickBeforeSave) {
317
+ const filename = buildExportFilename(selectedFile, opts);
318
+ exportTarget = await destinationAdapter.pickTarget(filename, destinationTarget);
319
+ if (!exportTarget) return;
320
+ setDestinationTarget(exportTarget);
321
+ }
316
322
  const { runExport } = await loadRunExportModule();
317
323
  await runExport(
318
324
  markdownSource,
319
325
  selectedFile,
320
326
  opts,
321
327
  mediaContainer,
322
- destinationAdapter ? handleDestinationSaveBlob : saveBlob
328
+ destinationAdapter ? (blob, filename) => saveToDestination(blob, filename, exportTarget) : saveBlob
323
329
  );
324
330
  setDialogOpen(false);
325
331
  } catch (caught) {
@@ -333,7 +339,8 @@ function ExportToolbarControls({
333
339
  selectedFile,
334
340
  mediaContainer,
335
341
  destinationAdapter,
336
- handleDestinationSaveBlob,
342
+ destinationTarget,
343
+ saveToDestination,
337
344
  saveBlob
338
345
  ]
339
346
  );
@@ -344,12 +351,18 @@ function ExportToolbarControls({
344
351
  setExportError(null);
345
352
  try {
346
353
  saveExportOptions(lastOptions);
347
- const { runExport } = await loadRunExportModule();
348
354
  let quickTarget = null;
349
355
  if (destinationAdapter) {
350
- if (!quickDestinationTarget) return;
351
- quickTarget = quickDestinationTarget;
356
+ if (destinationAdapter.pickBeforeSave) {
357
+ const filename = buildExportFilename(selectedFile, lastOptions);
358
+ quickTarget = await destinationAdapter.pickTarget(filename, quickDestinationTarget);
359
+ if (!quickTarget) return;
360
+ } else {
361
+ if (!quickDestinationTarget) return;
362
+ quickTarget = quickDestinationTarget;
363
+ }
352
364
  }
365
+ const { runExport } = await loadRunExportModule();
353
366
  await runExport(
354
367
  markdownSource,
355
368
  selectedFile,
@@ -375,8 +388,18 @@ function ExportToolbarControls({
375
388
  const handleDismissExportError = useCallback(() => {
376
389
  setExportError(null);
377
390
  }, []);
391
+ const handleVideoSave = useCallback(
392
+ async (blob, filename) => {
393
+ if (!destinationAdapter) return false;
394
+ const target = await destinationAdapter.pickTarget(filename, null);
395
+ if (!target) return false;
396
+ return await destinationAdapter.saveBlob(blob, filename, target) !== null;
397
+ },
398
+ [destinationAdapter]
399
+ );
378
400
  const LoadedVideoExportModal = videoModules?.Modal;
379
401
  const showAnimatedGifExport = showVideoExport && typeof ffmpegWasm?.coreURL === "string" && ffmpegWasm.coreURL.length > 0;
402
+ const quickSaveMode = destinationAdapter ? destinationAdapter.pickBeforeSave ? "save-as" : "destination" : "downloads";
380
403
  return /* @__PURE__ */ jsxs(Fragment, { children: [
381
404
  initialSharedMode && /* @__PURE__ */ jsx(SharedModeInitializer, { mode: initialSharedMode }),
382
405
  trigger === "button" ? /* @__PURE__ */ jsx(
@@ -429,13 +452,15 @@ function ExportToolbarControls({
429
452
  title: quickDestinationTarget ? quickLabel(
430
453
  lastOptions,
431
454
  transformSummaries,
432
- quickDestinationTarget.displayPath
455
+ quickSaveMode,
456
+ destinationAdapter?.pickBeforeSave ? void 0 : quickDestinationTarget.displayPath
433
457
  ) : void 0,
434
458
  children: quickDestinationTarget ? quickLabel(
435
459
  lastOptions,
436
460
  transformSummaries,
437
- quickDestinationTarget.displayPath
438
- ) : quickLabel(lastOptions, transformSummaries) + (destinationAdapter ? quickDestinationPending ? " (finding destination...)" : " (destination unavailable)" : "")
461
+ quickSaveMode,
462
+ destinationAdapter?.pickBeforeSave ? void 0 : quickDestinationTarget.displayPath
463
+ ) : quickLabel(lastOptions, transformSummaries, quickSaveMode) + (destinationAdapter ? quickDestinationPending ? " (finding destination...)" : " (destination unavailable)" : "")
439
464
  }
440
465
  ),
441
466
  /* @__PURE__ */ jsx(
@@ -495,13 +520,23 @@ function ExportToolbarControls({
495
520
  initial: dialogInitial,
496
521
  exporting,
497
522
  error: exportError,
498
- destination: destinationAdapter ? {
523
+ destination: destinationAdapter && destinationAdapter.showDestination !== false ? {
499
524
  value: destinationTarget?.displayPath ?? "",
500
525
  onPick: handlePickDestination,
501
526
  hint: destinationAdapter.hint
502
527
  } : void 0,
503
528
  onExport: handleExport,
504
529
  onOptionsChange: destinationAdapter ? handleOptionsChange : void 0,
530
+ actionLabel: (options) => {
531
+ const extension = options.format === "html" && (options.includeLinkedDocs || options.htmlBundle === "zip") ? "ZIP" : FORMAT_EXTENSIONS[options.format].slice(1);
532
+ if (destinationAdapter && !destinationAdapter.pickBeforeSave) {
533
+ return `Save ${extension.toUpperCase()}`;
534
+ }
535
+ return saveActionLabel(
536
+ extension,
537
+ destinationAdapter?.pickBeforeSave ? "save-as" : browserSaveMode()
538
+ );
539
+ },
505
540
  onClose: handleCloseDialog
506
541
  }
507
542
  ) }),
@@ -552,6 +587,10 @@ function ExportToolbarControls({
552
587
  ...ffmpegWasm ? { ffmpegWasm } : {},
553
588
  outputFormat: videoOutputFormat
554
589
  },
590
+ ...destinationAdapter ? {
591
+ saveOutput: handleVideoSave,
592
+ saveActionLabel: (format) => saveActionLabel(format, "save-as")
593
+ } : {},
555
594
  onClose: handleCloseVideoModal
556
595
  }
557
596
  )
@@ -0,0 +1,17 @@
1
+ import {
2
+ FORMAT_EXTENSIONS
3
+ } from "./chunk-EBWYGTN7.js";
4
+
5
+ // src/Export/export-filename.ts
6
+ function buildExportFilename(selectedFile, options) {
7
+ const base = selectedFile ? selectedFile.replace(/^\//, "").replace(/\.[^.]+$/, "") : "document";
8
+ if (options.format === "html") {
9
+ if (options.includeLinkedDocs || options.htmlBundle === "zip") return `${base}.zip`;
10
+ if (options.entryAsIndex) return "index.html";
11
+ }
12
+ return base + FORMAT_EXTENSIONS[options.format];
13
+ }
14
+
15
+ export {
16
+ buildExportFilename
17
+ };
@@ -31,14 +31,6 @@ function buildFilename(selectedFile, format) {
31
31
  const base = selectedFile ? selectedFile.replace(/^\//, "").replace(/\.[^.]+$/, "") : "document";
32
32
  return base + FORMAT_EXTENSIONS[format];
33
33
  }
34
- function buildExportFilename(selectedFile, options) {
35
- const base = selectedFile ? selectedFile.replace(/^\//, "").replace(/\.[^.]+$/, "") : "document";
36
- if (options.format === "html") {
37
- if (options.includeLinkedDocs || options.htmlBundle === "zip") return `${base}.zip`;
38
- if (options.entryAsIndex) return "index.html";
39
- }
40
- return base + FORMAT_EXTENSIONS[options.format];
41
- }
42
34
  async function runExport(markdown, selectedFile, options, mediaContainer, saveBlob, converterOverrides = {}) {
43
35
  const filename = buildFilename(selectedFile, options.format);
44
36
  const themeId = options.themeId !== "standard" ? options.themeId : void 0;
@@ -285,6 +277,5 @@ async function resolveDocImages(doc, container, collectImagePaths) {
285
277
  }
286
278
 
287
279
  export {
288
- buildExportFilename,
289
280
  runExport
290
281
  };
@@ -76,6 +76,7 @@ function ExportDialog({
76
76
  destination,
77
77
  onExport,
78
78
  onOptionsChange,
79
+ actionLabel,
79
80
  onClose
80
81
  }) {
81
82
  const [format, setFormat] = useState(initial.format);
@@ -163,7 +164,7 @@ function ExportDialog({
163
164
  className: "db-export-btn db-export-btn--primary",
164
165
  onClick: handleExport,
165
166
  disabled: exporting || Boolean(destination?.error),
166
- children: exporting ? "Exporting..." : "Export"
167
+ children: exporting ? "Exporting..." : actionLabel?.(currentOptions) ?? "Export"
167
168
  }
168
169
  )
169
170
  ] }),
@@ -0,0 +1,84 @@
1
+ // src/Export/browser-save.ts
2
+ var INSTALLED_DISPLAY_QUERIES = [
3
+ "(display-mode: window-controls-overlay)",
4
+ "(display-mode: standalone)"
5
+ ];
6
+ function isInstalledWebApp() {
7
+ return typeof globalThis.matchMedia === "function" && INSTALLED_DISPLAY_QUERIES.some((query) => globalThis.matchMedia(query).matches);
8
+ }
9
+ function browserSaveMode() {
10
+ return isInstalledWebApp() && typeof window !== "undefined" && typeof window.showSaveFilePicker === "function" ? "save-as" : "downloads";
11
+ }
12
+ function saveActionLabel(format, mode) {
13
+ return mode === "save-as" ? `Save ${format.toUpperCase()} as...` : `Save ${format.toUpperCase()} to Downloads`;
14
+ }
15
+ function isPickerCancellation(caught) {
16
+ return caught instanceof DOMException && caught.name === "AbortError";
17
+ }
18
+ function pickerOptions(blob, filename) {
19
+ const extensionMatch = filename.match(/(\.[^./\\]+)$/);
20
+ const extension = extensionMatch?.[1]?.toLowerCase();
21
+ if (!extension) return { suggestedName: filename };
22
+ const mimeType = blob?.type || "application/octet-stream";
23
+ return {
24
+ suggestedName: filename,
25
+ types: [
26
+ {
27
+ description: `${extension.slice(1).toUpperCase()} file`,
28
+ accept: { [mimeType]: [extension] }
29
+ }
30
+ ]
31
+ };
32
+ }
33
+ function savePickerFilename(filename) {
34
+ return filename.replace(/\\/g, "/").split("/").pop() || "document";
35
+ }
36
+ function createBrowserSaveAsAdapter() {
37
+ if (browserSaveMode() !== "save-as" || !window.showSaveFilePicker) return void 0;
38
+ const handles = /* @__PURE__ */ new Map();
39
+ let nextGrantId = 0;
40
+ return {
41
+ pickBeforeSave: true,
42
+ showDestination: false,
43
+ async resolveTarget(filename) {
44
+ return { grantId: null, displayPath: filename };
45
+ },
46
+ async pickTarget(filename) {
47
+ try {
48
+ const suggestedName = savePickerFilename(filename);
49
+ const handle = await window.showSaveFilePicker?.(pickerOptions(null, suggestedName));
50
+ if (!handle) return null;
51
+ const grantId = `browser-save-${nextGrantId}`;
52
+ nextGrantId += 1;
53
+ handles.set(grantId, handle);
54
+ return { grantId, displayPath: handle.name };
55
+ } catch (caught) {
56
+ if (isPickerCancellation(caught)) return null;
57
+ throw caught;
58
+ }
59
+ },
60
+ async saveBlob(blob, filename, target) {
61
+ if (!target?.grantId) throw new Error("Choose a file before saving the export.");
62
+ const handle = handles.get(target.grantId);
63
+ if (!handle) throw new Error("Choose a file before saving the export.");
64
+ const writable = await handle.createWritable();
65
+ try {
66
+ await writable.write(blob);
67
+ await writable.close();
68
+ } catch (caught) {
69
+ try {
70
+ await writable.abort();
71
+ } catch {
72
+ }
73
+ throw caught;
74
+ }
75
+ return target;
76
+ }
77
+ };
78
+ }
79
+
80
+ export {
81
+ browserSaveMode,
82
+ saveActionLabel,
83
+ createBrowserSaveAsAdapter
84
+ };
@@ -55,12 +55,13 @@ declare const DEFAULT_OPTIONS: ExportOptions;
55
55
  declare function loadLastExportOptions(): ExportOptions | null;
56
56
  declare function saveExportOptions(options: ExportOptions): void;
57
57
 
58
+ declare function buildExportFilename(selectedFile: string | null, options: ExportOptions): string;
59
+
58
60
  type ExportBlobSaver = (blob: Blob, filename: string) => Promise<void> | void;
59
61
  /** Host-provided converters that must be loaded before an export begins. */
60
62
  interface ExportConverterOverrides {
61
63
  docToPptx?: (typeof _bendyline_squisq_formats_pptx)['docToPptx'];
62
64
  }
63
- declare function buildExportFilename(selectedFile: string | null, options: ExportOptions): string;
64
65
  /** Run the export and trigger a download. */
65
66
  declare function runExport(markdown: string, selectedFile: string | null, options: ExportOptions, mediaContainer?: ContentContainer | null, saveBlob?: ExportBlobSaver, converterOverrides?: ExportConverterOverrides): Promise<void>;
66
67
 
@@ -81,6 +82,8 @@ interface ExportDialogProps {
81
82
  onExport: (options: ExportOptions) => void;
82
83
  /** Called whenever the currently selected options change. */
83
84
  onOptionsChange?: (options: ExportOptions) => void;
85
+ /** Host-aware label for the final save action. Defaults to "Export". */
86
+ actionLabel?: (options: ExportOptions) => string;
84
87
  /** Called when the dialog is dismissed. */
85
88
  onClose: () => void;
86
89
  }
@@ -93,7 +96,7 @@ interface ExportDestinationControl {
93
96
  /** A host-supplied validation error for the current destination value. */
94
97
  error?: string | null;
95
98
  }
96
- declare function ExportDialog({ initial, exporting, error, destination, onExport, onOptionsChange, onClose, }: ExportDialogProps): react_jsx_runtime.JSX.Element;
99
+ declare function ExportDialog({ initial, exporting, error, destination, onExport, onOptionsChange, actionLabel, onClose, }: ExportDialogProps): react_jsx_runtime.JSX.Element;
97
100
 
98
101
  /** Keep a user-edited target name while switching the selected export format. */
99
102
  declare function updateExportTargetExtension(targetPath: string, suggestedFilename: string): string;
@@ -3,13 +3,15 @@ import {
3
3
  } from "../chunk-BI7NVU6T.js";
4
4
  import {
5
5
  ExportDialog
6
- } from "../chunk-MHTQORMH.js";
6
+ } from "../chunk-SIIEGOHY.js";
7
7
  import {
8
- buildExportFilename,
9
8
  runExport
10
- } from "../chunk-GHQ4X7KM.js";
9
+ } from "../chunk-OSQUKIUN.js";
11
10
  import "../chunk-YBEYTVU2.js";
12
11
  import "../chunk-LG6HAWCK.js";
12
+ import {
13
+ buildExportFilename
14
+ } from "../chunk-M5Y5WO7Z.js";
13
15
  import {
14
16
  DEFAULT_OPTIONS,
15
17
  FORMAT_EXTENSIONS,
package/dist/index.d.ts CHANGED
@@ -397,6 +397,10 @@ interface ExportDestinationAdapter {
397
397
  resolveTarget: (filename: string) => Promise<ExportDestinationTarget>;
398
398
  pickTarget: (filename: string, currentTarget?: ExportDestinationTarget | null) => Promise<ExportDestinationTarget | null>;
399
399
  saveBlob: (blob: Blob, filename: string, target?: ExportDestinationTarget | null) => Promise<ExportDestinationTarget | null>;
400
+ /** Open the picker from the initiating click before expensive conversion work. */
401
+ pickBeforeSave?: boolean;
402
+ /** Whether the export dialog should render the adapter's destination field. */
403
+ showDestination?: boolean;
400
404
  hint?: string;
401
405
  }
402
406
 
package/dist/index.js CHANGED
@@ -33,11 +33,13 @@ import {
33
33
  } from "./chunk-JDJVRDOP.js";
34
34
  import {
35
35
  ExportDialog
36
- } from "./chunk-MHTQORMH.js";
36
+ } from "./chunk-SIIEGOHY.js";
37
37
  import {
38
- buildExportFilename,
39
38
  runExport
40
- } from "./chunk-GHQ4X7KM.js";
39
+ } from "./chunk-OSQUKIUN.js";
40
+ import {
41
+ createBrowserSaveAsAdapter
42
+ } from "./chunk-UMEDHMT7.js";
41
43
  import {
42
44
  useMenuKeyboard
43
45
  } from "./chunk-MRUK56JS.js";
@@ -45,6 +47,9 @@ import "./chunk-YBEYTVU2.js";
45
47
  import {
46
48
  Dialog
47
49
  } from "./chunk-LG6HAWCK.js";
50
+ import {
51
+ buildExportFilename
52
+ } from "./chunk-M5Y5WO7Z.js";
48
53
  import {
49
54
  DEFAULT_OPTIONS,
50
55
  loadLastExportOptions
@@ -3149,7 +3154,7 @@ function useDocumentSession(autoSaveDelayMs = 500) {
3149
3154
  import { lazy, Suspense } from "react";
3150
3155
  import { jsx as jsx10 } from "react/jsx-runtime";
3151
3156
  var ExportToolbarControlsImplementation = lazy(
3152
- () => import("./ExportToolbarControls-6MO4NX6H.js").then((module) => ({
3157
+ () => import("./ExportToolbarControls-I2EX7ZTH.js").then((module) => ({
3153
3158
  default: module.ExportToolbarControls
3154
3159
  }))
3155
3160
  );
@@ -5242,14 +5247,17 @@ function DocBlocksShell({
5242
5247
  const [selectedFile, setSelectedFile] = useState15(null);
5243
5248
  useDocumentTitle(selectedFile, homeDocumentTitle, homeDocumentPath);
5244
5249
  const exportDestinationAdapter = useMemo3(() => {
5245
- if (!isElectronHost3() || !activeWorkspaceId || !selectedFile) return void 0;
5246
- const documentId = JSON.stringify([activeWorkspaceId, selectedFile]);
5247
- const host = getDocBlocksHost().exports;
5248
- return {
5249
- resolveTarget: (filename) => host.resolveTarget(documentId, filename),
5250
- pickTarget: (filename, currentTarget) => host.pickTarget(documentId, filename, currentTarget?.grantId ?? null),
5251
- saveBlob: async (blob, filename, target) => host.save(documentId, filename, target?.grantId ?? null, await blob.arrayBuffer())
5252
- };
5250
+ if (!selectedFile) return void 0;
5251
+ if (isElectronHost3() && activeWorkspaceId) {
5252
+ const documentId = JSON.stringify([activeWorkspaceId, selectedFile]);
5253
+ const host = getDocBlocksHost().exports;
5254
+ return {
5255
+ resolveTarget: (filename) => host.resolveTarget(documentId, filename),
5256
+ pickTarget: (filename, currentTarget) => host.pickTarget(documentId, filename, currentTarget?.grantId ?? null),
5257
+ saveBlob: async (blob, filename, target) => host.save(documentId, filename, target?.grantId ?? null, await blob.arrayBuffer())
5258
+ };
5259
+ }
5260
+ return createBrowserSaveAsAdapter();
5253
5261
  }, [activeWorkspaceId, selectedFile]);
5254
5262
  const [selectedFolder, setSelectedFolder] = useState15(null);
5255
5263
  const [folderEntries, setFolderEntries] = useState15([]);
@@ -1,7 +1,9 @@
1
1
  import {
2
- buildExportFilename,
3
2
  runExport
4
- } from "./chunk-GHQ4X7KM.js";
3
+ } from "./chunk-OSQUKIUN.js";
4
+ import {
5
+ buildExportFilename
6
+ } from "./chunk-M5Y5WO7Z.js";
5
7
  import "./chunk-EBWYGTN7.js";
6
8
  export {
7
9
  buildExportFilename,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/docblocks-react",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "React components for DocBlocks — file explorer, workspace picker, and editor shell",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -75,13 +75,13 @@
75
75
  }
76
76
  },
77
77
  "dependencies": {
78
- "@bendyline/docblocks": "2.3.0",
79
- "@bendyline/squisq": "2.4.3",
80
- "@bendyline/squisq-editor-react": "2.4.5",
81
- "@bendyline/squisq-formats": "2.3.7",
82
- "@bendyline/squisq-react": "2.4.5",
83
- "@bendyline/squisq-video": "2.2.7",
84
- "@bendyline/squisq-video-react": "2.2.9"
78
+ "@bendyline/docblocks": "2.3.1",
79
+ "@bendyline/squisq": "2.4.4",
80
+ "@bendyline/squisq-editor-react": "2.4.7",
81
+ "@bendyline/squisq-formats": "2.3.9",
82
+ "@bendyline/squisq-react": "2.4.7",
83
+ "@bendyline/squisq-video": "2.2.8",
84
+ "@bendyline/squisq-video-react": "2.2.11"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@happy-dom/global-registrator": "20.9.0",