@bendyline/docblocks-react 1.1.2 → 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 +31 -5
  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 +15 -2
  9. package/dist/DocBlocksShell/DocBlocksShell.d.ts.map +1 -1
  10. package/dist/DocBlocksShell/DocBlocksShell.js +1677 -298
  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 +20 -18
  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 +96 -11
  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 +30 -13
  55. package/dist/Export/run-export.js.map +1 -1
  56. package/dist/ExportDialog-MEUISWZX.js +9 -0
  57. package/dist/ExportDialog-MEUISWZX.js.map +1 -0
  58. package/dist/ExportToolbarControls-D2YDWOXW.js +373 -0
  59. package/dist/ExportToolbarControls-D2YDWOXW.js.map +1 -0
  60. package/dist/FileExplorer/FileExplorer.d.ts +26 -4
  61. package/dist/FileExplorer/FileExplorer.d.ts.map +1 -1
  62. package/dist/FileExplorer/FileExplorer.js +204 -29
  63. package/dist/FileExplorer/FileExplorer.js.map +1 -1
  64. package/dist/FileExplorer/FileTreeNode.d.ts +24 -3
  65. package/dist/FileExplorer/FileTreeNode.d.ts.map +1 -1
  66. package/dist/FileExplorer/FileTreeNode.js +27 -8
  67. package/dist/FileExplorer/FileTreeNode.js.map +1 -1
  68. package/dist/FileExplorer/index.d.ts +1 -1
  69. package/dist/FileExplorer/index.d.ts.map +1 -1
  70. package/dist/FileExplorer/useFileTree.d.ts +5 -3
  71. package/dist/FileExplorer/useFileTree.d.ts.map +1 -1
  72. package/dist/FileExplorer/useFileTree.js +173 -13
  73. package/dist/FileExplorer/useFileTree.js.map +1 -1
  74. package/dist/Git/GitAuthGuidanceDialog.d.ts +18 -0
  75. package/dist/Git/GitAuthGuidanceDialog.d.ts.map +1 -0
  76. package/dist/Git/GitAuthGuidanceDialog.js +27 -0
  77. package/dist/Git/GitAuthGuidanceDialog.js.map +1 -0
  78. package/dist/Git/GitBranchesDialog.d.ts +13 -0
  79. package/dist/Git/GitBranchesDialog.d.ts.map +1 -0
  80. package/dist/Git/GitBranchesDialog.js +59 -0
  81. package/dist/Git/GitBranchesDialog.js.map +1 -0
  82. package/dist/Git/GitCloneDialog.d.ts +14 -0
  83. package/dist/Git/GitCloneDialog.d.ts.map +1 -0
  84. package/dist/Git/GitCloneDialog.js +79 -0
  85. package/dist/Git/GitCloneDialog.js.map +1 -0
  86. package/dist/Git/GitCommitDialog.d.ts +12 -0
  87. package/dist/Git/GitCommitDialog.d.ts.map +1 -0
  88. package/dist/Git/GitCommitDialog.js +38 -0
  89. package/dist/Git/GitCommitDialog.js.map +1 -0
  90. package/dist/Git/GitConflictsDialog.d.ts +12 -0
  91. package/dist/Git/GitConflictsDialog.d.ts.map +1 -0
  92. package/dist/Git/GitConflictsDialog.js +17 -0
  93. package/dist/Git/GitConflictsDialog.js.map +1 -0
  94. package/dist/Git/GitContext.d.ts +89 -0
  95. package/dist/Git/GitContext.d.ts.map +1 -0
  96. package/dist/Git/GitContext.js +15 -0
  97. package/dist/Git/GitContext.js.map +1 -0
  98. package/dist/Git/GitDiffDialog.d.ts +20 -0
  99. package/dist/Git/GitDiffDialog.d.ts.map +1 -0
  100. package/dist/Git/GitDiffDialog.js +100 -0
  101. package/dist/Git/GitDiffDialog.js.map +1 -0
  102. package/dist/Git/GitDiffView.d.ts +23 -0
  103. package/dist/Git/GitDiffView.d.ts.map +1 -0
  104. package/dist/Git/GitDiffView.js +77 -0
  105. package/dist/Git/GitDiffView.js.map +1 -0
  106. package/dist/Git/GitHistoryDialog.d.ts +15 -0
  107. package/dist/Git/GitHistoryDialog.d.ts.map +1 -0
  108. package/dist/Git/GitHistoryDialog.js +107 -0
  109. package/dist/Git/GitHistoryDialog.js.map +1 -0
  110. package/dist/Git/GitStatusBar.d.ts +8 -0
  111. package/dist/Git/GitStatusBar.d.ts.map +1 -0
  112. package/dist/Git/GitStatusBar.js +49 -0
  113. package/dist/Git/GitStatusBar.js.map +1 -0
  114. package/dist/Git/GitToolbarControl.d.ts +15 -0
  115. package/dist/Git/GitToolbarControl.d.ts.map +1 -0
  116. package/dist/Git/GitToolbarControl.js +51 -0
  117. package/dist/Git/GitToolbarControl.js.map +1 -0
  118. package/dist/Git/GitUI.d.ts +14 -0
  119. package/dist/Git/GitUI.d.ts.map +1 -0
  120. package/dist/Git/GitUI.js +21 -0
  121. package/dist/Git/GitUI.js.map +1 -0
  122. package/dist/Git/commit-selection.d.ts +22 -0
  123. package/dist/Git/commit-selection.d.ts.map +1 -0
  124. package/dist/Git/commit-selection.js +47 -0
  125. package/dist/Git/commit-selection.js.map +1 -0
  126. package/dist/Git/git-clone-utils.d.ts +8 -0
  127. package/dist/Git/git-clone-utils.d.ts.map +1 -0
  128. package/dist/Git/git-clone-utils.js +26 -0
  129. package/dist/Git/git-clone-utils.js.map +1 -0
  130. package/dist/Git/git-status.d.ts +24 -0
  131. package/dist/Git/git-status.d.ts.map +1 -0
  132. package/dist/Git/git-status.js +105 -0
  133. package/dist/Git/git-status.js.map +1 -0
  134. package/dist/Git/useGit.d.ts +15 -0
  135. package/dist/Git/useGit.d.ts.map +1 -0
  136. package/dist/Git/useGit.js +206 -0
  137. package/dist/Git/useGit.js.map +1 -0
  138. package/dist/Git/useGitStatus.d.ts +17 -0
  139. package/dist/Git/useGitStatus.d.ts.map +1 -0
  140. package/dist/Git/useGitStatus.js +63 -0
  141. package/dist/Git/useGitStatus.js.map +1 -0
  142. package/dist/GitToolbarControl-LMIR4R7I.js +117 -0
  143. package/dist/GitToolbarControl-LMIR4R7I.js.map +1 -0
  144. package/dist/GitUI-KGF5MSNV.js +1048 -0
  145. package/dist/GitUI-KGF5MSNV.js.map +1 -0
  146. package/dist/LazyEditorShell-EF2BWRXU.js +6 -0
  147. package/dist/LazyEditorShell-EF2BWRXU.js.map +1 -0
  148. package/dist/Settings/Settings.d.ts +23 -0
  149. package/dist/Settings/Settings.d.ts.map +1 -0
  150. package/dist/Settings/Settings.js +22 -0
  151. package/dist/Settings/Settings.js.map +1 -0
  152. package/dist/Settings/public-api.d.ts +3 -0
  153. package/dist/Settings/public-api.d.ts.map +1 -0
  154. package/dist/Settings/public-api.js +2 -0
  155. package/dist/Settings/public-api.js.map +1 -0
  156. package/dist/WorkspacePicker/WorkspacePicker.d.ts +6 -1
  157. package/dist/WorkspacePicker/WorkspacePicker.d.ts.map +1 -1
  158. package/dist/WorkspacePicker/WorkspacePicker.js +16 -5
  159. package/dist/WorkspacePicker/WorkspacePicker.js.map +1 -1
  160. package/dist/chunk-3SAXDU2U.js +157 -0
  161. package/dist/chunk-3SAXDU2U.js.map +1 -0
  162. package/dist/chunk-4XXSWN3T.js +13 -0
  163. package/dist/chunk-4XXSWN3T.js.map +1 -0
  164. package/dist/chunk-5A4KEWKT.js +97 -0
  165. package/dist/chunk-5A4KEWKT.js.map +1 -0
  166. package/dist/chunk-AOVTHZU7.js +321 -0
  167. package/dist/chunk-AOVTHZU7.js.map +1 -0
  168. package/dist/chunk-DD4VFJQI.js +51 -0
  169. package/dist/chunk-DD4VFJQI.js.map +1 -0
  170. package/dist/chunk-GSNZSCIK.js +55 -0
  171. package/dist/chunk-GSNZSCIK.js.map +1 -0
  172. package/dist/chunk-VHDP4IPL.js +70 -0
  173. package/dist/chunk-VHDP4IPL.js.map +1 -0
  174. package/dist/chunk-ZI56BNB7.js +270 -0
  175. package/dist/chunk-ZI56BNB7.js.map +1 -0
  176. package/dist/components/Dialog.d.ts +22 -0
  177. package/dist/components/Dialog.d.ts.map +1 -0
  178. package/dist/components/Dialog.js +33 -0
  179. package/dist/components/Dialog.js.map +1 -0
  180. package/dist/editor.d.ts +10 -0
  181. package/dist/editor.d.ts.map +1 -0
  182. package/dist/editor.js +70 -0
  183. package/dist/editor.js.map +1 -0
  184. package/dist/export/index.d.ts +87 -0
  185. package/dist/export/index.js +26 -0
  186. package/dist/export/index.js.map +1 -0
  187. package/dist/hooks/index.d.ts +2 -1
  188. package/dist/hooks/index.d.ts.map +1 -1
  189. package/dist/hooks/index.js +1 -1
  190. package/dist/hooks/index.js.map +1 -1
  191. package/dist/hooks/useDocumentSession.d.ts +16 -0
  192. package/dist/hooks/useDocumentSession.d.ts.map +1 -0
  193. package/dist/hooks/useDocumentSession.js +18 -0
  194. package/dist/hooks/useDocumentSession.js.map +1 -0
  195. package/dist/icons.d.ts +11 -6
  196. package/dist/icons.d.ts.map +1 -1
  197. package/dist/icons.js +21 -20
  198. package/dist/icons.js.map +1 -1
  199. package/dist/index.d.ts +8 -5
  200. package/dist/index.d.ts.map +1 -1
  201. package/dist/index.js +4 -2
  202. package/dist/index.js.map +1 -1
  203. package/dist/preferences/theme.d.ts +18 -0
  204. package/dist/preferences/theme.d.ts.map +1 -0
  205. package/dist/preferences/theme.js +63 -0
  206. package/dist/preferences/theme.js.map +1 -0
  207. package/dist/provider-lease.d.ts +10 -0
  208. package/dist/provider-lease.d.ts.map +1 -0
  209. package/dist/provider-lease.js +42 -0
  210. package/dist/provider-lease.js.map +1 -0
  211. package/dist/run-export-ICTZITXC.js +10 -0
  212. package/dist/run-export-ICTZITXC.js.map +1 -0
  213. package/dist/settings/index.d.ts +28 -0
  214. package/dist/settings/index.js +12 -0
  215. package/dist/settings/index.js.map +1 -0
  216. package/package.json +24 -9
  217. package/src/AppMenu/AppMenu.tsx +169 -99
  218. package/src/AppMenu/index.ts +1 -1
  219. package/src/DocBlocksShell/DocBlocksShell.tsx +2157 -537
  220. package/src/DocBlocksShell/LazyEditorShell.ts +2 -0
  221. package/src/DocBlocksShell/UpdateAvailableNotice.tsx +60 -0
  222. package/src/DocBlocksShell/document-title.ts +19 -0
  223. package/src/DocBlocksShell/workspace-authority-barrier.ts +26 -0
  224. package/src/Export/DeferredExportToolbarControls.tsx +23 -0
  225. package/src/Export/ExportDialog.tsx +74 -20
  226. package/src/Export/ExportToolbarControls.tsx +238 -40
  227. package/src/Export/export-destination.ts +30 -0
  228. package/src/Export/index.ts +18 -4
  229. package/src/Export/public-api.ts +17 -0
  230. package/src/Export/run-export.ts +36 -11
  231. package/src/FileExplorer/FileExplorer.tsx +284 -38
  232. package/src/FileExplorer/FileTreeNode.tsx +100 -8
  233. package/src/FileExplorer/index.ts +1 -1
  234. package/src/FileExplorer/useFileTree.ts +190 -16
  235. package/src/Git/GitAuthGuidanceDialog.tsx +84 -0
  236. package/src/Git/GitBranchesDialog.tsx +144 -0
  237. package/src/Git/GitCloneDialog.tsx +200 -0
  238. package/src/Git/GitCommitDialog.tsx +119 -0
  239. package/src/Git/GitConflictsDialog.tsx +62 -0
  240. package/src/Git/GitContext.tsx +88 -0
  241. package/src/Git/GitDiffDialog.tsx +147 -0
  242. package/src/Git/GitDiffView.tsx +105 -0
  243. package/src/Git/GitHistoryDialog.tsx +195 -0
  244. package/src/Git/GitStatusBar.tsx +157 -0
  245. package/src/Git/GitToolbarControl.tsx +123 -0
  246. package/src/Git/GitUI.tsx +68 -0
  247. package/src/Git/commit-selection.ts +63 -0
  248. package/src/Git/git-clone-utils.ts +23 -0
  249. package/src/Git/git-status.ts +113 -0
  250. package/src/Git/useGit.ts +279 -0
  251. package/src/Git/useGitStatus.ts +78 -0
  252. package/src/Settings/Settings.tsx +118 -0
  253. package/src/Settings/public-api.ts +8 -0
  254. package/src/WorkspacePicker/WorkspacePicker.tsx +62 -8
  255. package/src/components/Dialog.tsx +81 -0
  256. package/src/editor.ts +72 -0
  257. package/src/hooks/index.ts +2 -1
  258. package/src/hooks/useDocumentSession.ts +37 -0
  259. package/src/icons.tsx +33 -55
  260. package/src/index.ts +35 -5
  261. package/src/preferences/theme.ts +67 -0
  262. package/src/provider-lease.ts +52 -0
  263. package/src/styles/docblocks.css +2174 -79
  264. package/src/types/pwa-dom.d.ts +31 -0
  265. package/dist/hooks/useAutoSave.d.ts +0 -15
  266. package/dist/hooks/useAutoSave.d.ts.map +0 -1
  267. package/dist/hooks/useAutoSave.js +0 -83
  268. package/dist/hooks/useAutoSave.js.map +0 -1
  269. package/dist/monaco-slim.d.ts +0 -19
  270. package/dist/monaco-slim.d.ts.map +0 -1
  271. package/dist/monaco-slim.js +0 -19
  272. package/dist/monaco-slim.js.map +0 -1
  273. package/src/fonts/fonts.css +0 -362
  274. package/src/fonts/licenses/LICENSE-cormorant-garamond.txt +0 -93
  275. package/src/fonts/licenses/LICENSE-crimson-text.txt +0 -93
  276. package/src/fonts/licenses/LICENSE-dm-sans.txt +0 -93
  277. package/src/fonts/licenses/LICENSE-dm-serif-display.txt +0 -93
  278. package/src/fonts/licenses/LICENSE-hanken-grotesk.txt +0 -94
  279. package/src/fonts/licenses/LICENSE-ibm-plex-sans.txt +0 -93
  280. package/src/fonts/licenses/LICENSE-inter.txt +0 -93
  281. package/src/fonts/licenses/LICENSE-jetbrains-mono.txt +0 -93
  282. package/src/fonts/licenses/LICENSE-lora.txt +0 -93
  283. package/src/fonts/licenses/LICENSE-merriweather.txt +0 -93
  284. package/src/fonts/licenses/LICENSE-oswald.txt +0 -93
  285. package/src/fonts/licenses/LICENSE-playfair-display.txt +0 -93
  286. package/src/fonts/licenses/LICENSE-pt-serif.txt +0 -93
  287. package/src/fonts/licenses/LICENSE-roboto.txt +0 -93
  288. package/src/fonts/licenses/LICENSE-source-serif-4.txt +0 -93
  289. package/src/fonts/woff2/cormorant-garamond-400.woff2 +0 -0
  290. package/src/fonts/woff2/cormorant-garamond-700.woff2 +0 -0
  291. package/src/fonts/woff2/crimson-text-400.woff2 +0 -0
  292. package/src/fonts/woff2/crimson-text-400i.woff2 +0 -0
  293. package/src/fonts/woff2/crimson-text-700.woff2 +0 -0
  294. package/src/fonts/woff2/dm-sans-400.woff2 +0 -0
  295. package/src/fonts/woff2/dm-sans-400i.woff2 +0 -0
  296. package/src/fonts/woff2/dm-sans-500.woff2 +0 -0
  297. package/src/fonts/woff2/dm-sans-700.woff2 +0 -0
  298. package/src/fonts/woff2/dm-serif-display-400.woff2 +0 -0
  299. package/src/fonts/woff2/hanken-grotesk-400.woff2 +0 -0
  300. package/src/fonts/woff2/hanken-grotesk-400i.woff2 +0 -0
  301. package/src/fonts/woff2/hanken-grotesk-500.woff2 +0 -0
  302. package/src/fonts/woff2/hanken-grotesk-600.woff2 +0 -0
  303. package/src/fonts/woff2/hanken-grotesk-700.woff2 +0 -0
  304. package/src/fonts/woff2/ibm-plex-sans-400.woff2 +0 -0
  305. package/src/fonts/woff2/ibm-plex-sans-400i.woff2 +0 -0
  306. package/src/fonts/woff2/ibm-plex-sans-500.woff2 +0 -0
  307. package/src/fonts/woff2/ibm-plex-sans-600.woff2 +0 -0
  308. package/src/fonts/woff2/ibm-plex-sans-700.woff2 +0 -0
  309. package/src/fonts/woff2/inter-400.woff2 +0 -0
  310. package/src/fonts/woff2/inter-400i.woff2 +0 -0
  311. package/src/fonts/woff2/inter-500.woff2 +0 -0
  312. package/src/fonts/woff2/inter-600.woff2 +0 -0
  313. package/src/fonts/woff2/inter-700.woff2 +0 -0
  314. package/src/fonts/woff2/jetbrains-mono-400.woff2 +0 -0
  315. package/src/fonts/woff2/jetbrains-mono-400i.woff2 +0 -0
  316. package/src/fonts/woff2/jetbrains-mono-700.woff2 +0 -0
  317. package/src/fonts/woff2/lora-400.woff2 +0 -0
  318. package/src/fonts/woff2/lora-400i.woff2 +0 -0
  319. package/src/fonts/woff2/lora-700.woff2 +0 -0
  320. package/src/fonts/woff2/merriweather-400.woff2 +0 -0
  321. package/src/fonts/woff2/merriweather-700.woff2 +0 -0
  322. package/src/fonts/woff2/oswald-400.woff2 +0 -0
  323. package/src/fonts/woff2/oswald-700.woff2 +0 -0
  324. package/src/fonts/woff2/playfair-display-400.woff2 +0 -0
  325. package/src/fonts/woff2/playfair-display-700.woff2 +0 -0
  326. package/src/fonts/woff2/pt-serif-400.woff2 +0 -0
  327. package/src/fonts/woff2/pt-serif-700.woff2 +0 -0
  328. package/src/fonts/woff2/roboto-400.woff2 +0 -0
  329. package/src/fonts/woff2/roboto-400i.woff2 +0 -0
  330. package/src/fonts/woff2/roboto-700.woff2 +0 -0
  331. package/src/fonts/woff2/source-serif-4-400.woff2 +0 -0
  332. package/src/fonts/woff2/source-serif-4-400i.woff2 +0 -0
  333. package/src/fonts/woff2/source-serif-4-700.woff2 +0 -0
  334. package/src/hooks/useAutoSave.ts +0 -116
  335. package/src/monaco-slim.ts +0 -20
@@ -0,0 +1,97 @@
1
+ // src/Git/GitContext.tsx
2
+ import { createContext, useContext } from "react";
3
+ var GitContext = createContext(null);
4
+ function useGitContext() {
5
+ return useContext(GitContext);
6
+ }
7
+
8
+ // src/Git/git-status.ts
9
+ var BADGE_GLYPHS = {
10
+ modified: "M",
11
+ added: "A",
12
+ untracked: "U",
13
+ renamed: "R",
14
+ deleted: "D",
15
+ conflicted: "!",
16
+ dir: "\u2022"
17
+ };
18
+ var BADGE_LABELS = {
19
+ modified: "modified",
20
+ added: "added",
21
+ untracked: "untracked",
22
+ renamed: "renamed",
23
+ deleted: "deleted",
24
+ conflicted: "has conflicts",
25
+ dir: "contains changes"
26
+ };
27
+ function normalise(path) {
28
+ return path.startsWith("/") ? path : `/${path}`;
29
+ }
30
+ function isDotPath(path) {
31
+ return normalise(path).split("/").some((segment) => segment.startsWith("."));
32
+ }
33
+ function badgeKindFor(change) {
34
+ if (change.conflicted) return "conflicted";
35
+ if (change.worktree === "untracked") return "untracked";
36
+ if (change.index === "deleted" || change.worktree === "deleted") return "deleted";
37
+ if (change.index === "renamed" || change.worktree === "renamed") return "renamed";
38
+ if (change.index === "added" || change.worktree === "added") return "added";
39
+ return "modified";
40
+ }
41
+ function buildBadgeMap(changes) {
42
+ const badges = /* @__PURE__ */ new Map();
43
+ const dirKinds = /* @__PURE__ */ new Map();
44
+ for (const change of changes) {
45
+ if (isDotPath(change.path)) continue;
46
+ const filePath = normalise(change.path);
47
+ const kind = badgeKindFor(change);
48
+ if (kind !== "deleted") {
49
+ badges.set(filePath, kind);
50
+ }
51
+ const segments = filePath.split("/").slice(1, -1);
52
+ let dir = "";
53
+ for (const segment of segments) {
54
+ dir += `/${segment}`;
55
+ const rollup = kind === "conflicted" ? "conflicted" : "dir";
56
+ if (dirKinds.get(dir) !== "conflicted") dirKinds.set(dir, rollup);
57
+ }
58
+ }
59
+ for (const [dir, kind] of dirKinds) {
60
+ if (!badges.has(dir)) badges.set(dir, kind);
61
+ }
62
+ return badges;
63
+ }
64
+ function formatAheadBehind(status) {
65
+ const parts = [];
66
+ if (status.ahead > 0) parts.push(`${status.ahead}\u2191`);
67
+ if (status.behind > 0) parts.push(`${status.behind}\u2193`);
68
+ return parts.join(" ");
69
+ }
70
+ function isFileDirty(status, path) {
71
+ if (!status || !path) return false;
72
+ const target = normalise(path);
73
+ return status.changes.some((c) => normalise(c.path) === target);
74
+ }
75
+ function conflictedPaths(status) {
76
+ if (!status) return [];
77
+ return status.changes.filter((c) => c.conflicted).map((c) => normalise(c.path));
78
+ }
79
+ function summarizeDirty(status) {
80
+ const count = status?.changes.length ?? 0;
81
+ if (count === 0) return "";
82
+ return count === 1 ? "1 change" : `${count} changes`;
83
+ }
84
+
85
+ export {
86
+ GitContext,
87
+ useGitContext,
88
+ BADGE_GLYPHS,
89
+ BADGE_LABELS,
90
+ badgeKindFor,
91
+ buildBadgeMap,
92
+ formatAheadBehind,
93
+ isFileDirty,
94
+ conflictedPaths,
95
+ summarizeDirty
96
+ };
97
+ //# sourceMappingURL=chunk-5A4KEWKT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Git/GitContext.tsx","../src/Git/git-status.ts"],"sourcesContent":["/**\n * GitContext — the seam between DocBlocksShell and every git UI surface.\n *\n * The shell calls useGit() once and provides the value here; the status\n * bar, file-tree badges, toolbar control, and dialogs all consume it.\n * Consumers must tolerate a null context (FileExplorer renders standalone\n * in tests and on surfaces with no git).\n */\n\nimport { createContext, useContext } from 'react';\nimport type {\n DocBlocksHostGitAPI,\n GitCapabilities,\n GitRepoDetection,\n GitStatus,\n} from '@bendyline/docblocks/host';\nimport type { FileSystemProvider } from '@bendyline/docblocks/filesystem';\nimport type { GitBadgeKind } from './git-status.js';\n\nexport type GitDialogState =\n | { kind: 'none' }\n | { kind: 'commit' }\n | { kind: 'branches'; createFocus?: boolean }\n | { kind: 'history'; path?: string }\n /** `revision` absent → working tree vs HEAD; present → that commit vs its parent. */\n | { kind: 'diff'; path: string; revision?: { sha: string } }\n | { kind: 'clone' }\n | {\n kind: 'auth-guidance';\n operation: 'push' | 'pull' | 'fetch' | 'clone' | 'pr';\n detail?: string;\n }\n | { kind: 'conflicts'; paths: string[] };\n\nexport type GitBusyKind = 'push' | 'pull' | 'fetch' | 'commit' | 'branch' | 'pr' | null;\n\nexport interface GitInlineResult {\n tone: 'info' | 'error';\n message: string;\n}\n\nexport interface GitValue {\n /** Tier 1 — Electron host with a working git. Gates the clone entry. */\n available: boolean;\n capabilities: GitCapabilities | null;\n /** Tier 2 — the active workspace root is a repository. Gates everything else. */\n repo: GitRepoDetection | null;\n /** Main-owned repository capability; never a native path. */\n repositoryId: string | null;\n /** Parsed web location of the first remote, when one exists and parses. */\n remoteWeb: { host: string; owner: string; repo: string; webUrl: string } | null;\n /** Raw host API for read-heavy dialogs (log, branches, file-at-revision). */\n gitApi: DocBlocksHostGitAPI | null;\n provider: FileSystemProvider | null;\n theme: 'light' | 'dark';\n\n status: GitStatus | null;\n badges: ReadonlyMap<string, GitBadgeKind>;\n busy: GitBusyKind;\n /** Latest operation outcome, surfaced in an aria-live region. */\n lastResult: GitInlineResult | null;\n\n refresh: () => void;\n /** Debounced refresh — used after autosave writes. */\n scheduleRefresh: () => void;\n\n /** Actions route their typed errors to dialogs/lastResult internally. */\n commit: (message: string, paths: string[]) => Promise<boolean>;\n push: () => Promise<void>;\n pull: () => Promise<void>;\n fetchRemote: () => Promise<void>;\n createBranch: (name: string) => Promise<boolean>;\n switchBranch: (name: string) => Promise<boolean>;\n /** Open the repo (or a file within it) on the remote's web host. */\n openOnRemote: (filePath?: string) => void;\n createPullRequest: () => Promise<void>;\n\n dialog: GitDialogState;\n openDialog: (dialog: GitDialogState) => void;\n closeDialog: () => void;\n}\n\nexport const GitContext = createContext<GitValue | null>(null);\n\n/** Null when no provider is mounted — callers must degrade gracefully. */\nexport function useGitContext(): GitValue | null {\n return useContext(GitContext);\n}\n","/**\n * Pure helpers mapping GitStatus onto UI concerns — file-tree badges,\n * ahead/behind chips, dirty summaries. No React, no host access.\n */\n\nimport type { GitFileChange, GitStatus } from '@bendyline/docblocks/host';\n\nexport type GitBadgeKind =\n | 'modified'\n | 'added'\n | 'untracked'\n | 'renamed'\n | 'deleted'\n | 'conflicted'\n | 'dir';\n\nexport const BADGE_GLYPHS: Record<GitBadgeKind, string> = {\n modified: 'M',\n added: 'A',\n untracked: 'U',\n renamed: 'R',\n deleted: 'D',\n conflicted: '!',\n dir: '•',\n};\n\nexport const BADGE_LABELS: Record<GitBadgeKind, string> = {\n modified: 'modified',\n added: 'added',\n untracked: 'untracked',\n renamed: 'renamed',\n deleted: 'deleted',\n conflicted: 'has conflicts',\n dir: 'contains changes',\n};\n\nfunction normalise(path: string): string {\n return path.startsWith('/') ? path : `/${path}`;\n}\n\n/** True when any path segment is a dot-entry (.git, .github, .gitignore…). */\nfunction isDotPath(path: string): boolean {\n return normalise(path)\n .split('/')\n .some((segment) => segment.startsWith('.'));\n}\n\nexport function badgeKindFor(change: GitFileChange): GitBadgeKind {\n if (change.conflicted) return 'conflicted';\n if (change.worktree === 'untracked') return 'untracked';\n if (change.index === 'deleted' || change.worktree === 'deleted') return 'deleted';\n if (change.index === 'renamed' || change.worktree === 'renamed') return 'renamed';\n if (change.index === 'added' || change.worktree === 'added') return 'added';\n return 'modified';\n}\n\n/**\n * Slash-prefixed path → badge kind, including directory rollups: any\n * ancestor directory of a changed file gets a 'dir' dot (or 'conflicted'\n * when a conflicted descendant wins). Deleted files aren't in the tree, so\n * they contribute only their ancestor rollup. Dot-paths are excluded so a\n * `.gitignore` edit doesn't inexplicably dot the root.\n */\nexport function buildBadgeMap(changes: readonly GitFileChange[]): Map<string, GitBadgeKind> {\n const badges = new Map<string, GitBadgeKind>();\n const dirKinds = new Map<string, GitBadgeKind>();\n\n for (const change of changes) {\n if (isDotPath(change.path)) continue;\n const filePath = normalise(change.path);\n const kind = badgeKindFor(change);\n if (kind !== 'deleted') {\n badges.set(filePath, kind);\n }\n const segments = filePath.split('/').slice(1, -1);\n let dir = '';\n for (const segment of segments) {\n dir += `/${segment}`;\n const rollup = kind === 'conflicted' ? 'conflicted' : 'dir';\n if (dirKinds.get(dir) !== 'conflicted') dirKinds.set(dir, rollup);\n }\n }\n for (const [dir, kind] of dirKinds) {\n if (!badges.has(dir)) badges.set(dir, kind);\n }\n return badges;\n}\n\n/** \"2↑ 1↓\" — empty string when neither applies. */\nexport function formatAheadBehind(status: Pick<GitStatus, 'ahead' | 'behind'>): string {\n const parts: string[] = [];\n if (status.ahead > 0) parts.push(`${status.ahead}↑`);\n if (status.behind > 0) parts.push(`${status.behind}↓`);\n return parts.join(' ');\n}\n\nexport function isFileDirty(status: GitStatus | null, path: string | null): boolean {\n if (!status || !path) return false;\n const target = normalise(path);\n return status.changes.some((c) => normalise(c.path) === target);\n}\n\nexport function conflictedPaths(status: GitStatus | null): string[] {\n if (!status) return [];\n return status.changes.filter((c) => c.conflicted).map((c) => normalise(c.path));\n}\n\n/** \"3 changes\" / \"1 change\" / \"\" when clean. */\nexport function summarizeDirty(status: GitStatus | null): string {\n const count = status?.changes.length ?? 0;\n if (count === 0) return '';\n return count === 1 ? '1 change' : `${count} changes`;\n}\n"],"mappings":";AASA,SAAS,eAAe,kBAAkB;AAyEnC,IAAM,aAAa,cAA+B,IAAI;AAGtD,SAAS,gBAAiC;AAC/C,SAAO,WAAW,UAAU;AAC9B;;;ACvEO,IAAM,eAA6C;AAAA,EACxD,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,KAAK;AACP;AAEO,IAAM,eAA6C;AAAA,EACxD,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,KAAK;AACP;AAEA,SAAS,UAAU,MAAsB;AACvC,SAAO,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI;AAC/C;AAGA,SAAS,UAAU,MAAuB;AACxC,SAAO,UAAU,IAAI,EAClB,MAAM,GAAG,EACT,KAAK,CAAC,YAAY,QAAQ,WAAW,GAAG,CAAC;AAC9C;AAEO,SAAS,aAAa,QAAqC;AAChE,MAAI,OAAO,WAAY,QAAO;AAC9B,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,MAAI,OAAO,UAAU,aAAa,OAAO,aAAa,UAAW,QAAO;AACxE,MAAI,OAAO,UAAU,aAAa,OAAO,aAAa,UAAW,QAAO;AACxE,MAAI,OAAO,UAAU,WAAW,OAAO,aAAa,QAAS,QAAO;AACpE,SAAO;AACT;AASO,SAAS,cAAc,SAA8D;AAC1F,QAAM,SAAS,oBAAI,IAA0B;AAC7C,QAAM,WAAW,oBAAI,IAA0B;AAE/C,aAAW,UAAU,SAAS;AAC5B,QAAI,UAAU,OAAO,IAAI,EAAG;AAC5B,UAAM,WAAW,UAAU,OAAO,IAAI;AACtC,UAAM,OAAO,aAAa,MAAM;AAChC,QAAI,SAAS,WAAW;AACtB,aAAO,IAAI,UAAU,IAAI;AAAA,IAC3B;AACA,UAAM,WAAW,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE;AAChD,QAAI,MAAM;AACV,eAAW,WAAW,UAAU;AAC9B,aAAO,IAAI,OAAO;AAClB,YAAM,SAAS,SAAS,eAAe,eAAe;AACtD,UAAI,SAAS,IAAI,GAAG,MAAM,aAAc,UAAS,IAAI,KAAK,MAAM;AAAA,IAClE;AAAA,EACF;AACA,aAAW,CAAC,KAAK,IAAI,KAAK,UAAU;AAClC,QAAI,CAAC,OAAO,IAAI,GAAG,EAAG,QAAO,IAAI,KAAK,IAAI;AAAA,EAC5C;AACA,SAAO;AACT;AAGO,SAAS,kBAAkB,QAAqD;AACrF,QAAM,QAAkB,CAAC;AACzB,MAAI,OAAO,QAAQ,EAAG,OAAM,KAAK,GAAG,OAAO,KAAK,QAAG;AACnD,MAAI,OAAO,SAAS,EAAG,OAAM,KAAK,GAAG,OAAO,MAAM,QAAG;AACrD,SAAO,MAAM,KAAK,GAAG;AACvB;AAEO,SAAS,YAAY,QAA0B,MAA8B;AAClF,MAAI,CAAC,UAAU,CAAC,KAAM,QAAO;AAC7B,QAAM,SAAS,UAAU,IAAI;AAC7B,SAAO,OAAO,QAAQ,KAAK,CAAC,MAAM,UAAU,EAAE,IAAI,MAAM,MAAM;AAChE;AAEO,SAAS,gBAAgB,QAAoC;AAClE,MAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,SAAO,OAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,UAAU,EAAE,IAAI,CAAC;AAChF;AAGO,SAAS,eAAe,QAAkC;AAC/D,QAAM,QAAQ,QAAQ,QAAQ,UAAU;AACxC,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO,UAAU,IAAI,aAAa,GAAG,KAAK;AAC5C;","names":[]}
@@ -0,0 +1,321 @@
1
+ import {
2
+ loadTransformStyleSummaries
3
+ } from "./chunk-4XXSWN3T.js";
4
+ import {
5
+ FORMAT_LABELS,
6
+ saveExportOptions
7
+ } from "./chunk-DD4VFJQI.js";
8
+
9
+ // src/Export/ExportDialog.tsx
10
+ import { useState, useCallback, useEffect, useMemo, useRef } from "react";
11
+ import { getThemeSummaries } from "@bendyline/squisq/schemas";
12
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
+ var FORMATS = ["pdf", "docx", "pptx", "html", "md"];
14
+ var FORMAT_CHIP_LABELS = {
15
+ pdf: "PDF",
16
+ docx: "Word",
17
+ pptx: "PowerPoint",
18
+ html: "HTML",
19
+ md: "Markdown"
20
+ };
21
+ var HTML_STYLE_CHIPS = [
22
+ {
23
+ key: "plain",
24
+ label: "Plain",
25
+ hint: "A lightweight static HTML document."
26
+ },
27
+ {
28
+ key: "rendered",
29
+ label: "Rendered",
30
+ hint: "Renders via SquisqPlayer with themes and playback support."
31
+ }
32
+ ];
33
+ var HTML_BUNDLE_CHIPS = [
34
+ {
35
+ key: "single",
36
+ label: "Single file",
37
+ hint: "One .html file with images embedded as base64 data URIs."
38
+ },
39
+ {
40
+ key: "zip",
41
+ label: "ZIP archive",
42
+ hint: "A .zip with index.html plus separate image (and JS) files."
43
+ }
44
+ ];
45
+ function ChipRadioGroup({
46
+ name,
47
+ value,
48
+ options,
49
+ onChange
50
+ }) {
51
+ return /* @__PURE__ */ jsx("div", { className: "db-export-chips", role: "radiogroup", "aria-label": name, children: options.map((opt) => {
52
+ const active = opt.key === value;
53
+ return /* @__PURE__ */ jsx(
54
+ "button",
55
+ {
56
+ type: "button",
57
+ role: "radio",
58
+ "aria-checked": active,
59
+ className: `db-export-chip${active ? " db-export-chip--active" : ""}`,
60
+ onClick: () => onChange(opt.key),
61
+ title: opt.title,
62
+ children: opt.label
63
+ },
64
+ opt.key
65
+ );
66
+ }) });
67
+ }
68
+ function ExportDialog({
69
+ initial,
70
+ exporting,
71
+ destination,
72
+ onExport,
73
+ onOptionsChange,
74
+ onClose
75
+ }) {
76
+ const [format, setFormat] = useState(initial.format);
77
+ const [themeId, setThemeId] = useState(initial.themeId);
78
+ const [transformStyle, setTransformStyle] = useState(initial.transformStyle);
79
+ const [pageSize, setPageSize] = useState(initial.pageSize);
80
+ const [htmlStyle, setHtmlStyle] = useState(initial.htmlStyle);
81
+ const [htmlBundle, setHtmlBundle] = useState(initial.htmlBundle);
82
+ const [includeLinkedDocs, setIncludeLinkedDocs] = useState(initial.includeLinkedDocs);
83
+ const [entryAsIndex, setEntryAsIndex] = useState(initial.entryAsIndex);
84
+ const [transforms, setTransforms] = useState([]);
85
+ const dialogRef = useRef(null);
86
+ const themes = getThemeSummaries();
87
+ const showTheme = format === "docx" || format === "pdf" || format === "pptx" || format === "html";
88
+ const showTransform = format === "pptx";
89
+ const showPageSize = format === "pdf";
90
+ const showHtmlOptions = format === "html";
91
+ const showIncludeLinked = format === "html";
92
+ const showHtmlBundle = showHtmlOptions && !includeLinkedDocs;
93
+ const showEntryAsIndex = showHtmlOptions && (htmlBundle === "single" || includeLinkedDocs);
94
+ useEffect(() => {
95
+ if (!showTransform) return;
96
+ let cancelled = false;
97
+ loadTransformStyleSummaries().then((nextTransforms) => {
98
+ if (!cancelled) setTransforms(nextTransforms);
99
+ }).catch(() => {
100
+ if (!cancelled) setTransforms([]);
101
+ });
102
+ return () => {
103
+ cancelled = true;
104
+ };
105
+ }, [showTransform]);
106
+ const currentOptions = useMemo(
107
+ () => ({
108
+ format,
109
+ themeId,
110
+ transformStyle,
111
+ pageSize,
112
+ htmlStyle,
113
+ htmlBundle,
114
+ includeLinkedDocs: showIncludeLinked && includeLinkedDocs,
115
+ entryAsIndex: showEntryAsIndex && entryAsIndex
116
+ }),
117
+ [
118
+ format,
119
+ themeId,
120
+ transformStyle,
121
+ pageSize,
122
+ htmlStyle,
123
+ htmlBundle,
124
+ includeLinkedDocs,
125
+ entryAsIndex,
126
+ showIncludeLinked,
127
+ showEntryAsIndex
128
+ ]
129
+ );
130
+ useEffect(() => {
131
+ onOptionsChange?.(currentOptions);
132
+ }, [currentOptions, onOptionsChange]);
133
+ const handleExport = useCallback(() => {
134
+ saveExportOptions(currentOptions);
135
+ onExport(currentOptions);
136
+ }, [currentOptions, onExport]);
137
+ useEffect(() => {
138
+ const onKey = (e) => {
139
+ if (e.key === "Escape") onClose();
140
+ };
141
+ window.addEventListener("keydown", onKey);
142
+ return () => window.removeEventListener("keydown", onKey);
143
+ }, [onClose]);
144
+ const handleBackdropClick = useCallback(
145
+ (e) => {
146
+ if (e.target === e.currentTarget) onClose();
147
+ },
148
+ [onClose]
149
+ );
150
+ return /* @__PURE__ */ jsx("div", { className: "db-dialog-overlay", onClick: handleBackdropClick, children: /* @__PURE__ */ jsxs("div", { className: "db-dialog db-export-dialog", ref: dialogRef, children: [
151
+ /* @__PURE__ */ jsxs("div", { className: "db-dialog-header", children: [
152
+ /* @__PURE__ */ jsx("h2", { className: "db-dialog-title", children: "Export Document" }),
153
+ /* @__PURE__ */ jsx("button", { className: "db-dialog-close", onClick: onClose, "aria-label": "Close", children: "\xD7" })
154
+ ] }),
155
+ /* @__PURE__ */ jsxs("div", { className: "db-dialog-body", children: [
156
+ /* @__PURE__ */ jsxs("div", { className: "db-export-field", children: [
157
+ /* @__PURE__ */ jsx("span", { className: "db-export-label", children: "Format" }),
158
+ /* @__PURE__ */ jsx(
159
+ ChipRadioGroup,
160
+ {
161
+ name: "Format",
162
+ value: format,
163
+ options: FORMATS.map((f) => ({
164
+ key: f,
165
+ label: FORMAT_CHIP_LABELS[f],
166
+ title: FORMAT_LABELS[f]
167
+ })),
168
+ onChange: setFormat
169
+ }
170
+ )
171
+ ] }),
172
+ destination && /* @__PURE__ */ jsxs("div", { className: "db-export-field", children: [
173
+ /* @__PURE__ */ jsx("label", { className: "db-export-label", htmlFor: "db-export-path", children: "Export to" }),
174
+ /* @__PURE__ */ jsxs("div", { className: "db-export-path-row", children: [
175
+ /* @__PURE__ */ jsx(
176
+ "input",
177
+ {
178
+ id: "db-export-path",
179
+ className: "db-export-path-input",
180
+ value: destination.value,
181
+ readOnly: true,
182
+ disabled: exporting,
183
+ spellCheck: false,
184
+ autoComplete: "off"
185
+ }
186
+ ),
187
+ /* @__PURE__ */ jsx(
188
+ "button",
189
+ {
190
+ type: "button",
191
+ className: "db-export-path-pick",
192
+ onClick: () => void destination.onPick(currentOptions),
193
+ disabled: exporting,
194
+ "aria-label": "Choose export location",
195
+ title: "Choose export location",
196
+ children: "..."
197
+ }
198
+ )
199
+ ] }),
200
+ destination.hint && /* @__PURE__ */ jsx("span", { className: "db-export-hint", children: destination.hint })
201
+ ] }),
202
+ showHtmlOptions && /* @__PURE__ */ jsxs(Fragment, { children: [
203
+ /* @__PURE__ */ jsxs("div", { className: "db-export-field", children: [
204
+ /* @__PURE__ */ jsx("span", { className: "db-export-label", children: "Style" }),
205
+ /* @__PURE__ */ jsx(
206
+ ChipRadioGroup,
207
+ {
208
+ name: "Style",
209
+ value: htmlStyle,
210
+ options: HTML_STYLE_CHIPS,
211
+ onChange: setHtmlStyle
212
+ }
213
+ ),
214
+ /* @__PURE__ */ jsx("span", { className: "db-export-hint", children: HTML_STYLE_CHIPS.find((c) => c.key === htmlStyle)?.hint })
215
+ ] }),
216
+ showHtmlBundle && /* @__PURE__ */ jsxs("div", { className: "db-export-field", children: [
217
+ /* @__PURE__ */ jsx("span", { className: "db-export-label", children: "Bundle" }),
218
+ /* @__PURE__ */ jsx(
219
+ ChipRadioGroup,
220
+ {
221
+ name: "Bundle",
222
+ value: htmlBundle,
223
+ options: HTML_BUNDLE_CHIPS,
224
+ onChange: setHtmlBundle
225
+ }
226
+ ),
227
+ /* @__PURE__ */ jsx("span", { className: "db-export-hint", children: HTML_BUNDLE_CHIPS.find((c) => c.key === htmlBundle)?.hint })
228
+ ] }),
229
+ showIncludeLinked && /* @__PURE__ */ jsxs("div", { className: "db-export-field", children: [
230
+ /* @__PURE__ */ jsxs("label", { className: "db-export-checkbox", children: [
231
+ /* @__PURE__ */ jsx(
232
+ "input",
233
+ {
234
+ type: "checkbox",
235
+ checked: includeLinkedDocs,
236
+ onChange: (e) => setIncludeLinkedDocs(e.target.checked)
237
+ }
238
+ ),
239
+ /* @__PURE__ */ jsx("span", { children: "Include linked-to documents" })
240
+ ] }),
241
+ /* @__PURE__ */ jsx("span", { className: "db-export-hint", children: includeLinkedDocs ? "Follows relative .md links from this page and bundles every reachable document as its own .html in a ZIP. Cross-doc links rewrite from .md to .html." : "Only this document is exported." })
242
+ ] }),
243
+ showEntryAsIndex && /* @__PURE__ */ jsxs("div", { className: "db-export-field", children: [
244
+ /* @__PURE__ */ jsxs("label", { className: "db-export-checkbox", children: [
245
+ /* @__PURE__ */ jsx(
246
+ "input",
247
+ {
248
+ type: "checkbox",
249
+ checked: entryAsIndex,
250
+ onChange: (e) => setEntryAsIndex(e.target.checked)
251
+ }
252
+ ),
253
+ /* @__PURE__ */ jsx("span", { children: "Name entry page index.html" })
254
+ ] }),
255
+ /* @__PURE__ */ jsx("span", { className: "db-export-hint", children: entryAsIndex ? includeLinkedDocs ? "Renames this page to index.html in the ZIP and rewrites any cross-doc links pointing back at it. Drops straight into a static-site host." : "Downloads as index.html instead of the document name. Drops straight into a static-site host." : "Exports under the document name." })
256
+ ] })
257
+ ] }),
258
+ showTheme && /* @__PURE__ */ jsxs("div", { className: "db-export-field", children: [
259
+ /* @__PURE__ */ jsx("label", { className: "db-export-label", htmlFor: "db-export-theme", children: "Theme" }),
260
+ /* @__PURE__ */ jsx(
261
+ "select",
262
+ {
263
+ id: "db-export-theme",
264
+ className: "db-export-select",
265
+ value: themeId,
266
+ onChange: (e) => setThemeId(e.target.value),
267
+ children: themes.map((t) => /* @__PURE__ */ jsx("option", { value: t.id, children: t.name }, t.id))
268
+ }
269
+ ),
270
+ /* @__PURE__ */ jsx("span", { className: "db-export-hint", children: themes.find((t) => t.id === themeId)?.description })
271
+ ] }),
272
+ showTransform && /* @__PURE__ */ jsxs("div", { className: "db-export-field", children: [
273
+ /* @__PURE__ */ jsx("label", { className: "db-export-label", htmlFor: "db-export-transform", children: "Transform" }),
274
+ /* @__PURE__ */ jsx(
275
+ "select",
276
+ {
277
+ id: "db-export-transform",
278
+ className: "db-export-select",
279
+ value: transformStyle,
280
+ onChange: (e) => setTransformStyle(e.target.value),
281
+ children: transforms.length === 0 ? /* @__PURE__ */ jsx("option", { value: transformStyle, children: "Loading..." }) : transforms.map((t) => /* @__PURE__ */ jsx("option", { value: t.id, children: t.name }, t.id))
282
+ }
283
+ ),
284
+ /* @__PURE__ */ jsx("span", { className: "db-export-hint", children: transforms.find((t) => t.id === transformStyle)?.description })
285
+ ] }),
286
+ showPageSize && /* @__PURE__ */ jsxs("div", { className: "db-export-field", children: [
287
+ /* @__PURE__ */ jsx("label", { className: "db-export-label", htmlFor: "db-export-pagesize", children: "Page Size" }),
288
+ /* @__PURE__ */ jsxs(
289
+ "select",
290
+ {
291
+ id: "db-export-pagesize",
292
+ className: "db-export-select",
293
+ value: pageSize,
294
+ onChange: (e) => setPageSize(e.target.value),
295
+ children: [
296
+ /* @__PURE__ */ jsx("option", { value: "letter", children: "US Letter" }),
297
+ /* @__PURE__ */ jsx("option", { value: "a4", children: "A4" })
298
+ ]
299
+ }
300
+ )
301
+ ] })
302
+ ] }),
303
+ /* @__PURE__ */ jsxs("div", { className: "db-export-footer", children: [
304
+ /* @__PURE__ */ jsx("button", { className: "db-export-btn db-export-btn--secondary", onClick: onClose, children: "Cancel" }),
305
+ /* @__PURE__ */ jsx(
306
+ "button",
307
+ {
308
+ className: "db-export-btn db-export-btn--primary",
309
+ onClick: handleExport,
310
+ disabled: exporting,
311
+ children: exporting ? "Exporting..." : "Export"
312
+ }
313
+ )
314
+ ] })
315
+ ] }) });
316
+ }
317
+
318
+ export {
319
+ ExportDialog
320
+ };
321
+ //# sourceMappingURL=chunk-AOVTHZU7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Export/ExportDialog.tsx"],"sourcesContent":["/**\n * ExportDialog — modal for choosing export format and options.\n */\n\nimport { useState, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { getThemeSummaries } from '@bendyline/squisq/schemas';\nimport type { ExportFormat, ExportOptions, HtmlBundle, HtmlStyle } from './export-options.js';\nimport { FORMAT_LABELS, saveExportOptions } from './export-options.js';\nimport { loadTransformStyleSummaries, type ExportSummaryOption } from './transform-summaries.js';\n\nexport interface ExportDialogProps {\n /** Initial options (pre-populated from last export). */\n initial: ExportOptions;\n /** Whether the export is currently running. */\n exporting: boolean;\n /** Optional host-provided destination path control. */\n destination?: ExportDestinationControl;\n /** Called when the user confirms the export. */\n onExport: (options: ExportOptions) => void;\n /** Called whenever the currently selected options change. */\n onOptionsChange?: (options: ExportOptions) => void;\n /** Called when the dialog is dismissed. */\n onClose: () => void;\n}\n\nexport interface ExportDestinationControl {\n value: string;\n onPick: (options: ExportOptions) => void | Promise<void>;\n hint?: string;\n}\n\nconst FORMATS: ExportFormat[] = ['pdf', 'docx', 'pptx', 'html', 'md'];\n\n/** Short labels for the Format chip row. The fuller `FORMAT_LABELS` list\n * is still used as a tooltip so users can confirm the file extension. */\nconst FORMAT_CHIP_LABELS: Record<ExportFormat, string> = {\n pdf: 'PDF',\n docx: 'Word',\n pptx: 'PowerPoint',\n html: 'HTML',\n md: 'Markdown',\n};\n\nconst HTML_STYLE_CHIPS: { key: HtmlStyle; label: string; hint: string }[] = [\n {\n key: 'plain',\n label: 'Plain',\n hint: 'A lightweight static HTML document.',\n },\n {\n key: 'rendered',\n label: 'Rendered',\n hint: 'Renders via SquisqPlayer with themes and playback support.',\n },\n];\n\nconst HTML_BUNDLE_CHIPS: { key: HtmlBundle; label: string; hint: string }[] = [\n {\n key: 'single',\n label: 'Single file',\n hint: 'One .html file with images embedded as base64 data URIs.',\n },\n {\n key: 'zip',\n label: 'ZIP archive',\n hint: 'A .zip with index.html plus separate image (and JS) files.',\n },\n];\n\ninterface ChipOption<T extends string> {\n key: T;\n label: string;\n title?: string;\n}\n\nfunction ChipRadioGroup<T extends string>({\n name,\n value,\n options,\n onChange,\n}: {\n name: string;\n value: T;\n options: ChipOption<T>[];\n onChange: (next: T) => void;\n}) {\n return (\n <div className=\"db-export-chips\" role=\"radiogroup\" aria-label={name}>\n {options.map((opt) => {\n const active = opt.key === value;\n return (\n <button\n key={opt.key}\n type=\"button\"\n role=\"radio\"\n aria-checked={active}\n className={`db-export-chip${active ? ' db-export-chip--active' : ''}`}\n onClick={() => onChange(opt.key)}\n title={opt.title}\n >\n {opt.label}\n </button>\n );\n })}\n </div>\n );\n}\n\nexport function ExportDialog({\n initial,\n exporting,\n destination,\n onExport,\n onOptionsChange,\n onClose,\n}: ExportDialogProps) {\n const [format, setFormat] = useState<ExportFormat>(initial.format);\n const [themeId, setThemeId] = useState(initial.themeId);\n const [transformStyle, setTransformStyle] = useState(initial.transformStyle);\n const [pageSize, setPageSize] = useState(initial.pageSize);\n const [htmlStyle, setHtmlStyle] = useState<HtmlStyle>(initial.htmlStyle);\n const [htmlBundle, setHtmlBundle] = useState<HtmlBundle>(initial.htmlBundle);\n const [includeLinkedDocs, setIncludeLinkedDocs] = useState<boolean>(initial.includeLinkedDocs);\n const [entryAsIndex, setEntryAsIndex] = useState<boolean>(initial.entryAsIndex);\n const [transforms, setTransforms] = useState<ExportSummaryOption[]>([]);\n const dialogRef = useRef<HTMLDivElement>(null);\n\n const themes = getThemeSummaries();\n\n // Both HTML styles honor themes now: rendered HTML through the\n // SquisqPlayer's theme system, plain HTML through squisq's\n // `markdownDocToPlainHtml` which emits theme-driven CSS variables\n // and Google Fonts links. Show the dropdown for any export format\n // whose pipeline actually applies the picked theme.\n const showTheme = format === 'docx' || format === 'pdf' || format === 'pptx' || format === 'html';\n const showTransform = format === 'pptx';\n const showPageSize = format === 'pdf';\n const showHtmlOptions = format === 'html';\n // Both HTML styles now have a recursive bundle: plain via\n // `markdownDocsToPlainHtmlBundle`, rendered via\n // `markdownDocsToHtmlBundle` (which rewrites Doc-tree links to\n // `.html` before SquisqPlayer serialization). So the option applies\n // to any HTML export.\n const showIncludeLinked = format === 'html';\n // Multi-doc output is inherently a directory tree, so when recursion\n // is on the Bundle row would only confuse — ZIP is the only valid\n // packaging. Hide the chip row and surface the implication in a hint.\n const showHtmlBundle = showHtmlOptions && !includeLinkedDocs;\n // `entryAsIndex` is only honored in pipelines where we control the\n // output filename ourselves:\n // • single-file HTML downloads → renames `<doc>.html` → `index.html`\n // • recursive bundles → passed through to squisq's bundle helpers\n // In the single-doc ZIP path, squisq's `docToHtmlZip` and our plain-\n // HTML zip writer always emit `index.html` inside the archive, so the\n // checkbox has no observable effect — hide it to avoid surfacing an\n // inert control.\n const showEntryAsIndex = showHtmlOptions && (htmlBundle === 'single' || includeLinkedDocs);\n\n useEffect(() => {\n if (!showTransform) return;\n let cancelled = false;\n\n loadTransformStyleSummaries()\n .then((nextTransforms) => {\n if (!cancelled) setTransforms(nextTransforms);\n })\n .catch(() => {\n if (!cancelled) setTransforms([]);\n });\n\n return () => {\n cancelled = true;\n };\n }, [showTransform]);\n\n const currentOptions = useMemo<ExportOptions>(\n () => ({\n format,\n themeId,\n transformStyle,\n pageSize,\n htmlStyle,\n htmlBundle,\n includeLinkedDocs: showIncludeLinked && includeLinkedDocs,\n entryAsIndex: showEntryAsIndex && entryAsIndex,\n }),\n [\n format,\n themeId,\n transformStyle,\n pageSize,\n htmlStyle,\n htmlBundle,\n includeLinkedDocs,\n entryAsIndex,\n showIncludeLinked,\n showEntryAsIndex,\n ],\n );\n\n useEffect(() => {\n onOptionsChange?.(currentOptions);\n }, [currentOptions, onOptionsChange]);\n\n const handleExport = useCallback(() => {\n saveExportOptions(currentOptions);\n onExport(currentOptions);\n }, [currentOptions, onExport]);\n\n // Close on Escape\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [onClose]);\n\n // Close on backdrop click\n const handleBackdropClick = useCallback(\n (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n },\n [onClose],\n );\n\n return (\n <div className=\"db-dialog-overlay\" onClick={handleBackdropClick}>\n <div className=\"db-dialog db-export-dialog\" ref={dialogRef}>\n <div className=\"db-dialog-header\">\n <h2 className=\"db-dialog-title\">Export Document</h2>\n <button className=\"db-dialog-close\" onClick={onClose} aria-label=\"Close\">\n &times;\n </button>\n </div>\n\n <div className=\"db-dialog-body\">\n {/* Format — chip radio row for fast switching */}\n <div className=\"db-export-field\">\n <span className=\"db-export-label\">Format</span>\n <ChipRadioGroup\n name=\"Format\"\n value={format}\n options={FORMATS.map((f) => ({\n key: f,\n label: FORMAT_CHIP_LABELS[f],\n title: FORMAT_LABELS[f],\n }))}\n onChange={setFormat}\n />\n </div>\n\n {destination && (\n <div className=\"db-export-field\">\n <label className=\"db-export-label\" htmlFor=\"db-export-path\">\n Export to\n </label>\n <div className=\"db-export-path-row\">\n <input\n id=\"db-export-path\"\n className=\"db-export-path-input\"\n value={destination.value}\n readOnly\n disabled={exporting}\n spellCheck={false}\n autoComplete=\"off\"\n />\n <button\n type=\"button\"\n className=\"db-export-path-pick\"\n onClick={() => void destination.onPick(currentOptions)}\n disabled={exporting}\n aria-label=\"Choose export location\"\n title=\"Choose export location\"\n >\n ...\n </button>\n </div>\n {destination.hint && <span className=\"db-export-hint\">{destination.hint}</span>}\n </div>\n )}\n\n {/* HTML style + bundle (HTML only) — also chip rows */}\n {showHtmlOptions && (\n <>\n <div className=\"db-export-field\">\n <span className=\"db-export-label\">Style</span>\n <ChipRadioGroup\n name=\"Style\"\n value={htmlStyle}\n options={HTML_STYLE_CHIPS}\n onChange={setHtmlStyle}\n />\n <span className=\"db-export-hint\">\n {HTML_STYLE_CHIPS.find((c) => c.key === htmlStyle)?.hint}\n </span>\n </div>\n {showHtmlBundle && (\n <div className=\"db-export-field\">\n <span className=\"db-export-label\">Bundle</span>\n <ChipRadioGroup\n name=\"Bundle\"\n value={htmlBundle}\n options={HTML_BUNDLE_CHIPS}\n onChange={setHtmlBundle}\n />\n <span className=\"db-export-hint\">\n {HTML_BUNDLE_CHIPS.find((c) => c.key === htmlBundle)?.hint}\n </span>\n </div>\n )}\n {showIncludeLinked && (\n <div className=\"db-export-field\">\n <label className=\"db-export-checkbox\">\n <input\n type=\"checkbox\"\n checked={includeLinkedDocs}\n onChange={(e) => setIncludeLinkedDocs(e.target.checked)}\n />\n <span>Include linked-to documents</span>\n </label>\n <span className=\"db-export-hint\">\n {includeLinkedDocs\n ? 'Follows relative .md links from this page and bundles every reachable document as its own .html in a ZIP. Cross-doc links rewrite from .md to .html.'\n : 'Only this document is exported.'}\n </span>\n </div>\n )}\n {showEntryAsIndex && (\n <div className=\"db-export-field\">\n <label className=\"db-export-checkbox\">\n <input\n type=\"checkbox\"\n checked={entryAsIndex}\n onChange={(e) => setEntryAsIndex(e.target.checked)}\n />\n <span>Name entry page index.html</span>\n </label>\n <span className=\"db-export-hint\">\n {entryAsIndex\n ? includeLinkedDocs\n ? 'Renames this page to index.html in the ZIP and rewrites any cross-doc links pointing back at it. Drops straight into a static-site host.'\n : 'Downloads as index.html instead of the document name. Drops straight into a static-site host.'\n : 'Exports under the document name.'}\n </span>\n </div>\n )}\n </>\n )}\n\n {/* Theme */}\n {showTheme && (\n <div className=\"db-export-field\">\n <label className=\"db-export-label\" htmlFor=\"db-export-theme\">\n Theme\n </label>\n <select\n id=\"db-export-theme\"\n className=\"db-export-select\"\n value={themeId}\n onChange={(e) => setThemeId(e.target.value)}\n >\n {themes.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n <span className=\"db-export-hint\">\n {themes.find((t) => t.id === themeId)?.description}\n </span>\n </div>\n )}\n\n {/* Transform (PPTX only) */}\n {showTransform && (\n <div className=\"db-export-field\">\n <label className=\"db-export-label\" htmlFor=\"db-export-transform\">\n Transform\n </label>\n <select\n id=\"db-export-transform\"\n className=\"db-export-select\"\n value={transformStyle}\n onChange={(e) => setTransformStyle(e.target.value)}\n >\n {transforms.length === 0 ? (\n <option value={transformStyle}>Loading...</option>\n ) : (\n transforms.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))\n )}\n </select>\n <span className=\"db-export-hint\">\n {transforms.find((t) => t.id === transformStyle)?.description}\n </span>\n </div>\n )}\n\n {/* Page size (PDF only) */}\n {showPageSize && (\n <div className=\"db-export-field\">\n <label className=\"db-export-label\" htmlFor=\"db-export-pagesize\">\n Page Size\n </label>\n <select\n id=\"db-export-pagesize\"\n className=\"db-export-select\"\n value={pageSize}\n onChange={(e) => setPageSize(e.target.value as 'letter' | 'a4')}\n >\n <option value=\"letter\">US Letter</option>\n <option value=\"a4\">A4</option>\n </select>\n </div>\n )}\n </div>\n\n <div className=\"db-export-footer\">\n <button className=\"db-export-btn db-export-btn--secondary\" onClick={onClose}>\n Cancel\n </button>\n <button\n className=\"db-export-btn db-export-btn--primary\"\n onClick={handleExport}\n disabled={exporting}\n >\n {exporting ? 'Exporting...' : 'Export'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,51 @@
1
+ // src/Export/export-options.ts
2
+ var FORMAT_LABELS = {
3
+ docx: "Word Document (.docx)",
4
+ pdf: "PDF (.pdf)",
5
+ pptx: "PowerPoint (.pptx)",
6
+ md: "Markdown (.md)",
7
+ html: "HTML (.html)"
8
+ };
9
+ var FORMAT_EXTENSIONS = {
10
+ docx: ".docx",
11
+ pdf: ".pdf",
12
+ pptx: ".pptx",
13
+ md: ".md",
14
+ html: ".html"
15
+ };
16
+ var STORAGE_KEY = "docblocks-export-options";
17
+ var DEFAULT_OPTIONS = {
18
+ format: "pdf",
19
+ themeId: "standard",
20
+ transformStyle: "documentary",
21
+ pageSize: "letter",
22
+ htmlStyle: "plain",
23
+ htmlBundle: "single",
24
+ includeLinkedDocs: false,
25
+ entryAsIndex: false
26
+ };
27
+ function loadLastExportOptions() {
28
+ try {
29
+ const raw = localStorage.getItem(STORAGE_KEY);
30
+ if (!raw) return null;
31
+ const parsed = JSON.parse(raw);
32
+ return { ...DEFAULT_OPTIONS, ...parsed };
33
+ } catch {
34
+ return null;
35
+ }
36
+ }
37
+ function saveExportOptions(options) {
38
+ try {
39
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(options));
40
+ } catch {
41
+ }
42
+ }
43
+
44
+ export {
45
+ FORMAT_LABELS,
46
+ FORMAT_EXTENSIONS,
47
+ DEFAULT_OPTIONS,
48
+ loadLastExportOptions,
49
+ saveExportOptions
50
+ };
51
+ //# sourceMappingURL=chunk-DD4VFJQI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Export/export-options.ts"],"sourcesContent":["/**\n * Export option types and localStorage persistence for quick-export.\n */\n\nexport type ExportFormat = 'docx' | 'pdf' | 'pptx' | 'md' | 'html';\n\n/** Visual style for HTML export. */\nexport type HtmlStyle =\n /** Render via SquisqPlayer (themed, embeds player bundle). */\n | 'rendered'\n /** Plain semantic HTML — small, no JS, no playback. */\n | 'plain';\n\n/** Packaging for HTML export. */\nexport type HtmlBundle =\n /** Single self-contained .html file (images base64-embedded). */\n | 'single'\n /** ZIP containing index.html + asset files. */\n | 'zip';\n\nexport interface ExportOptions {\n format: ExportFormat;\n themeId: string;\n /** Transform style for PPTX — controls how content is segmented and styled. */\n transformStyle: string;\n /** Only applies to PDF */\n pageSize: 'letter' | 'a4';\n /** HTML rendering style. Only applies to format=html. */\n htmlStyle: HtmlStyle;\n /** HTML bundle layout. Only applies to format=html. */\n htmlBundle: HtmlBundle;\n /**\n * Recursive HTML bundle: walk relative `.md` links from the entry\n * document, render every reachable sibling/child page, and rewrite\n * cross-doc links from `.md` → `.html`. The output is a ZIP\n * regardless of `htmlBundle` because multi-doc output needs a\n * directory tree. Supported for both plain (`markdownDocsToPlainHtmlBundle`)\n * and rendered (`markdownDocsToHtmlBundle`) HTML styles. Only\n * meaningful when `format === 'html'`.\n */\n includeLinkedDocs: boolean;\n /**\n * Rename the entry page from `<basename>.html` to `index.html` so the\n * export drops straight into a static-site host that expects an\n * `index.html` landing page. For recursive bundles, cross-doc links\n * targeting the entry also rewrite to `index.html` so siblings don't\n * 404. For a single-doc HTML download, this just renames the file.\n * Only meaningful when `format === 'html'`.\n */\n entryAsIndex: boolean;\n}\n\nexport const FORMAT_LABELS: Record<ExportFormat, string> = {\n docx: 'Word Document (.docx)',\n pdf: 'PDF (.pdf)',\n pptx: 'PowerPoint (.pptx)',\n md: 'Markdown (.md)',\n html: 'HTML (.html)',\n};\n\nexport const FORMAT_EXTENSIONS: Record<ExportFormat, string> = {\n docx: '.docx',\n pdf: '.pdf',\n pptx: '.pptx',\n md: '.md',\n html: '.html',\n};\n\nconst STORAGE_KEY = 'docblocks-export-options';\n\nexport const DEFAULT_OPTIONS: ExportOptions = {\n format: 'pdf',\n themeId: 'standard',\n transformStyle: 'documentary',\n pageSize: 'letter',\n htmlStyle: 'plain',\n htmlBundle: 'single',\n includeLinkedDocs: false,\n entryAsIndex: false,\n};\n\nexport function loadLastExportOptions(): ExportOptions | null {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as Partial<ExportOptions>;\n return { ...DEFAULT_OPTIONS, ...parsed };\n } catch {\n return null;\n }\n}\n\nexport function saveExportOptions(options: ExportOptions): void {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(options));\n } catch {\n // Ignore storage errors\n }\n}\n"],"mappings":";AAoDO,IAAM,gBAA8C;AAAA,EACzD,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AACR;AAEO,IAAM,oBAAkD;AAAA,EAC7D,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AACR;AAEA,IAAM,cAAc;AAEb,IAAM,kBAAiC;AAAA,EAC5C,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,cAAc;AAChB;AAEO,SAAS,wBAA8C;AAC5D,MAAI;AACF,UAAM,MAAM,aAAa,QAAQ,WAAW;AAC5C,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,EAAE,GAAG,iBAAiB,GAAG,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,kBAAkB,SAA8B;AAC9D,MAAI;AACF,iBAAa,QAAQ,aAAa,KAAK,UAAU,OAAO,CAAC;AAAA,EAC3D,QAAQ;AAAA,EAER;AACF;","names":[]}
@@ -0,0 +1,55 @@
1
+ // src/components/Dialog.tsx
2
+ import { useCallback, useEffect, useRef } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ function Dialog({
5
+ title,
6
+ onClose,
7
+ size = "default",
8
+ children,
9
+ footer,
10
+ initialFocusRef,
11
+ closeOnBackdrop = true
12
+ }) {
13
+ const closeButtonRef = useRef(null);
14
+ useEffect(() => {
15
+ const onKey = (e) => {
16
+ if (e.key === "Escape") onClose();
17
+ };
18
+ window.addEventListener("keydown", onKey);
19
+ return () => window.removeEventListener("keydown", onKey);
20
+ }, [onClose]);
21
+ useEffect(() => {
22
+ const target = initialFocusRef?.current ?? closeButtonRef.current;
23
+ target?.focus();
24
+ }, []);
25
+ const handleBackdropClick = useCallback(
26
+ (e) => {
27
+ if (closeOnBackdrop && e.target === e.currentTarget) onClose();
28
+ },
29
+ [closeOnBackdrop, onClose]
30
+ );
31
+ const sizeClass = size === "wide" ? " db-dialog--wide" : size === "full" ? " db-dialog--full" : "";
32
+ return /* @__PURE__ */ jsx("div", { className: "db-dialog-overlay", onClick: handleBackdropClick, children: /* @__PURE__ */ jsxs("div", { className: `db-dialog${sizeClass}`, role: "dialog", "aria-modal": "true", "aria-label": title, children: [
33
+ /* @__PURE__ */ jsxs("div", { className: "db-dialog-header", children: [
34
+ /* @__PURE__ */ jsx("h2", { className: "db-dialog-title", children: title }),
35
+ /* @__PURE__ */ jsx(
36
+ "button",
37
+ {
38
+ ref: closeButtonRef,
39
+ type: "button",
40
+ className: "db-dialog-close",
41
+ onClick: onClose,
42
+ "aria-label": "Close",
43
+ children: "\xD7"
44
+ }
45
+ )
46
+ ] }),
47
+ /* @__PURE__ */ jsx("div", { className: "db-dialog-body", children }),
48
+ footer && /* @__PURE__ */ jsx("div", { className: "db-dialog-footer", children: footer })
49
+ ] }) });
50
+ }
51
+
52
+ export {
53
+ Dialog
54
+ };
55
+ //# sourceMappingURL=chunk-GSNZSCIK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Dialog.tsx"],"sourcesContent":["/**\n * Dialog — shared modal primitive.\n *\n * Promotes the `db-dialog-overlay` / `db-dialog` pattern used by the\n * settings dialogs into a reusable component, adding aria-modal and\n * initial focus. Escape and (by default) backdrop clicks close it.\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\n\nexport interface DialogProps {\n title: string;\n onClose: () => void;\n /** default 380px / wide 560px / full min(1100px, 94vw) column. */\n size?: 'default' | 'wide' | 'full';\n children: React.ReactNode;\n /** Right-aligned action row below the body. */\n footer?: React.ReactNode;\n /** Element to focus on open; defaults to the close button. */\n initialFocusRef?: React.RefObject<HTMLElement | null>;\n /** Set false when a stray backdrop click would lose user input. */\n closeOnBackdrop?: boolean;\n}\n\nexport function Dialog({\n title,\n onClose,\n size = 'default',\n children,\n footer,\n initialFocusRef,\n closeOnBackdrop = true,\n}: DialogProps) {\n const closeButtonRef = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [onClose]);\n\n useEffect(() => {\n const target = initialFocusRef?.current ?? closeButtonRef.current;\n target?.focus();\n // Focus only on mount — refocusing on every re-render would fight the user.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const handleBackdropClick = useCallback(\n (e: React.MouseEvent) => {\n if (closeOnBackdrop && e.target === e.currentTarget) onClose();\n },\n [closeOnBackdrop, onClose],\n );\n\n const sizeClass =\n size === 'wide' ? ' db-dialog--wide' : size === 'full' ? ' db-dialog--full' : '';\n\n return (\n <div className=\"db-dialog-overlay\" onClick={handleBackdropClick}>\n <div className={`db-dialog${sizeClass}`} role=\"dialog\" aria-modal=\"true\" aria-label={title}>\n <div className=\"db-dialog-header\">\n <h2 className=\"db-dialog-title\">{title}</h2>\n <button\n ref={closeButtonRef}\n type=\"button\"\n className=\"db-dialog-close\"\n onClick={onClose}\n aria-label=\"Close\"\n >\n &times;\n </button>\n </div>\n <div className=\"db-dialog-body\">{children}</div>\n {footer && <div className=\"db-dialog-footer\">{footer}</div>}\n </div>\n </div>\n );\n}\n"],"mappings":";AAQA,SAAS,aAAa,WAAW,cAAc;AAuDvC,SACE,KADF;AAvCD,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AACpB,GAAgB;AACd,QAAM,iBAAiB,OAA0B,IAAI;AAErD,YAAU,MAAM;AACd,UAAM,QAAQ,CAAC,MAAqB;AAClC,UAAI,EAAE,QAAQ,SAAU,SAAQ;AAAA,IAClC;AACA,WAAO,iBAAiB,WAAW,KAAK;AACxC,WAAO,MAAM,OAAO,oBAAoB,WAAW,KAAK;AAAA,EAC1D,GAAG,CAAC,OAAO,CAAC;AAEZ,YAAU,MAAM;AACd,UAAM,SAAS,iBAAiB,WAAW,eAAe;AAC1D,YAAQ,MAAM;AAAA,EAGhB,GAAG,CAAC,CAAC;AAEL,QAAM,sBAAsB;AAAA,IAC1B,CAAC,MAAwB;AACvB,UAAI,mBAAmB,EAAE,WAAW,EAAE,cAAe,SAAQ;AAAA,IAC/D;AAAA,IACA,CAAC,iBAAiB,OAAO;AAAA,EAC3B;AAEA,QAAM,YACJ,SAAS,SAAS,qBAAqB,SAAS,SAAS,qBAAqB;AAEhF,SACE,oBAAC,SAAI,WAAU,qBAAoB,SAAS,qBAC1C,+BAAC,SAAI,WAAW,YAAY,SAAS,IAAI,MAAK,UAAS,cAAW,QAAO,cAAY,OACnF;AAAA,yBAAC,SAAI,WAAU,oBACb;AAAA,0BAAC,QAAG,WAAU,mBAAmB,iBAAM;AAAA,MACvC;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT,cAAW;AAAA,UACZ;AAAA;AAAA,MAED;AAAA,OACF;AAAA,IACA,oBAAC,SAAI,WAAU,kBAAkB,UAAS;AAAA,IACzC,UAAU,oBAAC,SAAI,WAAU,oBAAoB,kBAAO;AAAA,KACvD,GACF;AAEJ;","names":[]}