@bendyline/docblocks-react 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/README.md +50 -15
  2. package/dist/AppMenu/AppMenu.d.ts +29 -2
  3. package/dist/AppMenu/AppMenu.d.ts.map +1 -1
  4. package/dist/AppMenu/AppMenu.js +41 -2
  5. package/dist/AppMenu/AppMenu.js.map +1 -1
  6. package/dist/AppMenu/index.d.ts +1 -1
  7. package/dist/AppMenu/index.d.ts.map +1 -1
  8. package/dist/DocBlocksShell/DocBlocksShell.d.ts +17 -4
  9. package/dist/DocBlocksShell/DocBlocksShell.d.ts.map +1 -1
  10. package/dist/DocBlocksShell/DocBlocksShell.js +1710 -299
  11. package/dist/DocBlocksShell/DocBlocksShell.js.map +1 -1
  12. package/dist/DocBlocksShell/LazyEditorShell.d.ts +3 -0
  13. package/dist/DocBlocksShell/LazyEditorShell.d.ts.map +1 -0
  14. package/dist/DocBlocksShell/LazyEditorShell.js +3 -0
  15. package/dist/DocBlocksShell/LazyEditorShell.js.map +1 -0
  16. package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts +13 -0
  17. package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts.map +1 -0
  18. package/dist/DocBlocksShell/UpdateAvailableNotice.js +16 -0
  19. package/dist/DocBlocksShell/UpdateAvailableNotice.js.map +1 -0
  20. package/dist/DocBlocksShell/document-title.d.ts +3 -0
  21. package/dist/DocBlocksShell/document-title.d.ts.map +1 -0
  22. package/dist/DocBlocksShell/document-title.js +17 -0
  23. package/dist/DocBlocksShell/document-title.js.map +1 -0
  24. package/dist/DocBlocksShell/workspace-authority-barrier.d.ts +14 -0
  25. package/dist/DocBlocksShell/workspace-authority-barrier.d.ts.map +1 -0
  26. package/dist/DocBlocksShell/workspace-authority-barrier.js +23 -0
  27. package/dist/DocBlocksShell/workspace-authority-barrier.js.map +1 -0
  28. package/dist/Export/DeferredExportToolbarControls.d.ts +5 -0
  29. package/dist/Export/DeferredExportToolbarControls.d.ts.map +1 -0
  30. package/dist/Export/DeferredExportToolbarControls.js +10 -0
  31. package/dist/Export/DeferredExportToolbarControls.js.map +1 -0
  32. package/dist/Export/ExportDialog.d.ts +10 -1
  33. package/dist/Export/ExportDialog.d.ts.map +1 -1
  34. package/dist/Export/ExportDialog.js +39 -20
  35. package/dist/Export/ExportDialog.js.map +1 -1
  36. package/dist/Export/ExportToolbarControls.d.ts +21 -1
  37. package/dist/Export/ExportToolbarControls.d.ts.map +1 -1
  38. package/dist/Export/ExportToolbarControls.js +161 -26
  39. package/dist/Export/ExportToolbarControls.js.map +1 -1
  40. package/dist/Export/export-destination.d.ts +3 -0
  41. package/dist/Export/export-destination.d.ts.map +1 -0
  42. package/dist/Export/export-destination.js +32 -0
  43. package/dist/Export/export-destination.js.map +1 -0
  44. package/dist/Export/index.d.ts +8 -4
  45. package/dist/Export/index.d.ts.map +1 -1
  46. package/dist/Export/index.js +4 -1
  47. package/dist/Export/index.js.map +1 -1
  48. package/dist/Export/public-api.d.ts +12 -0
  49. package/dist/Export/public-api.d.ts.map +1 -0
  50. package/dist/Export/public-api.js +9 -0
  51. package/dist/Export/public-api.js.map +1 -0
  52. package/dist/Export/run-export.d.ts +3 -1
  53. package/dist/Export/run-export.d.ts.map +1 -1
  54. package/dist/Export/run-export.js +58 -25
  55. package/dist/Export/run-export.js.map +1 -1
  56. package/dist/Export/transform-summaries.d.ts +7 -0
  57. package/dist/Export/transform-summaries.d.ts.map +1 -0
  58. package/dist/Export/transform-summaries.js +6 -0
  59. package/dist/Export/transform-summaries.js.map +1 -0
  60. package/dist/ExportDialog-MEUISWZX.js +9 -0
  61. package/dist/ExportDialog-MEUISWZX.js.map +1 -0
  62. package/dist/ExportToolbarControls-D2YDWOXW.js +373 -0
  63. package/dist/ExportToolbarControls-D2YDWOXW.js.map +1 -0
  64. package/dist/FileExplorer/FileExplorer.d.ts +26 -4
  65. package/dist/FileExplorer/FileExplorer.d.ts.map +1 -1
  66. package/dist/FileExplorer/FileExplorer.js +204 -29
  67. package/dist/FileExplorer/FileExplorer.js.map +1 -1
  68. package/dist/FileExplorer/FileTreeNode.d.ts +24 -3
  69. package/dist/FileExplorer/FileTreeNode.d.ts.map +1 -1
  70. package/dist/FileExplorer/FileTreeNode.js +27 -8
  71. package/dist/FileExplorer/FileTreeNode.js.map +1 -1
  72. package/dist/FileExplorer/index.d.ts +1 -1
  73. package/dist/FileExplorer/index.d.ts.map +1 -1
  74. package/dist/FileExplorer/useFileTree.d.ts +5 -3
  75. package/dist/FileExplorer/useFileTree.d.ts.map +1 -1
  76. package/dist/FileExplorer/useFileTree.js +173 -13
  77. package/dist/FileExplorer/useFileTree.js.map +1 -1
  78. package/dist/Git/GitAuthGuidanceDialog.d.ts +18 -0
  79. package/dist/Git/GitAuthGuidanceDialog.d.ts.map +1 -0
  80. package/dist/Git/GitAuthGuidanceDialog.js +27 -0
  81. package/dist/Git/GitAuthGuidanceDialog.js.map +1 -0
  82. package/dist/Git/GitBranchesDialog.d.ts +13 -0
  83. package/dist/Git/GitBranchesDialog.d.ts.map +1 -0
  84. package/dist/Git/GitBranchesDialog.js +59 -0
  85. package/dist/Git/GitBranchesDialog.js.map +1 -0
  86. package/dist/Git/GitCloneDialog.d.ts +14 -0
  87. package/dist/Git/GitCloneDialog.d.ts.map +1 -0
  88. package/dist/Git/GitCloneDialog.js +79 -0
  89. package/dist/Git/GitCloneDialog.js.map +1 -0
  90. package/dist/Git/GitCommitDialog.d.ts +12 -0
  91. package/dist/Git/GitCommitDialog.d.ts.map +1 -0
  92. package/dist/Git/GitCommitDialog.js +38 -0
  93. package/dist/Git/GitCommitDialog.js.map +1 -0
  94. package/dist/Git/GitConflictsDialog.d.ts +12 -0
  95. package/dist/Git/GitConflictsDialog.d.ts.map +1 -0
  96. package/dist/Git/GitConflictsDialog.js +17 -0
  97. package/dist/Git/GitConflictsDialog.js.map +1 -0
  98. package/dist/Git/GitContext.d.ts +89 -0
  99. package/dist/Git/GitContext.d.ts.map +1 -0
  100. package/dist/Git/GitContext.js +15 -0
  101. package/dist/Git/GitContext.js.map +1 -0
  102. package/dist/Git/GitDiffDialog.d.ts +20 -0
  103. package/dist/Git/GitDiffDialog.d.ts.map +1 -0
  104. package/dist/Git/GitDiffDialog.js +100 -0
  105. package/dist/Git/GitDiffDialog.js.map +1 -0
  106. package/dist/Git/GitDiffView.d.ts +23 -0
  107. package/dist/Git/GitDiffView.d.ts.map +1 -0
  108. package/dist/Git/GitDiffView.js +77 -0
  109. package/dist/Git/GitDiffView.js.map +1 -0
  110. package/dist/Git/GitHistoryDialog.d.ts +15 -0
  111. package/dist/Git/GitHistoryDialog.d.ts.map +1 -0
  112. package/dist/Git/GitHistoryDialog.js +107 -0
  113. package/dist/Git/GitHistoryDialog.js.map +1 -0
  114. package/dist/Git/GitStatusBar.d.ts +8 -0
  115. package/dist/Git/GitStatusBar.d.ts.map +1 -0
  116. package/dist/Git/GitStatusBar.js +49 -0
  117. package/dist/Git/GitStatusBar.js.map +1 -0
  118. package/dist/Git/GitToolbarControl.d.ts +15 -0
  119. package/dist/Git/GitToolbarControl.d.ts.map +1 -0
  120. package/dist/Git/GitToolbarControl.js +51 -0
  121. package/dist/Git/GitToolbarControl.js.map +1 -0
  122. package/dist/Git/GitUI.d.ts +14 -0
  123. package/dist/Git/GitUI.d.ts.map +1 -0
  124. package/dist/Git/GitUI.js +21 -0
  125. package/dist/Git/GitUI.js.map +1 -0
  126. package/dist/Git/commit-selection.d.ts +22 -0
  127. package/dist/Git/commit-selection.d.ts.map +1 -0
  128. package/dist/Git/commit-selection.js +47 -0
  129. package/dist/Git/commit-selection.js.map +1 -0
  130. package/dist/Git/git-clone-utils.d.ts +8 -0
  131. package/dist/Git/git-clone-utils.d.ts.map +1 -0
  132. package/dist/Git/git-clone-utils.js +26 -0
  133. package/dist/Git/git-clone-utils.js.map +1 -0
  134. package/dist/Git/git-status.d.ts +24 -0
  135. package/dist/Git/git-status.d.ts.map +1 -0
  136. package/dist/Git/git-status.js +105 -0
  137. package/dist/Git/git-status.js.map +1 -0
  138. package/dist/Git/useGit.d.ts +15 -0
  139. package/dist/Git/useGit.d.ts.map +1 -0
  140. package/dist/Git/useGit.js +206 -0
  141. package/dist/Git/useGit.js.map +1 -0
  142. package/dist/Git/useGitStatus.d.ts +17 -0
  143. package/dist/Git/useGitStatus.d.ts.map +1 -0
  144. package/dist/Git/useGitStatus.js +63 -0
  145. package/dist/Git/useGitStatus.js.map +1 -0
  146. package/dist/GitToolbarControl-LMIR4R7I.js +117 -0
  147. package/dist/GitToolbarControl-LMIR4R7I.js.map +1 -0
  148. package/dist/GitUI-KGF5MSNV.js +1048 -0
  149. package/dist/GitUI-KGF5MSNV.js.map +1 -0
  150. package/dist/LazyEditorShell-EF2BWRXU.js +6 -0
  151. package/dist/LazyEditorShell-EF2BWRXU.js.map +1 -0
  152. package/dist/Settings/Settings.d.ts +23 -0
  153. package/dist/Settings/Settings.d.ts.map +1 -0
  154. package/dist/Settings/Settings.js +22 -0
  155. package/dist/Settings/Settings.js.map +1 -0
  156. package/dist/Settings/public-api.d.ts +3 -0
  157. package/dist/Settings/public-api.d.ts.map +1 -0
  158. package/dist/Settings/public-api.js +2 -0
  159. package/dist/Settings/public-api.js.map +1 -0
  160. package/dist/WorkspacePicker/WorkspacePicker.d.ts +6 -1
  161. package/dist/WorkspacePicker/WorkspacePicker.d.ts.map +1 -1
  162. package/dist/WorkspacePicker/WorkspacePicker.js +16 -5
  163. package/dist/WorkspacePicker/WorkspacePicker.js.map +1 -1
  164. package/dist/chunk-3SAXDU2U.js +157 -0
  165. package/dist/chunk-3SAXDU2U.js.map +1 -0
  166. package/dist/chunk-4XXSWN3T.js +13 -0
  167. package/dist/chunk-4XXSWN3T.js.map +1 -0
  168. package/dist/chunk-5A4KEWKT.js +97 -0
  169. package/dist/chunk-5A4KEWKT.js.map +1 -0
  170. package/dist/chunk-AOVTHZU7.js +321 -0
  171. package/dist/chunk-AOVTHZU7.js.map +1 -0
  172. package/dist/chunk-DD4VFJQI.js +51 -0
  173. package/dist/chunk-DD4VFJQI.js.map +1 -0
  174. package/dist/chunk-GSNZSCIK.js +55 -0
  175. package/dist/chunk-GSNZSCIK.js.map +1 -0
  176. package/dist/chunk-VHDP4IPL.js +70 -0
  177. package/dist/chunk-VHDP4IPL.js.map +1 -0
  178. package/dist/chunk-ZI56BNB7.js +270 -0
  179. package/dist/chunk-ZI56BNB7.js.map +1 -0
  180. package/dist/components/Dialog.d.ts +22 -0
  181. package/dist/components/Dialog.d.ts.map +1 -0
  182. package/dist/components/Dialog.js +33 -0
  183. package/dist/components/Dialog.js.map +1 -0
  184. package/dist/editor.d.ts +10 -0
  185. package/dist/editor.d.ts.map +1 -0
  186. package/dist/editor.js +70 -0
  187. package/dist/editor.js.map +1 -0
  188. package/dist/export/index.d.ts +87 -0
  189. package/dist/export/index.js +26 -0
  190. package/dist/export/index.js.map +1 -0
  191. package/dist/hooks/index.d.ts +2 -1
  192. package/dist/hooks/index.d.ts.map +1 -1
  193. package/dist/hooks/index.js +1 -1
  194. package/dist/hooks/index.js.map +1 -1
  195. package/dist/hooks/useDocumentSession.d.ts +16 -0
  196. package/dist/hooks/useDocumentSession.d.ts.map +1 -0
  197. package/dist/hooks/useDocumentSession.js +18 -0
  198. package/dist/hooks/useDocumentSession.js.map +1 -0
  199. package/dist/icons.d.ts +11 -6
  200. package/dist/icons.d.ts.map +1 -1
  201. package/dist/icons.js +21 -20
  202. package/dist/icons.js.map +1 -1
  203. package/dist/index.d.ts +8 -5
  204. package/dist/index.d.ts.map +1 -1
  205. package/dist/index.js +4 -2
  206. package/dist/index.js.map +1 -1
  207. package/dist/preferences/theme.d.ts +18 -0
  208. package/dist/preferences/theme.d.ts.map +1 -0
  209. package/dist/preferences/theme.js +63 -0
  210. package/dist/preferences/theme.js.map +1 -0
  211. package/dist/provider-lease.d.ts +10 -0
  212. package/dist/provider-lease.d.ts.map +1 -0
  213. package/dist/provider-lease.js +42 -0
  214. package/dist/provider-lease.js.map +1 -0
  215. package/dist/run-export-ICTZITXC.js +10 -0
  216. package/dist/run-export-ICTZITXC.js.map +1 -0
  217. package/dist/settings/index.d.ts +28 -0
  218. package/dist/settings/index.js +12 -0
  219. package/dist/settings/index.js.map +1 -0
  220. package/package.json +27 -10
  221. package/src/AppMenu/AppMenu.tsx +169 -99
  222. package/src/AppMenu/index.ts +1 -1
  223. package/src/DocBlocksShell/DocBlocksShell.tsx +2183 -516
  224. package/src/DocBlocksShell/LazyEditorShell.ts +2 -0
  225. package/src/DocBlocksShell/UpdateAvailableNotice.tsx +60 -0
  226. package/src/DocBlocksShell/document-title.ts +19 -0
  227. package/src/DocBlocksShell/workspace-authority-barrier.ts +26 -0
  228. package/src/Export/DeferredExportToolbarControls.tsx +23 -0
  229. package/src/Export/ExportDialog.tsx +102 -27
  230. package/src/Export/ExportToolbarControls.tsx +343 -57
  231. package/src/Export/export-destination.ts +30 -0
  232. package/src/Export/index.ts +18 -4
  233. package/src/Export/public-api.ts +17 -0
  234. package/src/Export/run-export.ts +66 -29
  235. package/src/Export/transform-summaries.ts +14 -0
  236. package/src/FileExplorer/FileExplorer.tsx +284 -38
  237. package/src/FileExplorer/FileTreeNode.tsx +100 -8
  238. package/src/FileExplorer/index.ts +1 -1
  239. package/src/FileExplorer/useFileTree.ts +190 -16
  240. package/src/Git/GitAuthGuidanceDialog.tsx +84 -0
  241. package/src/Git/GitBranchesDialog.tsx +144 -0
  242. package/src/Git/GitCloneDialog.tsx +200 -0
  243. package/src/Git/GitCommitDialog.tsx +119 -0
  244. package/src/Git/GitConflictsDialog.tsx +62 -0
  245. package/src/Git/GitContext.tsx +88 -0
  246. package/src/Git/GitDiffDialog.tsx +147 -0
  247. package/src/Git/GitDiffView.tsx +105 -0
  248. package/src/Git/GitHistoryDialog.tsx +195 -0
  249. package/src/Git/GitStatusBar.tsx +157 -0
  250. package/src/Git/GitToolbarControl.tsx +123 -0
  251. package/src/Git/GitUI.tsx +68 -0
  252. package/src/Git/commit-selection.ts +63 -0
  253. package/src/Git/git-clone-utils.ts +23 -0
  254. package/src/Git/git-status.ts +113 -0
  255. package/src/Git/useGit.ts +279 -0
  256. package/src/Git/useGitStatus.ts +78 -0
  257. package/src/Settings/Settings.tsx +118 -0
  258. package/src/Settings/public-api.ts +8 -0
  259. package/src/WorkspacePicker/WorkspacePicker.tsx +62 -8
  260. package/src/components/Dialog.tsx +81 -0
  261. package/src/editor.ts +72 -0
  262. package/src/hooks/index.ts +2 -1
  263. package/src/hooks/useDocumentSession.ts +37 -0
  264. package/src/icons.tsx +33 -55
  265. package/src/index.ts +35 -5
  266. package/src/preferences/theme.ts +67 -0
  267. package/src/provider-lease.ts +52 -0
  268. package/src/styles/docblocks.css +2247 -77
  269. package/src/types/pwa-dom.d.ts +31 -0
  270. package/dist/hooks/useAutoSave.d.ts +0 -15
  271. package/dist/hooks/useAutoSave.d.ts.map +0 -1
  272. package/dist/hooks/useAutoSave.js +0 -83
  273. package/dist/hooks/useAutoSave.js.map +0 -1
  274. package/src/fonts/fonts.css +0 -362
  275. package/src/fonts/licenses/LICENSE-cormorant-garamond.txt +0 -93
  276. package/src/fonts/licenses/LICENSE-crimson-text.txt +0 -93
  277. package/src/fonts/licenses/LICENSE-dm-sans.txt +0 -93
  278. package/src/fonts/licenses/LICENSE-dm-serif-display.txt +0 -93
  279. package/src/fonts/licenses/LICENSE-hanken-grotesk.txt +0 -94
  280. package/src/fonts/licenses/LICENSE-ibm-plex-sans.txt +0 -93
  281. package/src/fonts/licenses/LICENSE-inter.txt +0 -93
  282. package/src/fonts/licenses/LICENSE-jetbrains-mono.txt +0 -93
  283. package/src/fonts/licenses/LICENSE-lora.txt +0 -93
  284. package/src/fonts/licenses/LICENSE-merriweather.txt +0 -93
  285. package/src/fonts/licenses/LICENSE-oswald.txt +0 -93
  286. package/src/fonts/licenses/LICENSE-playfair-display.txt +0 -93
  287. package/src/fonts/licenses/LICENSE-pt-serif.txt +0 -93
  288. package/src/fonts/licenses/LICENSE-roboto.txt +0 -93
  289. package/src/fonts/licenses/LICENSE-source-serif-4.txt +0 -93
  290. package/src/fonts/woff2/cormorant-garamond-400.woff2 +0 -0
  291. package/src/fonts/woff2/cormorant-garamond-700.woff2 +0 -0
  292. package/src/fonts/woff2/crimson-text-400.woff2 +0 -0
  293. package/src/fonts/woff2/crimson-text-400i.woff2 +0 -0
  294. package/src/fonts/woff2/crimson-text-700.woff2 +0 -0
  295. package/src/fonts/woff2/dm-sans-400.woff2 +0 -0
  296. package/src/fonts/woff2/dm-sans-400i.woff2 +0 -0
  297. package/src/fonts/woff2/dm-sans-500.woff2 +0 -0
  298. package/src/fonts/woff2/dm-sans-700.woff2 +0 -0
  299. package/src/fonts/woff2/dm-serif-display-400.woff2 +0 -0
  300. package/src/fonts/woff2/hanken-grotesk-400.woff2 +0 -0
  301. package/src/fonts/woff2/hanken-grotesk-400i.woff2 +0 -0
  302. package/src/fonts/woff2/hanken-grotesk-500.woff2 +0 -0
  303. package/src/fonts/woff2/hanken-grotesk-600.woff2 +0 -0
  304. package/src/fonts/woff2/hanken-grotesk-700.woff2 +0 -0
  305. package/src/fonts/woff2/ibm-plex-sans-400.woff2 +0 -0
  306. package/src/fonts/woff2/ibm-plex-sans-400i.woff2 +0 -0
  307. package/src/fonts/woff2/ibm-plex-sans-500.woff2 +0 -0
  308. package/src/fonts/woff2/ibm-plex-sans-600.woff2 +0 -0
  309. package/src/fonts/woff2/ibm-plex-sans-700.woff2 +0 -0
  310. package/src/fonts/woff2/inter-400.woff2 +0 -0
  311. package/src/fonts/woff2/inter-400i.woff2 +0 -0
  312. package/src/fonts/woff2/inter-500.woff2 +0 -0
  313. package/src/fonts/woff2/inter-600.woff2 +0 -0
  314. package/src/fonts/woff2/inter-700.woff2 +0 -0
  315. package/src/fonts/woff2/jetbrains-mono-400.woff2 +0 -0
  316. package/src/fonts/woff2/jetbrains-mono-400i.woff2 +0 -0
  317. package/src/fonts/woff2/jetbrains-mono-700.woff2 +0 -0
  318. package/src/fonts/woff2/lora-400.woff2 +0 -0
  319. package/src/fonts/woff2/lora-400i.woff2 +0 -0
  320. package/src/fonts/woff2/lora-700.woff2 +0 -0
  321. package/src/fonts/woff2/merriweather-400.woff2 +0 -0
  322. package/src/fonts/woff2/merriweather-700.woff2 +0 -0
  323. package/src/fonts/woff2/oswald-400.woff2 +0 -0
  324. package/src/fonts/woff2/oswald-700.woff2 +0 -0
  325. package/src/fonts/woff2/playfair-display-400.woff2 +0 -0
  326. package/src/fonts/woff2/playfair-display-700.woff2 +0 -0
  327. package/src/fonts/woff2/pt-serif-400.woff2 +0 -0
  328. package/src/fonts/woff2/pt-serif-700.woff2 +0 -0
  329. package/src/fonts/woff2/roboto-400.woff2 +0 -0
  330. package/src/fonts/woff2/roboto-400i.woff2 +0 -0
  331. package/src/fonts/woff2/roboto-700.woff2 +0 -0
  332. package/src/fonts/woff2/source-serif-4-400.woff2 +0 -0
  333. package/src/fonts/woff2/source-serif-4-400i.woff2 +0 -0
  334. package/src/fonts/woff2/source-serif-4-700.woff2 +0 -0
  335. package/src/hooks/useAutoSave.ts +0 -116
@@ -7,15 +7,21 @@
7
7
  * Must be rendered inside <EditorProvider> so useEditorContext() works.
8
8
  */
9
9
 
10
- import { useState, useCallback, useEffect, useRef, useMemo } from 'react';
10
+ import {
11
+ lazy,
12
+ Suspense,
13
+ useState,
14
+ useCallback,
15
+ useEffect,
16
+ useRef,
17
+ useMemo,
18
+ type ComponentType,
19
+ } from 'react';
11
20
  import { useEditorContext } from '@bendyline/squisq-editor-react';
12
21
  import { getThemeSummaries } from '@bendyline/squisq/schemas';
13
- import { getTransformStyleSummaries } from '@bendyline/squisq/transform';
14
22
  import { parseMarkdown } from '@bendyline/squisq/markdown';
15
- import { markdownToDoc } from '@bendyline/squisq/doc';
16
- import { VideoExportModal } from '@bendyline/squisq-video-react';
17
- import { PLAYER_BUNDLE } from '@bendyline/squisq-react/standalone-source';
18
23
  import type { ContentContainer } from '@bendyline/squisq/storage';
24
+ import type { VideoExportModalProps } from '@bendyline/squisq-video-react';
19
25
  import type { ExportOptions } from './export-options.js';
20
26
  import {
21
27
  DEFAULT_OPTIONS,
@@ -23,18 +29,80 @@ import {
23
29
  loadLastExportOptions,
24
30
  saveExportOptions,
25
31
  } from './export-options.js';
26
- import { ExportDialog } from './ExportDialog.js';
27
- import { runExport } from './run-export.js';
32
+ import type { ExportBlobSaver } from './run-export.js';
33
+ import { loadTransformStyleSummaries, type ExportSummaryOption } from './transform-summaries.js';
34
+
35
+ const ExportDialog = lazy(() =>
36
+ import('./ExportDialog.js').then((module) => ({ default: module.ExportDialog })),
37
+ );
38
+
39
+ let runExportModulePromise: Promise<typeof import('./run-export.js')> | null = null;
40
+
41
+ function loadRunExportModule(): Promise<typeof import('./run-export.js')> {
42
+ runExportModulePromise ??= import('./run-export.js');
43
+ return runExportModulePromise;
44
+ }
28
45
 
29
46
  export interface ExportToolbarControlsProps {
30
47
  /** Currently selected file path — used to derive the download filename. */
31
48
  selectedFile: string | null;
32
49
  /** Media container for resolving images during export. */
33
50
  mediaContainer?: ContentContainer | null;
51
+ /** Override the default browser download behavior for host-provided save flows. */
52
+ saveBlob?: ExportBlobSaver;
53
+ /** Optional host adapter for displaying, picking, and saving to a native target path. */
54
+ destinationAdapter?: ExportDestinationAdapter;
55
+ /** Render the trigger as a direct Export button instead of the overflow menu. */
56
+ trigger?: 'menu' | 'button';
57
+ /** Whether to show video export in the overflow menu. */
58
+ showVideoExport?: boolean;
59
+ }
60
+
61
+ /** Host-specific operations behind the shared export destination control. */
62
+ export interface ExportDestinationTarget {
63
+ grantId: string | null;
64
+ displayPath: string;
65
+ }
66
+
67
+ export interface ExportDestinationAdapter {
68
+ resolveTarget: (filename: string) => Promise<ExportDestinationTarget>;
69
+ pickTarget: (
70
+ filename: string,
71
+ currentTarget?: ExportDestinationTarget | null,
72
+ ) => Promise<ExportDestinationTarget | null>;
73
+ saveBlob: (
74
+ blob: Blob,
75
+ filename: string,
76
+ target?: ExportDestinationTarget | null,
77
+ ) => Promise<ExportDestinationTarget | null>;
78
+ hint?: string;
79
+ }
80
+
81
+ type ParsedMarkdown = ReturnType<typeof parseMarkdown>;
82
+
83
+ interface VideoExportModules {
84
+ Modal: ComponentType<VideoExportModalProps>;
85
+ markdownToDoc: (doc: ParsedMarkdown) => VideoExportModalProps['doc'];
86
+ playerScript: string;
87
+ }
88
+
89
+ let videoExportModulesPromise: Promise<VideoExportModules> | null = null;
90
+
91
+ function loadVideoExportModules(): Promise<VideoExportModules> {
92
+ videoExportModulesPromise ??= Promise.all([
93
+ import('@bendyline/squisq/doc'),
94
+ import('@bendyline/squisq-video-react'),
95
+ import('@bendyline/squisq-react/standalone-source'),
96
+ ]).then(([docModule, videoModule, playerModule]) => ({
97
+ Modal: videoModule.VideoExportModal,
98
+ markdownToDoc: docModule.markdownToDoc,
99
+ playerScript: playerModule.PLAYER_BUNDLE,
100
+ }));
101
+ return videoExportModulesPromise;
34
102
  }
35
103
 
36
104
  /** Build the quick-export label from saved options. */
37
- function quickLabel(opts: ExportOptions): string {
105
+ function quickLabel(opts: ExportOptions, transformSummaries: ExportSummaryOption[]): string {
38
106
  const baseExt = FORMAT_EXTENSIONS[opts.format].toUpperCase().replace('.', '');
39
107
  // Recursive HTML always emits a ZIP (multi-doc tree), regardless of
40
108
  // the saved `htmlBundle` value. Applies to both plain and rendered
@@ -58,7 +126,7 @@ function quickLabel(opts: ExportOptions): string {
58
126
  if (theme) parts.push(theme.name);
59
127
  }
60
128
  if (opts.format === 'pptx' && opts.transformStyle) {
61
- const transform = getTransformStyleSummaries().find((t) => t.id === opts.transformStyle);
129
+ const transform = transformSummaries.find((t) => t.id === opts.transformStyle);
62
130
  if (transform) parts.push(transform.name);
63
131
  }
64
132
 
@@ -71,12 +139,23 @@ function quickLabel(opts: ExportOptions): string {
71
139
  export function ExportToolbarControls({
72
140
  selectedFile,
73
141
  mediaContainer,
142
+ saveBlob,
143
+ destinationAdapter,
144
+ trigger = 'menu',
145
+ showVideoExport = true,
74
146
  }: ExportToolbarControlsProps) {
75
147
  const { markdownSource, markdownDoc } = useEditorContext();
76
148
  const [menuOpen, setMenuOpen] = useState(false);
77
149
  const [dialogOpen, setDialogOpen] = useState(false);
78
150
  const [videoModalOpen, setVideoModalOpen] = useState(false);
151
+ const [videoLoading, setVideoLoading] = useState(false);
152
+ const [videoLoadError, setVideoLoadError] = useState<string | null>(null);
153
+ const [videoModules, setVideoModules] = useState<VideoExportModules | null>(null);
154
+ const [videoDoc, setVideoDoc] = useState<VideoExportModalProps['doc'] | null>(null);
155
+ const [transformSummaries, setTransformSummaries] = useState<ExportSummaryOption[]>([]);
79
156
  const [exporting, setExporting] = useState(false);
157
+ const [destinationTarget, setDestinationTarget] = useState<ExportDestinationTarget | null>(null);
158
+ const destinationRequestRef = useRef(0);
80
159
  const menuRef = useRef<HTMLDivElement>(null);
81
160
 
82
161
  const lastOptions = loadLastExportOptions();
@@ -108,13 +187,6 @@ export function ExportToolbarControls({
108
187
  return docThemeId ? { ...base, themeId: docThemeId } : base;
109
188
  }, [lastOptions, docThemeId]);
110
189
 
111
- /** Build a Doc from the current markdown for video export. */
112
- const doc = useMemo(() => {
113
- if (!videoModalOpen) return null;
114
- const mdDoc = parseMarkdown(markdownSource);
115
- return markdownToDoc(mdDoc);
116
- }, [videoModalOpen, markdownSource]);
117
-
118
190
  // Close menu on outside click
119
191
  useEffect(() => {
120
192
  if (!menuOpen) return;
@@ -127,39 +199,150 @@ export function ExportToolbarControls({
127
199
  return () => document.removeEventListener('pointerdown', onPointerDown);
128
200
  }, [menuOpen]);
129
201
 
202
+ useEffect(() => {
203
+ if (
204
+ !menuOpen ||
205
+ lastOptions?.format !== 'pptx' ||
206
+ !lastOptions.transformStyle ||
207
+ transformSummaries.length > 0
208
+ ) {
209
+ return;
210
+ }
211
+
212
+ let cancelled = false;
213
+ loadTransformStyleSummaries()
214
+ .then((nextSummaries) => {
215
+ if (!cancelled) setTransformSummaries(nextSummaries);
216
+ })
217
+ .catch(() => {
218
+ if (!cancelled) setTransformSummaries([]);
219
+ });
220
+
221
+ return () => {
222
+ cancelled = true;
223
+ };
224
+ }, [lastOptions?.format, lastOptions?.transformStyle, menuOpen, transformSummaries.length]);
225
+
130
226
  const handleToggleMenu = useCallback(() => {
131
227
  setMenuOpen((prev) => !prev);
132
228
  }, []);
133
229
 
230
+ const refreshDestination = useCallback(
231
+ async (options: ExportOptions) => {
232
+ if (!destinationAdapter) return;
233
+
234
+ const requestId = destinationRequestRef.current + 1;
235
+ destinationRequestRef.current = requestId;
236
+
237
+ try {
238
+ const { buildExportFilename } = await loadRunExportModule();
239
+ const filename = buildExportFilename(selectedFile, options);
240
+ const target = await destinationAdapter.resolveTarget(filename);
241
+ if (destinationRequestRef.current === requestId) setDestinationTarget(target);
242
+ } catch {
243
+ if (destinationRequestRef.current === requestId) setDestinationTarget(null);
244
+ }
245
+ },
246
+ [destinationAdapter, selectedFile],
247
+ );
248
+
134
249
  const handleOpenDialog = useCallback(() => {
135
250
  setMenuOpen(false);
136
251
  setDialogOpen(true);
137
- }, []);
252
+ void refreshDestination(dialogInitial);
253
+ }, [dialogInitial, refreshDestination]);
138
254
 
139
255
  const handleCloseDialog = useCallback(() => {
140
256
  setDialogOpen(false);
141
257
  }, []);
142
258
 
143
- const handleOpenVideoModal = useCallback(() => {
259
+ const handleOpenVideoModal = useCallback(async () => {
144
260
  setMenuOpen(false);
145
261
  setVideoModalOpen(true);
146
- }, []);
262
+ setVideoLoading(true);
263
+ setVideoLoadError(null);
264
+
265
+ try {
266
+ const modules = videoModules ?? (await loadVideoExportModules());
267
+ setVideoModules(modules);
268
+ setVideoDoc(modules.markdownToDoc(parseMarkdown(markdownSource)));
269
+ } catch {
270
+ setVideoLoadError('Video export could not be loaded.');
271
+ } finally {
272
+ setVideoLoading(false);
273
+ }
274
+ }, [markdownSource, videoModules]);
147
275
 
148
276
  const handleCloseVideoModal = useCallback(() => {
149
277
  setVideoModalOpen(false);
278
+ setVideoDoc(null);
279
+ setVideoLoadError(null);
150
280
  }, []);
151
281
 
282
+ const handleOptionsChange = useCallback(
283
+ (options: ExportOptions) => {
284
+ void refreshDestination(options);
285
+ },
286
+ [refreshDestination],
287
+ );
288
+
289
+ const handlePickDestination = useCallback(
290
+ async (options: ExportOptions) => {
291
+ if (!destinationAdapter) return;
292
+ try {
293
+ const { buildExportFilename } = await loadRunExportModule();
294
+ const filename = buildExportFilename(selectedFile, options);
295
+ const pickedTarget = await destinationAdapter.pickTarget(filename, destinationTarget);
296
+ if (pickedTarget === null) return;
297
+ setDestinationTarget(pickedTarget);
298
+ } catch {
299
+ // Native hosts surface picker failures through their own UI channel.
300
+ }
301
+ },
302
+ [destinationAdapter, destinationTarget, selectedFile],
303
+ );
304
+
305
+ const saveToDestination = useCallback(
306
+ async (blob: Blob, filename: string, target: ExportDestinationTarget | null) => {
307
+ if (!destinationAdapter) return;
308
+ const savedTarget = await destinationAdapter.saveBlob(blob, filename, target);
309
+ if (savedTarget) setDestinationTarget(savedTarget);
310
+ },
311
+ [destinationAdapter],
312
+ );
313
+
314
+ const handleDestinationSaveBlob = useCallback(
315
+ async (blob: Blob, filename: string) => {
316
+ await saveToDestination(blob, filename, destinationTarget);
317
+ },
318
+ [destinationTarget, saveToDestination],
319
+ );
320
+
152
321
  const handleExport = useCallback(
153
322
  async (opts: ExportOptions) => {
154
323
  setExporting(true);
155
324
  try {
156
- await runExport(markdownSource, selectedFile, opts, mediaContainer);
325
+ const { runExport } = await loadRunExportModule();
326
+ await runExport(
327
+ markdownSource,
328
+ selectedFile,
329
+ opts,
330
+ mediaContainer,
331
+ destinationAdapter ? handleDestinationSaveBlob : saveBlob,
332
+ );
157
333
  } finally {
158
334
  setExporting(false);
159
335
  setDialogOpen(false);
160
336
  }
161
337
  },
162
- [markdownSource, selectedFile, mediaContainer],
338
+ [
339
+ markdownSource,
340
+ selectedFile,
341
+ mediaContainer,
342
+ destinationAdapter,
343
+ handleDestinationSaveBlob,
344
+ saveBlob,
345
+ ],
163
346
  );
164
347
 
165
348
  const handleQuickExport = useCallback(async () => {
@@ -168,58 +351,161 @@ export function ExportToolbarControls({
168
351
  setExporting(true);
169
352
  try {
170
353
  saveExportOptions(lastOptions);
171
- await runExport(markdownSource, selectedFile, lastOptions, mediaContainer);
354
+ const { runExport } = await loadRunExportModule();
355
+ let quickTarget: ExportDestinationTarget | null = null;
356
+ if (destinationAdapter) {
357
+ const { buildExportFilename } = await loadRunExportModule();
358
+ quickTarget = await destinationAdapter.resolveTarget(
359
+ buildExportFilename(selectedFile, lastOptions),
360
+ );
361
+ }
362
+ await runExport(
363
+ markdownSource,
364
+ selectedFile,
365
+ lastOptions,
366
+ mediaContainer,
367
+ destinationAdapter
368
+ ? async (blob, filename) => saveToDestination(blob, filename, quickTarget)
369
+ : saveBlob,
370
+ );
172
371
  } finally {
173
372
  setExporting(false);
174
373
  }
175
- }, [lastOptions, markdownSource, selectedFile, mediaContainer]);
374
+ }, [
375
+ destinationAdapter,
376
+ lastOptions,
377
+ markdownSource,
378
+ mediaContainer,
379
+ saveBlob,
380
+ saveToDestination,
381
+ selectedFile,
382
+ ]);
383
+
384
+ const LoadedVideoExportModal = videoModules?.Modal;
176
385
 
177
386
  return (
178
387
  <>
179
- <div className="db-toolbar-menu" ref={menuRef}>
388
+ {trigger === 'button' ? (
180
389
  <button
181
- className="db-toolbar-menu-trigger"
182
- onClick={handleToggleMenu}
183
- aria-label="More actions"
184
- title="More actions"
390
+ type="button"
391
+ className="squisq-toolbar-button db-toolbar-export-trigger"
392
+ onClick={handleOpenDialog}
393
+ disabled={exporting}
394
+ aria-label="Export document"
395
+ data-tooltip={exporting ? 'Exporting...' : 'Export document'}
185
396
  >
186
- &middot;&middot;&middot;
397
+ <ExportGlyph />
187
398
  </button>
399
+ ) : (
400
+ <div className="db-toolbar-menu" ref={menuRef}>
401
+ <button
402
+ className="db-toolbar-menu-trigger"
403
+ onClick={handleToggleMenu}
404
+ aria-label="More actions"
405
+ title="More actions"
406
+ >
407
+ &middot;&middot;&middot;
408
+ </button>
188
409
 
189
- {menuOpen && (
190
- <div className="db-toolbar-menu-dropdown">
191
- {lastOptions && (
192
- <button
193
- className="db-toolbar-menu-item"
194
- onClick={handleQuickExport}
195
- disabled={exporting}
196
- >
197
- {quickLabel(lastOptions)}
410
+ {menuOpen && (
411
+ <div className="db-toolbar-menu-dropdown">
412
+ {lastOptions && (
413
+ <button
414
+ className="db-toolbar-menu-item"
415
+ onClick={handleQuickExport}
416
+ disabled={exporting}
417
+ >
418
+ {quickLabel(lastOptions, transformSummaries)}
419
+ </button>
420
+ )}
421
+ <button className="db-toolbar-menu-item" onClick={handleOpenDialog}>
422
+ Export...
198
423
  </button>
199
- )}
200
- <button className="db-toolbar-menu-item" onClick={handleOpenDialog}>
201
- Export...
202
- </button>
203
- <div className="db-toolbar-menu-divider" />
204
- <button className="db-toolbar-menu-item" onClick={handleOpenVideoModal}>
205
- Export Video...
206
- </button>
207
- </div>
208
- )}
209
- </div>
424
+ {showVideoExport && (
425
+ <>
426
+ <div className="db-toolbar-menu-divider" />
427
+ <button className="db-toolbar-menu-item" onClick={handleOpenVideoModal}>
428
+ Export Video...
429
+ </button>
430
+ </>
431
+ )}
432
+ </div>
433
+ )}
434
+ </div>
435
+ )}
210
436
 
211
437
  {dialogOpen && (
212
- <ExportDialog
213
- initial={dialogInitial}
214
- exporting={exporting}
215
- onExport={handleExport}
216
- onClose={handleCloseDialog}
217
- />
438
+ <Suspense fallback={null}>
439
+ <ExportDialog
440
+ initial={dialogInitial}
441
+ exporting={exporting}
442
+ destination={
443
+ destinationAdapter
444
+ ? {
445
+ value: destinationTarget?.displayPath ?? '',
446
+ onPick: handlePickDestination,
447
+ hint: destinationAdapter.hint,
448
+ }
449
+ : undefined
450
+ }
451
+ onExport={handleExport}
452
+ onOptionsChange={destinationAdapter ? handleOptionsChange : undefined}
453
+ onClose={handleCloseDialog}
454
+ />
455
+ </Suspense>
218
456
  )}
219
457
 
220
- {videoModalOpen && doc && (
221
- <VideoExportModal doc={doc} playerScript={PLAYER_BUNDLE} onClose={handleCloseVideoModal} />
458
+ {videoModalOpen && (videoLoading || videoLoadError) && (
459
+ <div className="db-dialog-overlay">
460
+ <div className="db-dialog">
461
+ <div className="db-dialog-header">
462
+ <h2 className="db-dialog-title">Export Video</h2>
463
+ <button
464
+ className="db-dialog-close"
465
+ onClick={handleCloseVideoModal}
466
+ aria-label="Close"
467
+ >
468
+ &times;
469
+ </button>
470
+ </div>
471
+ <div className="db-dialog-body">
472
+ <p className="db-export-hint">{videoLoadError ?? 'Loading...'}</p>
473
+ </div>
474
+ </div>
475
+ </div>
222
476
  )}
477
+
478
+ {videoModalOpen &&
479
+ videoModules &&
480
+ LoadedVideoExportModal &&
481
+ videoDoc &&
482
+ !videoLoading &&
483
+ !videoLoadError && (
484
+ <LoadedVideoExportModal
485
+ doc={videoDoc}
486
+ playerScript={videoModules.playerScript}
487
+ onClose={handleCloseVideoModal}
488
+ />
489
+ )}
223
490
  </>
224
491
  );
225
492
  }
493
+
494
+ function ExportGlyph() {
495
+ return (
496
+ <svg
497
+ viewBox="0 0 16 16"
498
+ fill="none"
499
+ stroke="currentColor"
500
+ strokeWidth="1.5"
501
+ strokeLinecap="round"
502
+ strokeLinejoin="round"
503
+ aria-hidden="true"
504
+ >
505
+ <path d="M4.5 1.75h4.25L12 5v7.25a1.5 1.5 0 0 1-1.5 1.5h-6A1.5 1.5 0 0 1 3 12.25v-9a1.5 1.5 0 0 1 1.5-1.5z" />
506
+ <path d="M8.75 1.75V5h3.25" />
507
+ <path d="M6 8.75h4.5" />
508
+ <path d="M8.75 7 10.5 8.75 8.75 10.5" />
509
+ </svg>
510
+ );
511
+ }
@@ -0,0 +1,30 @@
1
+ /** Keep a user-edited target name while switching the selected export format. */
2
+ export function updateExportTargetExtension(targetPath: string, suggestedFilename: string): string {
3
+ const nextExtension = extensionOf(suggestedFilename);
4
+ if (!nextExtension) return targetPath;
5
+ if (!targetPath.trim()) return suggestedFilename;
6
+
7
+ const suffixIndex = firstSuffixIndex(targetPath);
8
+ const pathPart = suffixIndex === -1 ? targetPath : targetPath.slice(0, suffixIndex);
9
+ const suffix = suffixIndex === -1 ? '' : targetPath.slice(suffixIndex);
10
+ const separatorIndex = Math.max(pathPart.lastIndexOf('/'), pathPart.lastIndexOf('\\'));
11
+ const dotIndex = pathPart.lastIndexOf('.');
12
+ const stem = dotIndex > separatorIndex ? pathPart.slice(0, dotIndex) : pathPart;
13
+ return `${stem}${nextExtension}${suffix}`;
14
+ }
15
+
16
+ function extensionOf(value: string): string {
17
+ const suffixIndex = firstSuffixIndex(value);
18
+ const pathPart = suffixIndex === -1 ? value : value.slice(0, suffixIndex);
19
+ const separatorIndex = Math.max(pathPart.lastIndexOf('/'), pathPart.lastIndexOf('\\'));
20
+ const dotIndex = pathPart.lastIndexOf('.');
21
+ return dotIndex > separatorIndex ? pathPart.slice(dotIndex) : '';
22
+ }
23
+
24
+ function firstSuffixIndex(value: string): number {
25
+ const query = value.indexOf('?');
26
+ const fragment = value.indexOf('#');
27
+ if (query === -1) return fragment;
28
+ if (fragment === -1) return query;
29
+ return Math.min(query, fragment);
30
+ }
@@ -1,5 +1,19 @@
1
- export { ExportToolbarControls } from './ExportToolbarControls.js';
2
- export type { ExportToolbarControlsProps } from './ExportToolbarControls.js';
1
+ export { ExportToolbarControls } from './DeferredExportToolbarControls.js';
2
+ export type {
3
+ ExportDestinationAdapter,
4
+ ExportDestinationTarget,
5
+ ExportToolbarControlsProps,
6
+ } from './DeferredExportToolbarControls.js';
3
7
  export { ExportDialog } from './ExportDialog.js';
4
- export type { ExportDialogProps } from './ExportDialog.js';
5
- export type { ExportFormat, ExportOptions } from './export-options.js';
8
+ export type { ExportDestinationControl, ExportDialogProps } from './ExportDialog.js';
9
+ export {
10
+ DEFAULT_OPTIONS,
11
+ FORMAT_EXTENSIONS,
12
+ FORMAT_LABELS,
13
+ loadLastExportOptions,
14
+ saveExportOptions,
15
+ } from './export-options.js';
16
+ export type { ExportFormat, ExportOptions, HtmlBundle, HtmlStyle } from './export-options.js';
17
+ export { buildExportFilename, runExport } from './run-export.js';
18
+ export { updateExportTargetExtension } from './export-destination.js';
19
+ export type { ExportBlobSaver } from './run-export.js';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Narrow public export pipeline for hosts that provide their own editor shell.
3
+ * Keep toolbar/video controls out of this entry so consumers such as the VS
4
+ * Code webview do not eagerly transform the video worker graph.
5
+ */
6
+ export { ExportDialog } from './ExportDialog.js';
7
+ export type { ExportDestinationControl, ExportDialogProps } from './ExportDialog.js';
8
+ export {
9
+ DEFAULT_OPTIONS,
10
+ FORMAT_EXTENSIONS,
11
+ FORMAT_LABELS,
12
+ loadLastExportOptions,
13
+ saveExportOptions,
14
+ } from './export-options.js';
15
+ export type { ExportFormat, ExportOptions, HtmlBundle, HtmlStyle } from './export-options.js';
16
+ export { buildExportFilename, runExport } from './run-export.js';
17
+ export type { ExportBlobSaver } from './run-export.js';