@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
@@ -0,0 +1,1048 @@
1
+ import {
2
+ BADGE_GLYPHS,
3
+ BADGE_LABELS,
4
+ badgeKindFor,
5
+ formatAheadBehind,
6
+ summarizeDirty,
7
+ useGitContext
8
+ } from "./chunk-5A4KEWKT.js";
9
+ import {
10
+ Dialog
11
+ } from "./chunk-GSNZSCIK.js";
12
+
13
+ // src/Git/GitStatusBar.tsx
14
+ import { useCallback, useEffect, useRef, useState } from "react";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
16
+ function GitStatusBar() {
17
+ const git = useGitContext();
18
+ const [menuOpen, setMenuOpen] = useState(false);
19
+ const rootRef = useRef(null);
20
+ useEffect(() => {
21
+ if (!menuOpen) return;
22
+ const onPointerDown = (e) => {
23
+ if (rootRef.current && !rootRef.current.contains(e.target)) {
24
+ setMenuOpen(false);
25
+ }
26
+ };
27
+ document.addEventListener("pointerdown", onPointerDown);
28
+ return () => document.removeEventListener("pointerdown", onPointerDown);
29
+ }, [menuOpen]);
30
+ const runItem = useCallback((action) => {
31
+ setMenuOpen(false);
32
+ action();
33
+ }, []);
34
+ if (!git || !git.repo || !git.status) return null;
35
+ const { status } = git;
36
+ const branchLabel = status.detached ? "detached HEAD" : status.branch ?? "no branch";
37
+ const aheadBehind = formatAheadBehind(status);
38
+ const dirty = summarizeDirty(status);
39
+ const merging = status.operation === "merge";
40
+ const chipLabelParts = [`Git: branch ${branchLabel}`];
41
+ if (status.ahead > 0) chipLabelParts.push(`${status.ahead} ahead`);
42
+ if (status.behind > 0) chipLabelParts.push(`${status.behind} behind`);
43
+ if (dirty) chipLabelParts.push(dirty);
44
+ if (merging) chipLabelParts.push("merge in progress");
45
+ const canCreatePr = git.capabilities?.ghAvailable === true && git.remoteWeb?.host === "github.com";
46
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: "db-git-statusbar", children: [
47
+ /* @__PURE__ */ jsxs(
48
+ "button",
49
+ {
50
+ type: "button",
51
+ className: "db-git-statusbar-chip",
52
+ onClick: () => setMenuOpen((open) => !open),
53
+ "aria-haspopup": "menu",
54
+ "aria-expanded": menuOpen,
55
+ "aria-label": chipLabelParts.join(", "),
56
+ title: chipLabelParts.join(", "),
57
+ children: [
58
+ /* @__PURE__ */ jsx("span", { className: "db-git-branch-glyph", "aria-hidden": "true", children: "\u2387" }),
59
+ /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-branch", children: branchLabel }),
60
+ aheadBehind && /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-counts", children: aheadBehind }),
61
+ dirty && /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-dirty", children: dirty }),
62
+ merging && /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-merge", children: "merging" }),
63
+ git.busy && /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-busy", "aria-hidden": "true", children: "\u2026" })
64
+ ]
65
+ }
66
+ ),
67
+ menuOpen && /* @__PURE__ */ jsxs("div", { className: "db-git-menu", role: "menu", "aria-label": "Git actions", children: [
68
+ /* @__PURE__ */ jsx(
69
+ "button",
70
+ {
71
+ type: "button",
72
+ role: "menuitem",
73
+ className: "db-git-menu-item",
74
+ disabled: status.changes.length === 0 && !merging,
75
+ onClick: () => runItem(() => git.openDialog({ kind: "commit" })),
76
+ children: merging ? "Commit merge\u2026" : "Commit\u2026"
77
+ }
78
+ ),
79
+ /* @__PURE__ */ jsx(
80
+ "button",
81
+ {
82
+ type: "button",
83
+ role: "menuitem",
84
+ className: "db-git-menu-item",
85
+ disabled: git.busy !== null,
86
+ onClick: () => runItem(() => void git.push()),
87
+ children: status.upstream === null && !status.unborn ? "Publish branch" : "Push"
88
+ }
89
+ ),
90
+ /* @__PURE__ */ jsx(
91
+ "button",
92
+ {
93
+ type: "button",
94
+ role: "menuitem",
95
+ className: "db-git-menu-item",
96
+ disabled: git.busy !== null,
97
+ onClick: () => runItem(() => void git.pull()),
98
+ children: "Pull"
99
+ }
100
+ ),
101
+ /* @__PURE__ */ jsx(
102
+ "button",
103
+ {
104
+ type: "button",
105
+ role: "menuitem",
106
+ className: "db-git-menu-item",
107
+ disabled: git.busy !== null,
108
+ onClick: () => runItem(() => void git.fetchRemote()),
109
+ children: "Fetch"
110
+ }
111
+ ),
112
+ /* @__PURE__ */ jsx("div", { className: "db-git-menu-divider", role: "separator" }),
113
+ /* @__PURE__ */ jsx(
114
+ "button",
115
+ {
116
+ type: "button",
117
+ role: "menuitem",
118
+ className: "db-git-menu-item",
119
+ onClick: () => runItem(() => git.openDialog({ kind: "branches" })),
120
+ children: "Branches\u2026"
121
+ }
122
+ ),
123
+ /* @__PURE__ */ jsx(
124
+ "button",
125
+ {
126
+ type: "button",
127
+ role: "menuitem",
128
+ className: "db-git-menu-item",
129
+ onClick: () => runItem(() => git.openDialog({ kind: "history" })),
130
+ children: "Commit history\u2026"
131
+ }
132
+ ),
133
+ (git.remoteWeb || canCreatePr) && /* @__PURE__ */ jsx("div", { className: "db-git-menu-divider", role: "separator" }),
134
+ git.remoteWeb && /* @__PURE__ */ jsxs(
135
+ "button",
136
+ {
137
+ type: "button",
138
+ role: "menuitem",
139
+ className: "db-git-menu-item",
140
+ onClick: () => runItem(() => git.openOnRemote()),
141
+ children: [
142
+ "Open on ",
143
+ git.remoteWeb.host
144
+ ]
145
+ }
146
+ ),
147
+ canCreatePr && /* @__PURE__ */ jsx(
148
+ "button",
149
+ {
150
+ type: "button",
151
+ role: "menuitem",
152
+ className: "db-git-menu-item",
153
+ disabled: git.busy !== null,
154
+ onClick: () => runItem(() => void git.createPullRequest()),
155
+ children: "Create pull request"
156
+ }
157
+ )
158
+ ] })
159
+ ] });
160
+ }
161
+
162
+ // src/Git/GitCommitDialog.tsx
163
+ import { useRef as useRef2, useState as useState2 } from "react";
164
+
165
+ // src/Git/commit-selection.ts
166
+ function normalise(path) {
167
+ return path.startsWith("/") ? path : `/${path}`;
168
+ }
169
+ function initSelection(changes, merging) {
170
+ const included = /* @__PURE__ */ new Map();
171
+ const locked = /* @__PURE__ */ new Set();
172
+ for (const change of changes) {
173
+ const path = normalise(change.path);
174
+ included.set(path, true);
175
+ if (merging && change.conflicted) locked.add(path);
176
+ }
177
+ return { included, locked };
178
+ }
179
+ function toggleSelection(selection, path) {
180
+ const key = normalise(path);
181
+ if (selection.locked.has(key)) return selection;
182
+ const included = new Map(selection.included);
183
+ included.set(key, !included.get(key));
184
+ return { included, locked: selection.locked };
185
+ }
186
+ function setAllSelected(selection, value) {
187
+ const included = /* @__PURE__ */ new Map();
188
+ for (const key of selection.included.keys()) {
189
+ included.set(key, selection.locked.has(key) ? true : value);
190
+ }
191
+ return { included, locked: selection.locked };
192
+ }
193
+ function selectedPaths(selection) {
194
+ return [...selection.included.entries()].filter(([, on]) => on).map(([path]) => path);
195
+ }
196
+ function canCommit(message, selection) {
197
+ return message.trim().length > 0 && selectedPaths(selection).length > 0;
198
+ }
199
+ function isMergeCommit(status) {
200
+ return status?.operation === "merge";
201
+ }
202
+
203
+ // src/Git/GitCommitDialog.tsx
204
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
205
+ function GitCommitDialog({ onClose }) {
206
+ const git = useGitContext();
207
+ const status = git?.status ?? null;
208
+ const merging = isMergeCommit(status);
209
+ const [message, setMessage] = useState2("");
210
+ const [selection, setSelection] = useState2(
211
+ () => initSelection(status?.changes ?? [], merging)
212
+ );
213
+ const messageRef = useRef2(null);
214
+ if (!git || !status) return null;
215
+ const allOn = [...selection.included.values()].every(Boolean);
216
+ const commitDisabled = !canCommit(message, selection) || git.busy !== null;
217
+ const handleCommit = async () => {
218
+ const ok = await git.commit(message, selectedPaths(selection));
219
+ if (ok) onClose();
220
+ };
221
+ return /* @__PURE__ */ jsxs2(
222
+ Dialog,
223
+ {
224
+ title: merging ? "Commit merge" : "Commit changes",
225
+ onClose,
226
+ size: "wide",
227
+ closeOnBackdrop: false,
228
+ initialFocusRef: messageRef,
229
+ footer: /* @__PURE__ */ jsxs2(Fragment, { children: [
230
+ /* @__PURE__ */ jsx2("button", { type: "button", className: "db-git-secondary-btn", onClick: onClose, children: "Cancel" }),
231
+ /* @__PURE__ */ jsx2(
232
+ "button",
233
+ {
234
+ type: "button",
235
+ className: "db-git-primary-btn",
236
+ disabled: commitDisabled,
237
+ onClick: () => void handleCommit(),
238
+ children: "Commit"
239
+ }
240
+ )
241
+ ] }),
242
+ children: [
243
+ merging && /* @__PURE__ */ jsx2("p", { className: "db-settings-hint", children: "You\u2019re completing a merge. Committing will conclude it." }),
244
+ /* @__PURE__ */ jsx2(
245
+ "textarea",
246
+ {
247
+ ref: messageRef,
248
+ className: "db-git-commit-message",
249
+ value: message,
250
+ onChange: (e) => setMessage(e.target.value),
251
+ placeholder: "Commit message",
252
+ "aria-label": "Commit message",
253
+ rows: 3
254
+ }
255
+ ),
256
+ /* @__PURE__ */ jsx2("div", { className: "db-git-form-row", children: /* @__PURE__ */ jsx2(
257
+ "button",
258
+ {
259
+ type: "button",
260
+ className: "db-git-secondary-btn",
261
+ onClick: () => setSelection((s) => setAllSelected(s, !allOn)),
262
+ children: allOn ? "Select none" : "Select all"
263
+ }
264
+ ) }),
265
+ /* @__PURE__ */ jsx2("ul", { className: "db-git-file-list", children: status.changes.map((change) => {
266
+ const kind = badgeKindFor(change);
267
+ const locked = selection.locked.has(change.path);
268
+ const checked = locked || (selection.included.get(change.path) ?? true);
269
+ return /* @__PURE__ */ jsxs2("li", { className: "db-git-file-row", children: [
270
+ /* @__PURE__ */ jsxs2("label", { children: [
271
+ /* @__PURE__ */ jsx2(
272
+ "input",
273
+ {
274
+ type: "checkbox",
275
+ checked,
276
+ disabled: locked,
277
+ onChange: () => setSelection((s) => toggleSelection(s, change.path))
278
+ }
279
+ ),
280
+ /* @__PURE__ */ jsx2("span", { children: change.path.replace(/^\/+/, "") })
281
+ ] }),
282
+ /* @__PURE__ */ jsx2("span", { className: "db-git-file-kind", children: BADGE_LABELS[kind] })
283
+ ] }, change.path);
284
+ }) }),
285
+ git.lastResult?.tone === "error" && /* @__PURE__ */ jsx2("p", { className: "db-git-form-error", role: "alert", children: git.lastResult.message })
286
+ ]
287
+ }
288
+ );
289
+ }
290
+
291
+ // src/Git/GitBranchesDialog.tsx
292
+ import { useEffect as useEffect2, useRef as useRef3, useState as useState3 } from "react";
293
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
294
+ function GitBranchesDialog({
295
+ createFocus,
296
+ onClose
297
+ }) {
298
+ const git = useGitContext();
299
+ const gitApi = git?.gitApi ?? null;
300
+ const repositoryId = git?.repositoryId ?? null;
301
+ const [branches, setBranches] = useState3(null);
302
+ const [loadError, setLoadError] = useState3(null);
303
+ const [newName, setNewName] = useState3("");
304
+ const createInputRef = useRef3(null);
305
+ useEffect2(() => {
306
+ if (!gitApi || !repositoryId) return;
307
+ let cancelled = false;
308
+ void gitApi.listBranches(repositoryId).then((result) => {
309
+ if (cancelled) return;
310
+ if (result.ok) setBranches(result.value);
311
+ else setLoadError(result.error.message || "Could not list branches");
312
+ });
313
+ return () => {
314
+ cancelled = true;
315
+ };
316
+ }, [gitApi, repositoryId]);
317
+ if (!git) return null;
318
+ const locals = branches?.filter((b) => b.kind === "local") ?? [];
319
+ const remotes = branches?.filter((b) => b.kind === "remote") ?? [];
320
+ const canCreate = newName.trim().length > 0 && git.busy === null;
321
+ const handleSwitch = async (name) => {
322
+ const ok = await git.switchBranch(name);
323
+ if (ok) onClose();
324
+ };
325
+ const handleCreate = async () => {
326
+ if (!canCreate) return;
327
+ const ok = await git.createBranch(newName.trim());
328
+ if (ok) onClose();
329
+ };
330
+ return /* @__PURE__ */ jsxs3(
331
+ Dialog,
332
+ {
333
+ title: "Branches",
334
+ onClose,
335
+ initialFocusRef: createFocus ? createInputRef : void 0,
336
+ children: [
337
+ branches === null && loadError === null && /* @__PURE__ */ jsx3("p", { className: "db-git-hint", children: "Loading branches\u2026" }),
338
+ loadError !== null && /* @__PURE__ */ jsx3("p", { className: "db-git-form-error", role: "alert", children: loadError }),
339
+ branches !== null && /* @__PURE__ */ jsx3("div", { className: "db-git-branch-list", children: locals.map(
340
+ (branch) => branch.current ? /* @__PURE__ */ jsx3(
341
+ "span",
342
+ {
343
+ className: "db-git-branch-row db-git-branch-row--current",
344
+ "aria-current": "true",
345
+ children: branch.name
346
+ },
347
+ branch.name
348
+ ) : /* @__PURE__ */ jsx3(
349
+ "button",
350
+ {
351
+ type: "button",
352
+ className: "db-git-branch-row",
353
+ disabled: git.busy !== null,
354
+ onClick: () => void handleSwitch(branch.name),
355
+ children: branch.name
356
+ },
357
+ branch.name
358
+ )
359
+ ) }),
360
+ git.lastResult?.tone === "error" && /* @__PURE__ */ jsx3("p", { className: "db-git-form-error", role: "alert", children: git.lastResult.message }),
361
+ /* @__PURE__ */ jsx3("hr", {}),
362
+ /* @__PURE__ */ jsxs3("div", { className: "db-git-form-row", children: [
363
+ /* @__PURE__ */ jsx3("label", { className: "db-git-form-label", htmlFor: "db-git-new-branch-name", children: "New branch" }),
364
+ /* @__PURE__ */ jsx3(
365
+ "input",
366
+ {
367
+ id: "db-git-new-branch-name",
368
+ ref: createInputRef,
369
+ className: "db-git-form-input",
370
+ type: "text",
371
+ value: newName,
372
+ onChange: (e) => setNewName(e.target.value),
373
+ onKeyDown: (e) => {
374
+ if (e.key === "Enter") void handleCreate();
375
+ },
376
+ placeholder: "feature/my-branch",
377
+ spellCheck: false
378
+ }
379
+ ),
380
+ /* @__PURE__ */ jsx3(
381
+ "button",
382
+ {
383
+ type: "button",
384
+ className: "db-git-primary-btn",
385
+ disabled: !canCreate,
386
+ onClick: () => void handleCreate(),
387
+ children: "Create"
388
+ }
389
+ )
390
+ ] }),
391
+ remotes.length > 0 && /* @__PURE__ */ jsxs3("details", { children: [
392
+ /* @__PURE__ */ jsxs3("summary", { children: [
393
+ "Remote branches (",
394
+ remotes.length,
395
+ ")"
396
+ ] }),
397
+ /* @__PURE__ */ jsx3("div", { className: "db-git-branch-list", children: remotes.map((branch) => /* @__PURE__ */ jsx3("span", { className: "db-git-branch-row", children: branch.name }, branch.name)) })
398
+ ] })
399
+ ]
400
+ }
401
+ );
402
+ }
403
+
404
+ // src/Git/GitHistoryDialog.tsx
405
+ import { useCallback as useCallback2, useEffect as useEffect3, useState as useState4 } from "react";
406
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
407
+ var PAGE_SIZE = 50;
408
+ function extraBody(body, subject) {
409
+ const trimmedBody = body.trim();
410
+ const trimmedSubject = subject.trim();
411
+ if (!trimmedBody || trimmedBody === trimmedSubject) return "";
412
+ if (trimmedBody.startsWith(trimmedSubject)) {
413
+ return trimmedBody.slice(trimmedSubject.length).trim();
414
+ }
415
+ return trimmedBody;
416
+ }
417
+ function formatDate(iso) {
418
+ const date = new Date(iso);
419
+ return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
420
+ }
421
+ function GitHistoryDialog({ path, onClose }) {
422
+ const git = useGitContext();
423
+ const gitApi = git?.gitApi ?? null;
424
+ const repositoryId = git?.repositoryId ?? null;
425
+ const [entries, setEntries] = useState4([]);
426
+ const [loading, setLoading] = useState4(false);
427
+ const [error, setError] = useState4(null);
428
+ const [hasMore, setHasMore] = useState4(false);
429
+ const [expandedSha, setExpandedSha] = useState4(null);
430
+ const [details, setDetails] = useState4(/* @__PURE__ */ new Map());
431
+ const loadPage = useCallback2(
432
+ async (skip) => {
433
+ if (!gitApi || !repositoryId) return;
434
+ setLoading(true);
435
+ setError(null);
436
+ try {
437
+ const result = await gitApi.log(repositoryId, { path, maxCount: PAGE_SIZE, skip });
438
+ if (!result.ok) {
439
+ setError(result.error.message);
440
+ return;
441
+ }
442
+ setEntries((prev) => skip === 0 ? result.value : [...prev, ...result.value]);
443
+ setHasMore(result.value.length === PAGE_SIZE);
444
+ } finally {
445
+ setLoading(false);
446
+ }
447
+ },
448
+ [gitApi, repositoryId, path]
449
+ );
450
+ useEffect3(() => {
451
+ setEntries([]);
452
+ setExpandedSha(null);
453
+ setDetails(/* @__PURE__ */ new Map());
454
+ setHasMore(false);
455
+ void loadPage(0);
456
+ }, [loadPage]);
457
+ const handleRowClick = (sha) => {
458
+ if (expandedSha === sha) {
459
+ setExpandedSha(null);
460
+ return;
461
+ }
462
+ setExpandedSha(sha);
463
+ if (!gitApi || !repositoryId || details.has(sha)) return;
464
+ void gitApi.commitFiles(repositoryId, sha).then((result) => {
465
+ setDetails((prev) => {
466
+ const next = new Map(prev);
467
+ next.set(sha, result.ok ? result.value : { error: result.error.message });
468
+ return next;
469
+ });
470
+ });
471
+ };
472
+ if (!git) return null;
473
+ const baseName = path ? path.replace(/^\/+/, "").split("/").pop() : null;
474
+ const title = baseName ? `History \u2014 ${baseName}` : "Commit history";
475
+ return /* @__PURE__ */ jsxs4(Dialog, { title, size: "wide", onClose, children: [
476
+ error && /* @__PURE__ */ jsx4("p", { className: "db-git-form-error", role: "alert", children: error }),
477
+ !error && entries.length === 0 && loading && /* @__PURE__ */ jsx4("p", { className: "db-git-hint", children: "Loading history\u2026" }),
478
+ !error && entries.length === 0 && !loading && /* @__PURE__ */ jsx4("p", { className: "db-git-hint", children: "No commits yet." }),
479
+ entries.length > 0 && /* @__PURE__ */ jsx4("ul", { className: "db-git-history-list", children: entries.map((entry) => {
480
+ const expanded = expandedSha === entry.sha;
481
+ const detail = details.get(entry.sha);
482
+ const meta = [
483
+ entry.authorName,
484
+ entry.sha.slice(0, 7),
485
+ formatDate(entry.authorDate),
486
+ entry.refs.join(", ")
487
+ ].filter(Boolean).join(" \xB7 ");
488
+ const body = detail && !("error" in detail) ? extraBody(detail.body, entry.subject) : "";
489
+ return /* @__PURE__ */ jsxs4("li", { className: "db-git-history-item", children: [
490
+ /* @__PURE__ */ jsxs4(
491
+ "button",
492
+ {
493
+ type: "button",
494
+ className: "db-git-history-toggle",
495
+ "aria-expanded": expanded,
496
+ onClick: () => handleRowClick(entry.sha),
497
+ children: [
498
+ /* @__PURE__ */ jsx4("span", { className: "db-git-history-subject", children: entry.subject }),
499
+ /* @__PURE__ */ jsx4("span", { className: "db-git-history-meta", children: meta })
500
+ ]
501
+ }
502
+ ),
503
+ expanded && !detail && /* @__PURE__ */ jsx4("p", { className: "db-git-hint", children: "Loading\u2026" }),
504
+ expanded && detail && "error" in detail && /* @__PURE__ */ jsx4("p", { className: "db-git-form-error", role: "alert", children: detail.error }),
505
+ expanded && detail && !("error" in detail) && /* @__PURE__ */ jsxs4(Fragment2, { children: [
506
+ body && /* @__PURE__ */ jsx4("pre", { className: "db-git-history-body", children: body }),
507
+ /* @__PURE__ */ jsx4("ul", { className: "db-git-history-files", children: detail.files.map((file) => {
508
+ const kind = badgeKindFor(file);
509
+ return /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsxs4(
510
+ "button",
511
+ {
512
+ type: "button",
513
+ className: "db-git-history-file",
514
+ onClick: () => git.openDialog({
515
+ kind: "diff",
516
+ path: file.path,
517
+ revision: { sha: entry.sha }
518
+ }),
519
+ children: [
520
+ /* @__PURE__ */ jsx4(
521
+ "span",
522
+ {
523
+ className: "db-git-file-kind",
524
+ "aria-label": BADGE_LABELS[kind],
525
+ title: BADGE_LABELS[kind],
526
+ children: BADGE_GLYPHS[kind]
527
+ }
528
+ ),
529
+ file.path.replace(/^\/+/, "")
530
+ ]
531
+ }
532
+ ) }, file.path);
533
+ }) })
534
+ ] })
535
+ ] }, entry.sha);
536
+ }) }),
537
+ hasMore && /* @__PURE__ */ jsx4(
538
+ "button",
539
+ {
540
+ type: "button",
541
+ className: "db-git-secondary-btn",
542
+ disabled: loading,
543
+ onClick: () => void loadPage(entries.length),
544
+ children: "Show older commits"
545
+ }
546
+ )
547
+ ] });
548
+ }
549
+
550
+ // src/Git/GitDiffDialog.tsx
551
+ import { useEffect as useEffect5, useState as useState5 } from "react";
552
+ import { getFileSystemProviderV2, parseWorkspacePath } from "@bendyline/docblocks/filesystem";
553
+
554
+ // src/Git/GitDiffView.tsx
555
+ import { useEffect as useEffect4, useRef as useRef4 } from "react";
556
+ import {
557
+ detectLanguageFromFileName,
558
+ useMonacoLoader
559
+ } from "@bendyline/squisq-editor-react";
560
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
561
+ function languageFor(fileName) {
562
+ const detected = detectLanguageFromFileName(fileName);
563
+ if (detected) return detected;
564
+ return fileName.toLowerCase().endsWith(".md") ? "markdown" : "plaintext";
565
+ }
566
+ function GitDiffView({ original, modified, fileName, theme, labels }) {
567
+ const { monaco, ready } = useMonacoLoader();
568
+ const hostRef = useRef4(null);
569
+ const editorRef = useRef4(null);
570
+ const modelsRef = useRef4(null);
571
+ const language = languageFor(fileName);
572
+ useEffect4(() => {
573
+ const host = hostRef.current;
574
+ if (!monaco || !host) return;
575
+ const originalModel = monaco.editor.createModel("", "plaintext");
576
+ const modifiedModel = monaco.editor.createModel("", "plaintext");
577
+ const editor = monaco.editor.createDiffEditor(host, {
578
+ readOnly: true,
579
+ renderSideBySide: true,
580
+ automaticLayout: true,
581
+ minimap: { enabled: false },
582
+ wordWrap: "on",
583
+ scrollBeyondLastLine: false,
584
+ renderOverviewRuler: false
585
+ });
586
+ editor.setModel({ original: originalModel, modified: modifiedModel });
587
+ editorRef.current = editor;
588
+ modelsRef.current = { original: originalModel, modified: modifiedModel };
589
+ return () => {
590
+ editorRef.current = null;
591
+ modelsRef.current = null;
592
+ editor.dispose();
593
+ originalModel.dispose();
594
+ modifiedModel.dispose();
595
+ };
596
+ }, [monaco]);
597
+ useEffect4(() => {
598
+ if (!monaco) return;
599
+ const models = modelsRef.current;
600
+ if (!models) return;
601
+ if (models.original.getValue() !== original) models.original.setValue(original);
602
+ if (models.modified.getValue() !== modified) models.modified.setValue(modified);
603
+ monaco.editor.setModelLanguage(models.original, language);
604
+ monaco.editor.setModelLanguage(models.modified, language);
605
+ }, [monaco, original, modified, language]);
606
+ useEffect4(() => {
607
+ if (!monaco) return;
608
+ monaco.editor.setTheme(theme === "dark" ? "vs-dark" : "vs");
609
+ }, [monaco, theme]);
610
+ if (!ready) {
611
+ return /* @__PURE__ */ jsx5("div", { className: "db-git-diff-loading", children: "Loading diff\u2026" });
612
+ }
613
+ return /* @__PURE__ */ jsxs5(Fragment3, { children: [
614
+ labels && /* @__PURE__ */ jsxs5("div", { className: "db-git-diff-labels", children: [
615
+ /* @__PURE__ */ jsx5("span", { children: labels.original }),
616
+ /* @__PURE__ */ jsx5("span", { children: labels.modified })
617
+ ] }),
618
+ /* @__PURE__ */ jsx5("div", { ref: hostRef, className: "db-git-diff-host" })
619
+ ] });
620
+ }
621
+
622
+ // src/Git/GitDiffDialog.tsx
623
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
624
+ function GitDiffDialog({ path, revision, onClose }) {
625
+ const git = useGitContext();
626
+ const gitApi = git?.gitApi ?? null;
627
+ const provider = git?.provider ?? null;
628
+ const repositoryId = git?.repositoryId ?? null;
629
+ const sha = revision?.sha ?? null;
630
+ const [state, setState] = useState5({ phase: "loading" });
631
+ useEffect5(() => {
632
+ if (!gitApi || !repositoryId) {
633
+ setState({ phase: "error", message: "Git is not available for this workspace." });
634
+ return;
635
+ }
636
+ let cancelled = false;
637
+ setState({ phase: "loading" });
638
+ const load = async () => {
639
+ if (sha) {
640
+ const short = sha.slice(0, 7);
641
+ const [parent, at] = await Promise.all([
642
+ gitApi.readFileAtRevision(repositoryId, path, { kind: "parent-of", sha }),
643
+ gitApi.readFileAtRevision(repositoryId, path, { kind: "commit", sha })
644
+ ]);
645
+ if (!parent.ok) return { phase: "error", message: parent.error.message };
646
+ if (!at.ok) return { phase: "error", message: at.error.message };
647
+ if (parent.value.content === null && parent.value.binary || at.value.content === null && at.value.binary) {
648
+ return { phase: "binary" };
649
+ }
650
+ return {
651
+ phase: "ready",
652
+ original: parent.value.content ?? "",
653
+ modified: at.value.content ?? "",
654
+ labels: {
655
+ original: parent.value.content === null ? `${short}^ (absent)` : `${short}^`,
656
+ modified: at.value.content === null ? `${short} (absent)` : short
657
+ }
658
+ };
659
+ }
660
+ if (!provider) {
661
+ return { phase: "error", message: "Workspace files are not available." };
662
+ }
663
+ const providerV2 = getFileSystemProviderV2(provider);
664
+ const [head, working] = await Promise.all([
665
+ gitApi.readFileAtRevision(repositoryId, path, { kind: "head" }),
666
+ providerV2 ? providerV2.readFile(parseWorkspacePath(path)).then((file) => file ? new TextDecoder().decode(file.data) : null) : provider.readFile(path)
667
+ ]);
668
+ if (!head.ok) return { phase: "error", message: head.error.message };
669
+ if (head.value.content === null && head.value.binary) return { phase: "binary" };
670
+ return {
671
+ phase: "ready",
672
+ original: head.value.content ?? "",
673
+ modified: working ?? "",
674
+ labels: {
675
+ original: head.value.content === null ? "HEAD (absent)" : "HEAD",
676
+ modified: working === null ? "Working tree (absent)" : "Working tree"
677
+ }
678
+ };
679
+ };
680
+ load().catch(
681
+ (err) => ({
682
+ phase: "error",
683
+ message: err instanceof Error ? err.message : "Failed to load the diff"
684
+ })
685
+ ).then((next) => {
686
+ if (!cancelled) setState(next);
687
+ });
688
+ return () => {
689
+ cancelled = true;
690
+ };
691
+ }, [gitApi, provider, repositoryId, path, sha]);
692
+ if (!git) return null;
693
+ const fullPath = path.replace(/^\/+/, "");
694
+ const baseName = fullPath.split("/").pop() || fullPath;
695
+ return /* @__PURE__ */ jsxs6(Dialog, { title: baseName, size: "full", onClose, children: [
696
+ /* @__PURE__ */ jsx6("p", { className: "db-settings-hint", children: fullPath }),
697
+ state.phase === "loading" && /* @__PURE__ */ jsx6("p", { className: "db-git-hint", children: "Loading changes\u2026" }),
698
+ state.phase === "error" && /* @__PURE__ */ jsx6("p", { className: "db-git-form-error", role: "alert", children: state.message }),
699
+ state.phase === "binary" && /* @__PURE__ */ jsx6("p", { className: "db-git-hint", children: "Binary file \u2014 no text diff available." }),
700
+ state.phase === "ready" && /* @__PURE__ */ jsx6(
701
+ GitDiffView,
702
+ {
703
+ original: state.original,
704
+ modified: state.modified,
705
+ fileName: baseName,
706
+ theme: git.theme,
707
+ labels: state.labels
708
+ }
709
+ )
710
+ ] });
711
+ }
712
+
713
+ // src/Git/GitCloneDialog.tsx
714
+ import { useEffect as useEffect6, useRef as useRef5, useState as useState6 } from "react";
715
+
716
+ // src/Git/git-clone-utils.ts
717
+ function deriveCloneFolderName(url) {
718
+ const trimmed = url.trim().replace(/\/+$/, "");
719
+ const lastSegment = trimmed.split(/[/:\\]/).pop() ?? "";
720
+ const withoutGit = lastSegment.replace(/\.git$/i, "");
721
+ const sanitized = withoutGit.replace(/[^A-Za-z0-9._-]/g, "-");
722
+ return sanitized.length > 0 ? sanitized : "repository";
723
+ }
724
+ function isLikelyGitUrl(url) {
725
+ const trimmed = url.trim();
726
+ if (trimmed.length === 0 || /\s/.test(trimmed)) return false;
727
+ if (trimmed.startsWith("-") || trimmed.toLowerCase().startsWith("file:")) return false;
728
+ if (/^(https?|ssh|git):\/\/\S+\/\S+/i.test(trimmed)) return true;
729
+ if (/^[\w.-]+@[\w.-]+:\S+/.test(trimmed)) return true;
730
+ return false;
731
+ }
732
+
733
+ // src/Git/GitAuthGuidanceDialog.tsx
734
+ import { maybeGetDocBlocksHost } from "@bendyline/docblocks/host";
735
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
736
+ var LEARN_MORE_URL = "https://docs.github.com/en/get-started/getting-started-with-git/caching-your-github-credentials-in-git";
737
+ var OPERATION_LABELS = {
738
+ push: "push",
739
+ pull: "pull",
740
+ fetch: "fetch",
741
+ clone: "clone",
742
+ pr: "create the pull request"
743
+ };
744
+ function GitCredentialGuidance({ detail }) {
745
+ return /* @__PURE__ */ jsxs7(Fragment4, { children: [
746
+ /* @__PURE__ */ jsx7("p", { className: "db-settings-hint", children: "DocBlocks never stores Git credentials. Sign in with one of these, then try again:" }),
747
+ /* @__PURE__ */ jsxs7("ul", { className: "db-git-hint", children: [
748
+ /* @__PURE__ */ jsxs7("li", { children: [
749
+ "A git credential helper (",
750
+ /* @__PURE__ */ jsx7("code", { children: "git config credential.helper" }),
751
+ ")"
752
+ ] }),
753
+ /* @__PURE__ */ jsxs7("li", { children: [
754
+ "The GitHub CLI (",
755
+ /* @__PURE__ */ jsx7("code", { children: "gh auth login" }),
756
+ ")"
757
+ ] }),
758
+ /* @__PURE__ */ jsx7("li", { children: "An SSH key registered with your remote" })
759
+ ] }),
760
+ detail && /* @__PURE__ */ jsxs7("details", { children: [
761
+ /* @__PURE__ */ jsx7("summary", { children: "Details" }),
762
+ /* @__PURE__ */ jsx7("p", { className: "db-git-hint", children: detail })
763
+ ] })
764
+ ] });
765
+ }
766
+ function GitAuthGuidanceDialog({
767
+ operation,
768
+ detail,
769
+ onClose
770
+ }) {
771
+ return /* @__PURE__ */ jsxs7(
772
+ Dialog,
773
+ {
774
+ title: "Git needs credentials",
775
+ onClose,
776
+ footer: /* @__PURE__ */ jsxs7(Fragment4, { children: [
777
+ /* @__PURE__ */ jsx7(
778
+ "button",
779
+ {
780
+ type: "button",
781
+ className: "db-git-secondary-btn",
782
+ onClick: () => void maybeGetDocBlocksHost()?.shell.openExternal(LEARN_MORE_URL),
783
+ children: "Learn more"
784
+ }
785
+ ),
786
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "db-git-primary-btn", onClick: onClose, children: "Close" })
787
+ ] }),
788
+ children: [
789
+ /* @__PURE__ */ jsxs7("p", { className: "db-settings-hint", children: [
790
+ "Git could not authenticate with the remote while trying to ",
791
+ OPERATION_LABELS[operation],
792
+ "."
793
+ ] }),
794
+ /* @__PURE__ */ jsx7(GitCredentialGuidance, { detail })
795
+ ]
796
+ }
797
+ );
798
+ }
799
+
800
+ // src/Git/GitCloneDialog.tsx
801
+ import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
802
+ function GitCloneDialog({
803
+ onClose,
804
+ onCloned
805
+ }) {
806
+ const git = useGitContext();
807
+ const gitApi = git?.gitApi ?? null;
808
+ const [url, setUrl] = useState6("");
809
+ const [cloning, setCloning] = useState6(false);
810
+ const [progress, setProgress] = useState6(null);
811
+ const [error, setError] = useState6(null);
812
+ const [authDetail, setAuthDetail] = useState6(null);
813
+ const handleRef = useRef5(null);
814
+ const urlInputRef = useRef5(null);
815
+ useEffect6(
816
+ () => () => {
817
+ handleRef.current?.cancel();
818
+ },
819
+ []
820
+ );
821
+ if (!gitApi || typeof gitApi.clone !== "function") return null;
822
+ const canClone = isLikelyGitUrl(url) && !cloning;
823
+ const handleClone = async () => {
824
+ if (!canClone) return;
825
+ setCloning(true);
826
+ setError(null);
827
+ setProgress(null);
828
+ const handle = gitApi.clone(url.trim(), (p) => setProgress(p));
829
+ handleRef.current = handle;
830
+ const result = await handle.result;
831
+ handleRef.current = null;
832
+ setCloning(false);
833
+ setProgress(null);
834
+ if (!result.ok) {
835
+ switch (result.error.code) {
836
+ case "invalid-url":
837
+ setError("That doesn\u2019t look like a valid repository URL.");
838
+ break;
839
+ case "destination-exists":
840
+ setError("A folder with that name already exists there. Pick a different location.");
841
+ break;
842
+ case "auth-failed":
843
+ setAuthDetail({ detail: result.error.message });
844
+ break;
845
+ case "cancelled":
846
+ break;
847
+ // user cancelled — just return to the form
848
+ default:
849
+ setError(result.error.message);
850
+ }
851
+ return;
852
+ }
853
+ if (result.value === null) return;
854
+ onCloned(result.value);
855
+ };
856
+ const progressPercent = progress?.percent ?? null;
857
+ const progressText = progress !== null ? `${progress.phase}\u2026${progressPercent !== null ? ` ${Math.round(progressPercent)}%` : ""}` : "Starting clone\u2026";
858
+ if (authDetail !== null) {
859
+ return /* @__PURE__ */ jsxs8(
860
+ Dialog,
861
+ {
862
+ title: "Clone repository",
863
+ onClose,
864
+ footer: /* @__PURE__ */ jsxs8(Fragment5, { children: [
865
+ /* @__PURE__ */ jsx8(
866
+ "button",
867
+ {
868
+ type: "button",
869
+ className: "db-git-secondary-btn",
870
+ onClick: () => setAuthDetail(null),
871
+ children: "Back"
872
+ }
873
+ ),
874
+ /* @__PURE__ */ jsx8("button", { type: "button", className: "db-git-primary-btn", onClick: onClose, children: "Close" })
875
+ ] }),
876
+ children: [
877
+ /* @__PURE__ */ jsx8("p", { className: "db-settings-hint", children: "Git could not authenticate with that remote." }),
878
+ /* @__PURE__ */ jsx8(GitCredentialGuidance, { detail: authDetail.detail })
879
+ ]
880
+ }
881
+ );
882
+ }
883
+ return /* @__PURE__ */ jsxs8(
884
+ Dialog,
885
+ {
886
+ title: "Clone repository",
887
+ onClose,
888
+ closeOnBackdrop: !cloning,
889
+ initialFocusRef: urlInputRef,
890
+ footer: /* @__PURE__ */ jsxs8(Fragment5, { children: [
891
+ /* @__PURE__ */ jsx8(
892
+ "button",
893
+ {
894
+ type: "button",
895
+ className: "db-git-secondary-btn",
896
+ onClick: onClose,
897
+ disabled: cloning,
898
+ children: "Cancel"
899
+ }
900
+ ),
901
+ /* @__PURE__ */ jsx8(
902
+ "button",
903
+ {
904
+ type: "button",
905
+ className: "db-git-primary-btn",
906
+ disabled: !canClone,
907
+ onClick: () => void handleClone(),
908
+ children: "Clone"
909
+ }
910
+ )
911
+ ] }),
912
+ children: [
913
+ /* @__PURE__ */ jsxs8("div", { className: "db-git-form-row", children: [
914
+ /* @__PURE__ */ jsx8("label", { className: "db-git-form-label", htmlFor: "db-git-clone-url", children: "Repository URL" }),
915
+ /* @__PURE__ */ jsx8(
916
+ "input",
917
+ {
918
+ id: "db-git-clone-url",
919
+ ref: urlInputRef,
920
+ className: "db-git-form-input",
921
+ type: "text",
922
+ value: url,
923
+ onChange: (e) => setUrl(e.target.value),
924
+ onKeyDown: (e) => {
925
+ if (e.key === "Enter") void handleClone();
926
+ },
927
+ placeholder: "https://github.com/owner/repo.git",
928
+ disabled: cloning,
929
+ spellCheck: false
930
+ }
931
+ )
932
+ ] }),
933
+ isLikelyGitUrl(url) && /* @__PURE__ */ jsxs8("p", { className: "db-git-hint", children: [
934
+ "Will clone into: ",
935
+ /* @__PURE__ */ jsx8("b", { children: deriveCloneFolderName(url) }),
936
+ " \u2014 you\u2019ll pick where next"
937
+ ] }),
938
+ /* @__PURE__ */ jsx8("p", { className: "db-git-hint", children: "HTTPS and SSH URLs both work. You\u2019ll choose the destination folder in the next step." }),
939
+ error !== null && /* @__PURE__ */ jsx8("p", { className: "db-git-form-error", role: "alert", children: error }),
940
+ cloning && /* @__PURE__ */ jsxs8("div", { className: "db-git-progress", children: [
941
+ progressPercent !== null && /* @__PURE__ */ jsx8(
942
+ "div",
943
+ {
944
+ className: "db-git-progress-bar",
945
+ role: "progressbar",
946
+ "aria-valuemin": 0,
947
+ "aria-valuemax": 100,
948
+ "aria-valuenow": Math.round(progressPercent),
949
+ style: { width: `${progressPercent}%` }
950
+ }
951
+ ),
952
+ /* @__PURE__ */ jsx8("p", { className: "db-git-progress-text", children: progressText }),
953
+ /* @__PURE__ */ jsx8(
954
+ "button",
955
+ {
956
+ type: "button",
957
+ className: "db-git-secondary-btn",
958
+ onClick: () => handleRef.current?.cancel(),
959
+ children: "Cancel"
960
+ }
961
+ )
962
+ ] })
963
+ ]
964
+ }
965
+ );
966
+ }
967
+
968
+ // src/Git/GitConflictsDialog.tsx
969
+ import { Fragment as Fragment6, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
970
+ function GitConflictsDialog({
971
+ paths,
972
+ onOpenFile,
973
+ onClose
974
+ }) {
975
+ const git = useGitContext();
976
+ return /* @__PURE__ */ jsxs9(
977
+ Dialog,
978
+ {
979
+ title: "Merge conflicts",
980
+ onClose,
981
+ footer: /* @__PURE__ */ jsxs9(Fragment6, { children: [
982
+ /* @__PURE__ */ jsx9("button", { type: "button", className: "db-git-secondary-btn", onClick: onClose, children: "Close" }),
983
+ /* @__PURE__ */ jsx9(
984
+ "button",
985
+ {
986
+ type: "button",
987
+ className: "db-git-primary-btn",
988
+ onClick: () => git?.openDialog({ kind: "commit" }),
989
+ children: "Open commit dialog"
990
+ }
991
+ )
992
+ ] }),
993
+ children: [
994
+ /* @__PURE__ */ jsx9("p", { className: "db-settings-hint", children: "These files contain conflict markers. Edit each one to resolve the conflicts, then commit to complete the merge." }),
995
+ /* @__PURE__ */ jsx9("ul", { className: "db-git-file-list", children: paths.map((path) => /* @__PURE__ */ jsx9("li", { className: "db-git-file-row", children: /* @__PURE__ */ jsx9(
996
+ "button",
997
+ {
998
+ type: "button",
999
+ onClick: () => {
1000
+ onOpenFile(path);
1001
+ onClose();
1002
+ },
1003
+ children: path.replace(/^\/+/, "")
1004
+ }
1005
+ ) }, path)) })
1006
+ ]
1007
+ }
1008
+ );
1009
+ }
1010
+
1011
+ // src/Git/GitUI.tsx
1012
+ import { Fragment as Fragment7, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1013
+ function GitUI({ onOpenFile, onWorkspaceCloned }) {
1014
+ const git = useGitContext();
1015
+ if (!git || !git.available) return null;
1016
+ const { dialog, closeDialog } = git;
1017
+ return /* @__PURE__ */ jsxs10(Fragment7, { children: [
1018
+ /* @__PURE__ */ jsx10(GitStatusBar, {}),
1019
+ git.repo && /* @__PURE__ */ jsx10("span", { className: "db-git-inline-status", role: "status", "aria-live": "polite", children: git.lastResult?.message ?? "" }),
1020
+ dialog.kind === "commit" && /* @__PURE__ */ jsx10(GitCommitDialog, { onClose: closeDialog }),
1021
+ dialog.kind === "branches" && /* @__PURE__ */ jsx10(GitBranchesDialog, { createFocus: dialog.createFocus, onClose: closeDialog }),
1022
+ dialog.kind === "history" && /* @__PURE__ */ jsx10(GitHistoryDialog, { path: dialog.path, onClose: closeDialog }),
1023
+ dialog.kind === "diff" && /* @__PURE__ */ jsx10(GitDiffDialog, { path: dialog.path, revision: dialog.revision, onClose: closeDialog }),
1024
+ dialog.kind === "clone" && /* @__PURE__ */ jsx10(
1025
+ GitCloneDialog,
1026
+ {
1027
+ onClose: closeDialog,
1028
+ onCloned: (info) => {
1029
+ closeDialog();
1030
+ onWorkspaceCloned?.(info);
1031
+ }
1032
+ }
1033
+ ),
1034
+ dialog.kind === "auth-guidance" && /* @__PURE__ */ jsx10(
1035
+ GitAuthGuidanceDialog,
1036
+ {
1037
+ operation: dialog.operation,
1038
+ detail: dialog.detail,
1039
+ onClose: closeDialog
1040
+ }
1041
+ ),
1042
+ dialog.kind === "conflicts" && /* @__PURE__ */ jsx10(GitConflictsDialog, { paths: dialog.paths, onOpenFile, onClose: closeDialog })
1043
+ ] });
1044
+ }
1045
+ export {
1046
+ GitUI
1047
+ };
1048
+ //# sourceMappingURL=GitUI-KGF5MSNV.js.map