@rightkit/document-workspace 0.0.0-stage → 0.1.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 (262) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE-APACHE +201 -0
  3. package/LICENSE-MIT +21 -0
  4. package/README.md +51 -2
  5. package/dist/app/App.d.ts +1 -0
  6. package/dist/app/App.js +6 -0
  7. package/dist/app/AppDialogs.d.ts +52 -0
  8. package/dist/app/AppDialogs.js +23 -0
  9. package/dist/app/AppDialogsHost.d.ts +31 -0
  10. package/dist/app/AppDialogsHost.js +30 -0
  11. package/dist/app/AppLifecycle.d.ts +19 -0
  12. package/dist/app/AppLifecycle.js +87 -0
  13. package/dist/app/AppProvider.d.ts +317 -0
  14. package/dist/app/AppProvider.js +217 -0
  15. package/dist/app/AppRoot.d.ts +8 -0
  16. package/dist/app/AppRoot.js +159 -0
  17. package/dist/app/AppShell.d.ts +2 -0
  18. package/dist/app/AppShell.js +81 -0
  19. package/dist/app/CommandPalette.d.ts +13 -0
  20. package/dist/app/CommandPalette.js +47 -0
  21. package/dist/app/DocActionBar.d.ts +36 -0
  22. package/dist/app/DocActionBar.js +300 -0
  23. package/dist/app/DocumentContextMenu.d.ts +29 -0
  24. package/dist/app/DocumentContextMenu.js +122 -0
  25. package/dist/app/DocumentPane.d.ts +52 -0
  26. package/dist/app/DocumentPane.js +30 -0
  27. package/dist/app/DocumentRouterTable.d.ts +58 -0
  28. package/dist/app/DocumentRouterTable.js +143 -0
  29. package/dist/app/ErrorBoundary.d.ts +12 -0
  30. package/dist/app/ErrorBoundary.js +16 -0
  31. package/dist/app/FindBar.d.ts +12 -0
  32. package/dist/app/FindBar.js +199 -0
  33. package/dist/app/LiveTitle.d.ts +14 -0
  34. package/dist/app/LiveTitle.js +14 -0
  35. package/dist/app/OpeningProgress.d.ts +13 -0
  36. package/dist/app/OpeningProgress.js +21 -0
  37. package/dist/app/PrintPreviewWindow.d.ts +2 -0
  38. package/dist/app/PrintPreviewWindow.js +57 -0
  39. package/dist/app/ShortcutHelp.d.ts +3 -0
  40. package/dist/app/ShortcutHelp.js +99 -0
  41. package/dist/app/Sidebar.d.ts +36 -0
  42. package/dist/app/Sidebar.js +121 -0
  43. package/dist/app/ToastViewport.d.ts +1 -0
  44. package/dist/app/ToastViewport.js +31 -0
  45. package/dist/app/Toolbar.d.ts +26 -0
  46. package/dist/app/Toolbar.js +63 -0
  47. package/dist/app/activeFormatSavers.d.ts +7 -0
  48. package/dist/app/activeFormatSavers.js +4 -0
  49. package/dist/app/clipboardPaths.d.ts +1 -0
  50. package/dist/app/clipboardPaths.js +31 -0
  51. package/dist/app/documentDrafts.d.ts +17 -0
  52. package/dist/app/documentDrafts.js +104 -0
  53. package/dist/app/draftResolution.d.ts +5 -0
  54. package/dist/app/draftResolution.js +25 -0
  55. package/dist/app/markdownPaletteActions.d.ts +8 -0
  56. package/dist/app/markdownPaletteActions.js +107 -0
  57. package/dist/app/resourceCensusDev.d.ts +41 -0
  58. package/dist/app/resourceCensusDev.js +518 -0
  59. package/dist/app/setupRecovery.d.ts +34 -0
  60. package/dist/app/setupRecovery.js +70 -0
  61. package/dist/app/shell/DocStatsPill.d.ts +18 -0
  62. package/dist/app/shell/DocStatsPill.js +32 -0
  63. package/dist/app/shell/DocumentTools.d.ts +9 -0
  64. package/dist/app/shell/DocumentTools.js +73 -0
  65. package/dist/app/shell/InfoInspector.d.ts +9 -0
  66. package/dist/app/shell/InfoInspector.js +67 -0
  67. package/dist/app/shell/StartPage.d.ts +9 -0
  68. package/dist/app/shell/StartPage.js +49 -0
  69. package/dist/app/shell/readEdit.d.ts +6 -0
  70. package/dist/app/shell/readEdit.js +6 -0
  71. package/dist/app/sidebar/SidebarDocumentMenu.d.ts +20 -0
  72. package/dist/app/sidebar/SidebarDocumentMenu.js +56 -0
  73. package/dist/app/sidebar/SidebarExpandedPanel.d.ts +9 -0
  74. package/dist/app/sidebar/SidebarExpandedPanel.js +78 -0
  75. package/dist/app/sidebar/SidebarIcons.d.ts +3 -0
  76. package/dist/app/sidebar/SidebarIcons.js +18 -0
  77. package/dist/app/sidebar/SidebarMenus.d.ts +19 -0
  78. package/dist/app/sidebar/SidebarMenus.js +64 -0
  79. package/dist/app/sidebar/SidebarPathUtils.d.ts +10 -0
  80. package/dist/app/sidebar/SidebarPathUtils.js +55 -0
  81. package/dist/app/sidebar/SidebarPrimitives.d.ts +12 -0
  82. package/dist/app/sidebar/SidebarPrimitives.js +45 -0
  83. package/dist/app/sidebar/SidebarRail.d.ts +5 -0
  84. package/dist/app/sidebar/SidebarRail.js +37 -0
  85. package/dist/app/sidebar/explorer/ExplorerRowMenu.d.ts +21 -0
  86. package/dist/app/sidebar/explorer/ExplorerRowMenu.js +37 -0
  87. package/dist/app/sidebar/explorer/ExplorerSections.d.ts +16 -0
  88. package/dist/app/sidebar/explorer/ExplorerSections.js +259 -0
  89. package/dist/app/sidebar/explorer/ExplorerTree.d.ts +46 -0
  90. package/dist/app/sidebar/explorer/ExplorerTree.js +387 -0
  91. package/dist/app/sidebar/explorer/explorerState.d.ts +37 -0
  92. package/dist/app/sidebar/explorer/explorerState.js +135 -0
  93. package/dist/app/tabMountPolicy.d.ts +45 -0
  94. package/dist/app/tabMountPolicy.js +104 -0
  95. package/dist/app/tabWarmOrder.d.ts +7 -0
  96. package/dist/app/tabWarmOrder.js +48 -0
  97. package/dist/app/tabs/TabFuseCurves.d.ts +3 -0
  98. package/dist/app/tabs/TabFuseCurves.js +15 -0
  99. package/dist/app/tabs/TabOverview.d.ts +24 -0
  100. package/dist/app/tabs/TabOverview.js +121 -0
  101. package/dist/app/tabs/TabStrip.d.ts +42 -0
  102. package/dist/app/tabs/TabStrip.js +380 -0
  103. package/dist/app/tabs/tabIds.d.ts +5 -0
  104. package/dist/app/tabs/tabIds.js +7 -0
  105. package/dist/app/tabs/useTabDirty.d.ts +3 -0
  106. package/dist/app/tabs/useTabDirty.js +11 -0
  107. package/dist/app/useAppChromeState.d.ts +21 -0
  108. package/dist/app/useAppChromeState.js +48 -0
  109. package/dist/app/useAppCommands.d.ts +66 -0
  110. package/dist/app/useAppCommands.js +71 -0
  111. package/dist/app/useAppDocumentCore.d.ts +210 -0
  112. package/dist/app/useAppDocumentCore.js +40 -0
  113. package/dist/app/useAppEffects.d.ts +18 -0
  114. package/dist/app/useAppEffects.js +52 -0
  115. package/dist/app/useAppPaneSearch.d.ts +37 -0
  116. package/dist/app/useAppPaneSearch.js +74 -0
  117. package/dist/app/useAppShellSetup.d.ts +40 -0
  118. package/dist/app/useAppShellSetup.js +52 -0
  119. package/dist/app/useAppSlots.d.ts +28 -0
  120. package/dist/app/useAppSlots.js +40 -0
  121. package/dist/app/useAppTabChrome.d.ts +51 -0
  122. package/dist/app/useAppTabChrome.js +66 -0
  123. package/dist/app/useAutoSave.d.ts +34 -0
  124. package/dist/app/useAutoSave.js +116 -0
  125. package/dist/app/useCloseAll.d.ts +52 -0
  126. package/dist/app/useCloseAll.js +295 -0
  127. package/dist/app/useClosedTabEviction.d.ts +10 -0
  128. package/dist/app/useClosedTabEviction.js +38 -0
  129. package/dist/app/useCommandPalette.d.ts +44 -0
  130. package/dist/app/useCommandPalette.js +254 -0
  131. package/dist/app/useCrossDocSearch.d.ts +7 -0
  132. package/dist/app/useCrossDocSearch.js +94 -0
  133. package/dist/app/useDistractionFree.d.ts +21 -0
  134. package/dist/app/useDistractionFree.js +73 -0
  135. package/dist/app/useDocumentCreation.d.ts +18 -0
  136. package/dist/app/useDocumentCreation.js +63 -0
  137. package/dist/app/useDocumentDirty.d.ts +31 -0
  138. package/dist/app/useDocumentDirty.js +46 -0
  139. package/dist/app/useDocumentLoader.d.ts +55 -0
  140. package/dist/app/useDocumentLoader.js +267 -0
  141. package/dist/app/useDocumentOutputActions.d.ts +6 -0
  142. package/dist/app/useDocumentOutputActions.js +45 -0
  143. package/dist/app/useDocumentRuntimeEffects.d.ts +36 -0
  144. package/dist/app/useDocumentRuntimeEffects.js +458 -0
  145. package/dist/app/useDocumentSaver.d.ts +58 -0
  146. package/dist/app/useDocumentSaver.js +511 -0
  147. package/dist/app/useDocumentTabs.d.ts +41 -0
  148. package/dist/app/useDocumentTabs.js +207 -0
  149. package/dist/app/useDocumentWatcher.d.ts +83 -0
  150. package/dist/app/useDocumentWatcher.js +393 -0
  151. package/dist/app/useDocumentZoom.d.ts +24 -0
  152. package/dist/app/useDocumentZoom.js +104 -0
  153. package/dist/app/useDocuments.d.ts +169 -0
  154. package/dist/app/useDocuments.js +455 -0
  155. package/dist/app/useDraftConfirmGate.d.ts +27 -0
  156. package/dist/app/useDraftConfirmGate.js +47 -0
  157. package/dist/app/useFileDragOverlay.d.ts +12 -0
  158. package/dist/app/useFileDragOverlay.js +49 -0
  159. package/dist/app/useFormatApis.d.ts +13 -0
  160. package/dist/app/useFormatApis.js +62 -0
  161. package/dist/app/useFormatDirtyState.d.ts +29 -0
  162. package/dist/app/useFormatDirtyState.js +81 -0
  163. package/dist/app/useGlobalShortcuts.d.ts +47 -0
  164. package/dist/app/useGlobalShortcuts.js +359 -0
  165. package/dist/app/useHtmlSession.d.ts +68 -0
  166. package/dist/app/useHtmlSession.js +463 -0
  167. package/dist/app/useHtmlSessionProps.d.ts +33 -0
  168. package/dist/app/useHtmlSessionProps.js +57 -0
  169. package/dist/app/useLibrary.d.ts +21 -0
  170. package/dist/app/useLibrary.js +81 -0
  171. package/dist/app/useOpenFromClipboard.d.ts +7 -0
  172. package/dist/app/useOpenFromClipboard.js +44 -0
  173. package/dist/app/usePaneLiveness.d.ts +29 -0
  174. package/dist/app/usePaneLiveness.js +199 -0
  175. package/dist/app/usePendingSavePaths.d.ts +19 -0
  176. package/dist/app/usePendingSavePaths.js +67 -0
  177. package/dist/app/useReadyShow.d.ts +12 -0
  178. package/dist/app/useReadyShow.js +142 -0
  179. package/dist/app/useSearchController.d.ts +22 -0
  180. package/dist/app/useSearchController.js +114 -0
  181. package/dist/app/useSetupRecovery.d.ts +41 -0
  182. package/dist/app/useSetupRecovery.js +153 -0
  183. package/dist/app/useTabChrome.d.ts +40 -0
  184. package/dist/app/useTabChrome.js +115 -0
  185. package/dist/app/useViewState.d.ts +27 -0
  186. package/dist/app/useViewState.js +160 -0
  187. package/dist/appName.d.ts +2 -0
  188. package/dist/appName.js +8 -0
  189. package/dist/documents/DocumentRouter.d.ts +102 -0
  190. package/dist/documents/DocumentRouter.js +153 -0
  191. package/dist/documents/FileTypeIcon.d.ts +6 -0
  192. package/dist/documents/FileTypeIcon.js +93 -0
  193. package/dist/documents/ImageDocument.d.ts +14 -0
  194. package/dist/documents/ImageDocument.js +61 -0
  195. package/dist/documents/capabilities.d.ts +17 -0
  196. package/dist/documents/capabilities.js +18 -0
  197. package/dist/documents/html/HtmlDocument.d.ts +15 -0
  198. package/dist/documents/html/HtmlDocument.js +584 -0
  199. package/dist/documents/html/HtmlDocumentLayout.d.ts +87 -0
  200. package/dist/documents/html/HtmlDocumentLayout.js +25 -0
  201. package/dist/documents/html/HtmlDocumentProps.d.ts +60 -0
  202. package/dist/documents/html/HtmlDocumentProps.js +1 -0
  203. package/dist/documents/html/HtmlDocumentSource.d.ts +34 -0
  204. package/dist/documents/html/HtmlDocumentSource.js +28 -0
  205. package/dist/documents/markdown/MarkdownSplitPane.d.ts +115 -0
  206. package/dist/documents/markdown/MarkdownSplitPane.js +352 -0
  207. package/dist/documents/mdx/MdxSplitPane.d.ts +32 -0
  208. package/dist/documents/mdx/MdxSplitPane.js +60 -0
  209. package/dist/documents/txt/LinkDialog.d.ts +8 -0
  210. package/dist/documents/txt/LinkDialog.js +34 -0
  211. package/dist/documents/txt/MarkdownSourceToolbar.d.ts +8 -0
  212. package/dist/documents/txt/MarkdownSourceToolbar.js +25 -0
  213. package/dist/documents/txt/SourceEditorToolbar.d.ts +12 -0
  214. package/dist/documents/txt/SourceEditorToolbar.js +4 -0
  215. package/dist/documents/txt/TxtEditor.d.ts +39 -0
  216. package/dist/documents/txt/TxtEditor.js +186 -0
  217. package/dist/documents/txt/sourceEditorTypes.d.ts +49 -0
  218. package/dist/documents/txt/sourceEditorTypes.js +1 -0
  219. package/dist/documents/txt/sourceExtensions.d.ts +38 -0
  220. package/dist/documents/txt/sourceExtensions.js +444 -0
  221. package/dist/documents/txt/sourceFormatting.d.ts +18 -0
  222. package/dist/documents/txt/sourceFormatting.js +183 -0
  223. package/dist/documents/txt/sourceTheme.d.ts +5 -0
  224. package/dist/documents/txt/sourceTheme.js +220 -0
  225. package/dist/documents/txt/useCodeMirrorSourceEditor.d.ts +69 -0
  226. package/dist/documents/txt/useCodeMirrorSourceEditor.js +546 -0
  227. package/dist/documents/txt/useSourceSearch.d.ts +39 -0
  228. package/dist/documents/txt/useSourceSearch.js +122 -0
  229. package/dist/documents/txt/useTextEditorCommands.d.ts +26 -0
  230. package/dist/documents/txt/useTextEditorCommands.js +151 -0
  231. package/dist/documents/web/LivePreviewPane.d.ts +11 -0
  232. package/dist/documents/web/LivePreviewPane.js +58 -0
  233. package/dist/env.d.ts +66 -0
  234. package/dist/index.d.ts +121 -0
  235. package/dist/index.js +123 -0
  236. package/dist/settings/AppearanceMenu.d.ts +9 -0
  237. package/dist/settings/AppearanceMenu.js +54 -0
  238. package/dist/settings/SettingsPanel.d.ts +7 -0
  239. package/dist/settings/SettingsPanel.js +104 -0
  240. package/dist/settings/publishedSections.d.ts +22 -0
  241. package/dist/settings/publishedSections.js +79 -0
  242. package/dist/settings/sections/AboutSection.d.ts +1 -0
  243. package/dist/settings/sections/AboutSection.js +13 -0
  244. package/dist/settings/sections/DiagnosticsSection.d.ts +1 -0
  245. package/dist/settings/sections/DiagnosticsSection.js +42 -0
  246. package/dist/settings/sections/PrivacySection.d.ts +3 -0
  247. package/dist/settings/sections/PrivacySection.js +51 -0
  248. package/dist/settings/sections/UpdateLicenseBlock.d.ts +10 -0
  249. package/dist/settings/sections/UpdateLicenseBlock.js +158 -0
  250. package/dist/state/explorer.d.ts +32 -0
  251. package/dist/state/explorer.js +111 -0
  252. package/dist/state/legal.d.ts +51 -0
  253. package/dist/state/legal.js +130 -0
  254. package/dist/state/library.d.ts +33 -0
  255. package/dist/state/library.js +110 -0
  256. package/dist/state/updateLicense.d.ts +31 -0
  257. package/dist/state/updateLicense.js +340 -0
  258. package/dist/styles/explorer.css +219 -0
  259. package/dist/styles/index.css +1477 -0
  260. package/dist/styles/tabs.css +467 -0
  261. package/dist/styles.css +6 -0
  262. package/package.json +88 -3
@@ -0,0 +1,359 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { createShortcutRegistry } from "@rightkit/react-shell";
3
+ import { capabilitiesFor } from "../documents/capabilities.js";
4
+ // Global keyboard map, registered on the RightKit shortcut registry. Modifier shortcuts: Ctrl/Cmd+N new,
5
+ // +O open, +Shift+P palette; +F find, +H replace; +W close; +P print; +S save, +Shift+S save as; +Tab /
6
+ // +Shift+Tab cycle tabs; +1..9 jump to tab; +Shift+T reopen closed; +0 reset zoom; +E toggle sidebar. Bare
7
+ // keys (guarded against focused editors): Alt+Z word wrap, ? help overlay. DOCX routes save/print through
8
+ // its bridge.
9
+ export function useGlobalShortcuts({ active, activeEditable, searchProvider, canOpenFind, docxMenu, newDocument, onOpenDialog, onPrint, onSave, onSaveAs, requestClose, togglePalette, openFind, onHtmlSaveShortcut, reloadActiveFromDisk, openFromClipboard, cycleTab, jumpToTab, reopenClosed, resetZoom, toggleWordWrap, toggleSidebar, toggleTabOverview, showHelp, findOpen, toggleDistractionFree, }) {
10
+ const latest = {
11
+ active,
12
+ activeEditable,
13
+ searchProvider,
14
+ canOpenFind,
15
+ docxMenu,
16
+ newDocument,
17
+ onOpenDialog,
18
+ onPrint,
19
+ onSave,
20
+ onSaveAs,
21
+ requestClose,
22
+ openFind,
23
+ onHtmlSaveShortcut,
24
+ reloadActiveFromDisk,
25
+ openFromClipboard,
26
+ cycleTab,
27
+ jumpToTab,
28
+ reopenClosed,
29
+ resetZoom,
30
+ toggleWordWrap,
31
+ toggleSidebar,
32
+ toggleTabOverview,
33
+ showHelp,
34
+ findOpen,
35
+ togglePalette,
36
+ toggleDistractionFree,
37
+ };
38
+ const latestRef = useRef(latest);
39
+ latestRef.current = latest;
40
+ useEffect(() => {
41
+ const registry = createShortcutRegistry();
42
+ // The former window listener ran for every keydown, even one another handler had already prevented
43
+ // (editors and previews call preventDefault on their own keys) or one during IME composition. Each
44
+ // binding keeps that behaviour, so the shell chords still fire exactly as before.
45
+ const bind = (def) => registry.register({ allowDefaultPrevented: true, allowComposing: true, ...def });
46
+ // Gated bindings act on the active document; the rest work with no document open.
47
+ const hasActive = () => latestRef.current.active !== null;
48
+ // Browser-style refresh: HTML re-reads its current page + rebuilds the preview (via the window
49
+ // event HtmlDocument listens for); other disk docs re-read from disk. Always preventDefault on the
50
+ // caller so F5/Ctrl+R never reload the whole WebView2 app (which would blow away all open tabs).
51
+ const reloadActiveDoc = () => {
52
+ const { active, reloadActiveFromDisk } = latestRef.current;
53
+ if (!active)
54
+ return;
55
+ if (active.format === "html")
56
+ window.dispatchEvent(new Event("viewright:html-reload"));
57
+ else if (active.format === "web")
58
+ window.dispatchEvent(new Event("viewright:web-reload"));
59
+ else
60
+ reloadActiveFromDisk(active);
61
+ };
62
+ bind({
63
+ id: "reload",
64
+ label: "Reload",
65
+ chord: ["f5", "ctrlormeta+r", "ctrlormeta+shift+r"],
66
+ allowInInput: true,
67
+ run: () => {
68
+ reloadActiveDoc();
69
+ },
70
+ });
71
+ // Browser-native inspect accelerators are consumed so WebView2/WKWebView never opens the whole-app
72
+ // inspector. HTML preview frames own these shortcuts & forward them through their scoped bridge;
73
+ // events originating inside an iframe do not bubble into this document. Cmd/Ctrl+Opt+I is the
74
+ // reliable Mac path because bare F12 is normally volume-up; Ctrl+Shift+I is the Windows/Linux path.
75
+ bind({
76
+ id: "inspector-consume",
77
+ label: "Inspector (consumed)",
78
+ hidden: true,
79
+ chord: ["f12", "ctrlormeta+alt+i", "ctrlormeta+shift+i"],
80
+ allowInInput: true,
81
+ run: () => undefined,
82
+ });
83
+ // F3 / Shift+F3 step find next/previous (works even inside an editor — it's not a character).
84
+ // If the bar is open, let it own the step; otherwise open it.
85
+ const findStep = (dir) => {
86
+ const { findOpen, canOpenFind, searchProvider, openFind } = latestRef.current;
87
+ if (findOpen)
88
+ window.dispatchEvent(new CustomEvent("viewright:find-step", { detail: { dir } }));
89
+ else if (canOpenFind ?? !!searchProvider)
90
+ openFind(false);
91
+ };
92
+ bind({
93
+ id: "find-next",
94
+ label: "Find next",
95
+ chord: "f3",
96
+ allowInInput: true,
97
+ run: () => {
98
+ findStep(1);
99
+ },
100
+ });
101
+ bind({
102
+ id: "find-previous",
103
+ label: "Find previous",
104
+ chord: "shift+f3",
105
+ allowInInput: true,
106
+ run: () => {
107
+ findStep(-1);
108
+ },
109
+ });
110
+ // Bare keys: the registry drops these while focus is in a text field (allowInInput: false).
111
+ bind({
112
+ id: "word-wrap",
113
+ label: "Toggle word wrap",
114
+ chord: ["alt+z", "alt+shift+z"],
115
+ allowInInput: false,
116
+ run: () => {
117
+ latestRef.current.toggleWordWrap();
118
+ },
119
+ });
120
+ bind({
121
+ id: "help",
122
+ label: "Keyboard shortcuts",
123
+ chord: "?",
124
+ allowInInput: false,
125
+ run: () => {
126
+ latestRef.current.showHelp();
127
+ },
128
+ });
129
+ // Ctrl/Cmd+V (and the explicit Ctrl/Cmd+Shift+V) → open whatever's on the clipboard. Suppressed inside
130
+ // a text field so an editor's own paste keeps working there.
131
+ bind({
132
+ id: "paste",
133
+ label: "Open clipboard",
134
+ chord: ["ctrlormeta+v", "ctrlormeta+shift+v"],
135
+ allowInInput: false,
136
+ run: () => {
137
+ latestRef.current.openFromClipboard();
138
+ },
139
+ });
140
+ // Tab navigation (independent of the active doc).
141
+ bind({
142
+ id: "tab-next",
143
+ label: "Next tab",
144
+ chord: "ctrlormeta+tab",
145
+ run: () => {
146
+ latestRef.current.cycleTab(1);
147
+ },
148
+ });
149
+ bind({
150
+ id: "tab-previous",
151
+ label: "Previous tab",
152
+ chord: "ctrlormeta+shift+tab",
153
+ run: () => {
154
+ latestRef.current.cycleTab(-1);
155
+ },
156
+ });
157
+ bind({
158
+ id: "tab-jump",
159
+ label: "Jump to tab",
160
+ chord: Array.from({ length: 9 }, (_, i) => `ctrlormeta+${i + 1}`),
161
+ run: (event) => {
162
+ latestRef.current.jumpToTab(Number(event.key) - 1); // 9 is mapped to "last tab" by the handler
163
+ },
164
+ });
165
+ bind({
166
+ id: "new-document-tab",
167
+ label: "New document",
168
+ chord: "ctrlormeta+t", // Ctrl/Cmd+T — new untitled tab, same as the strip's "+"
169
+ run: () => {
170
+ latestRef.current.newDocument();
171
+ },
172
+ });
173
+ bind({
174
+ id: "reopen-closed",
175
+ label: "Reopen closed tab",
176
+ chord: "ctrlormeta+shift+t",
177
+ run: () => {
178
+ latestRef.current.reopenClosed();
179
+ },
180
+ });
181
+ bind({
182
+ id: "toggle-sidebar",
183
+ label: "Toggle sidebar",
184
+ chord: ["ctrlormeta+e", "ctrlormeta+\\"],
185
+ run: () => {
186
+ latestRef.current.toggleSidebar();
187
+ },
188
+ });
189
+ bind({
190
+ id: "tab-overview",
191
+ label: "Tab overview",
192
+ chord: "ctrlormeta+shift+a",
193
+ run: () => {
194
+ latestRef.current.toggleTabOverview();
195
+ },
196
+ });
197
+ // Document commands. The modifier-tolerant ones keep their former behaviour of ignoring Shift/Alt.
198
+ bind({
199
+ id: "new-document",
200
+ label: "New document",
201
+ chord: "ctrlormeta+n",
202
+ ignoreExtraModifiers: true,
203
+ run: () => {
204
+ latestRef.current.newDocument();
205
+ },
206
+ });
207
+ bind({
208
+ id: "open",
209
+ label: "Open",
210
+ chord: "ctrlormeta+o",
211
+ ignoreExtraModifiers: true,
212
+ run: () => {
213
+ void latestRef.current.onOpenDialog();
214
+ },
215
+ });
216
+ bind({
217
+ id: "palette",
218
+ label: "Command palette",
219
+ chord: "ctrlormeta+shift+p",
220
+ run: () => {
221
+ latestRef.current.togglePalette();
222
+ },
223
+ });
224
+ // Distraction-free reading is checked before the find handler so Shift+F doesn't open find.
225
+ bind({
226
+ id: "distraction-free",
227
+ label: "Distraction-free reading",
228
+ chord: "ctrlormeta+shift+f",
229
+ run: () => {
230
+ latestRef.current.toggleDistractionFree();
231
+ },
232
+ });
233
+ // Find is always swallowed for Ctrl+F AND Ctrl+G so WebView2's native find-on-page never opens (Ctrl+G
234
+ // is the engine's "find next" and would otherwise leak the native bar inside an iframe preview).
235
+ // Route both to the host app own find; open even if the provider is still racing into place.
236
+ const openFindFromShortcut = () => {
237
+ const { canOpenFind, searchProvider, openFind } = latestRef.current;
238
+ if (canOpenFind ?? !!searchProvider)
239
+ openFind(false);
240
+ };
241
+ bind({
242
+ id: "reset-zoom",
243
+ label: "Reset zoom",
244
+ chord: "ctrlormeta+0",
245
+ ignoreExtraModifiers: true,
246
+ when: hasActive,
247
+ run: () => {
248
+ latestRef.current.resetZoom();
249
+ },
250
+ });
251
+ bind({
252
+ id: "find",
253
+ label: "Find",
254
+ chord: "ctrlormeta+f",
255
+ when: hasActive,
256
+ run: openFindFromShortcut,
257
+ });
258
+ bind({
259
+ id: "find-g",
260
+ label: "Find",
261
+ chord: "ctrlormeta+g",
262
+ ignoreExtraModifiers: true,
263
+ when: hasActive,
264
+ run: openFindFromShortcut,
265
+ });
266
+ bind({
267
+ id: "replace",
268
+ label: "Replace",
269
+ chord: "ctrlormeta+h",
270
+ ignoreExtraModifiers: true,
271
+ when: hasActive,
272
+ run: () => {
273
+ const { searchProvider, openFind } = latestRef.current;
274
+ if (searchProvider?.canReplace)
275
+ openFind(true);
276
+ },
277
+ });
278
+ // Close the active document (with unsaved-guard) — never let WebView2 close the window.
279
+ bind({
280
+ id: "close-document",
281
+ label: "Close document",
282
+ chord: "ctrlormeta+w",
283
+ ignoreExtraModifiers: true,
284
+ when: hasActive,
285
+ run: () => {
286
+ const doc = latestRef.current.active;
287
+ if (doc)
288
+ latestRef.current.requestClose(doc.path);
289
+ },
290
+ });
291
+ // DOCX prints through the editor bridge; route it like save so Ctrl+P works everywhere.
292
+ bind({
293
+ id: "print",
294
+ label: "Print",
295
+ chord: "ctrlormeta+p",
296
+ when: hasActive,
297
+ run: () => {
298
+ const doc = latestRef.current.active;
299
+ if (!doc)
300
+ return;
301
+ if (doc.format === "docx")
302
+ void latestRef.current.docxMenu?.print();
303
+ else
304
+ latestRef.current.onPrint(doc);
305
+ },
306
+ });
307
+ bind({
308
+ id: "save-as",
309
+ label: "Save as",
310
+ chord: "ctrlormeta+shift+s",
311
+ when: hasActive,
312
+ run: () => {
313
+ const doc = latestRef.current.active;
314
+ if (doc && capabilitiesFor(doc.format).canSaveAs)
315
+ latestRef.current.onSaveAs(doc);
316
+ },
317
+ });
318
+ bind({
319
+ id: "save",
320
+ label: "Save",
321
+ chord: "ctrlormeta+s",
322
+ when: hasActive,
323
+ run: () => {
324
+ const doc = latestRef.current.active;
325
+ if (!doc)
326
+ return;
327
+ // Route DOCX save through the editor bridge (it no longer ships its own toolbar/keymap).
328
+ if (doc.format === "docx")
329
+ void latestRef.current.docxMenu?.save();
330
+ // One dirty page saves directly; several open the page-aware Save current / Save all chooser.
331
+ else if (doc.format === "html")
332
+ latestRef.current.onHtmlSaveShortcut(doc.path);
333
+ else if (latestRef.current.activeEditable)
334
+ latestRef.current.onSave(doc);
335
+ },
336
+ });
337
+ const detachKeys = registry.attach(window);
338
+ // Native Window-menu items can't bind ⌃Tab through the menu-bridge key syntax, so lib.rs emits
339
+ // these events instead ("Select Next/Previous Tab").
340
+ const nextTab = () => latestRef.current.cycleTab(1);
341
+ const prevTab = () => latestRef.current.cycleTab(-1);
342
+ window.addEventListener("viewright:next-tab", nextTab);
343
+ window.addEventListener("viewright:prev-tab", prevTab);
344
+ // The crash screen's "Close tab" action (ErrorBoundary) asks the shell to close a tab through
345
+ // the same unsaved-guarded path as Ctrl+W.
346
+ const closeTab = (e) => {
347
+ const path = e.detail?.path;
348
+ if (path)
349
+ latestRef.current.requestClose(path);
350
+ };
351
+ window.addEventListener("viewright:close-tab", closeTab);
352
+ return () => {
353
+ window.removeEventListener("viewright:close-tab", closeTab);
354
+ detachKeys();
355
+ window.removeEventListener("viewright:next-tab", nextTab);
356
+ window.removeEventListener("viewright:prev-tab", prevTab);
357
+ };
358
+ }, []);
359
+ }
@@ -0,0 +1,68 @@
1
+ import { type Dispatch, type SetStateAction } from "react";
2
+ import { type LoadedDocument } from "@rightkit/document-core/documents/types";
3
+ import type { DocumentTabs } from "./useDocumentTabs.js";
4
+ import type { BlockDraftRegistry } from "@rightkit/document-core/app/blockDrafts";
5
+ /** The page-aware close/save chooser target: which session, and whether saving should also close it. */
6
+ export type HtmlConfirmState = {
7
+ entryPath: string;
8
+ mode: "save" | "close";
9
+ } | null;
10
+ /** A sub-page on-disk conflict awaiting the user's reload/keep decision. */
11
+ export type HtmlConflictState = {
12
+ entryPath: string;
13
+ pagePath: string;
14
+ } | null;
15
+ /** Shared tab/edit state this hook reads through (owned by useDocumentTabs, threaded via useDocuments). */
16
+ type TabsForHtml = Pick<DocumentTabs, "openDocs" | "editsRef" | "writeEdits" | "htmlPagesRef" | "writeHtmlPages" | "htmlActivePage" | "setHtmlActivePage">;
17
+ interface HtmlSessionDeps extends TabsForHtml {
18
+ htmlConfirm: HtmlConfirmState;
19
+ setHtmlConfirm: Dispatch<SetStateAction<HtmlConfirmState>>;
20
+ htmlConflict: HtmlConflictState;
21
+ setHtmlConflict: Dispatch<SetStateAction<HtmlConflictState>>;
22
+ onSave: (doc: LoadedDocument, options?: {
23
+ silent?: boolean;
24
+ resolveDrafts?: boolean;
25
+ }) => Promise<string | null>;
26
+ doClose: (path: string) => void;
27
+ markSelfSaved: (path: string) => void;
28
+ setError: Dispatch<SetStateAction<string | null>>;
29
+ onDirty?: (entryPath: string) => void;
30
+ onSaveActivity?: (entryPath: string, delta: 1 | -1) => void;
31
+ blockDrafts?: BlockDraftRegistry;
32
+ }
33
+ /**
34
+ * HTML site sessions: the navigated SUB-page buffers (the entry page reuses the shared edits/onSave
35
+ * path), their per-page save/discard/dirty model, the page-aware close/save chooser, the sub-page
36
+ * on-disk conflict flow, and the external-change reconciliation for a session's sub-pages.
37
+ *
38
+ * Extracted verbatim from useDocuments so that hook stays a focused open/save/close/conflict surface.
39
+ * Bodies are unchanged from when this lived inline; the only edits are deps-array entries for the
40
+ * dialog/error setters, which are stable props here rather than this hook's own useState setters.
41
+ */
42
+ export declare function useHtmlSession({ openDocs, editsRef, writeEdits, htmlPagesRef, writeHtmlPages, htmlActivePage, setHtmlActivePage, htmlConfirm, setHtmlConfirm, htmlConflict, setHtmlConflict, onSave, doClose, markSelfSaved, setError, onDirty, onSaveActivity, blockDrafts, }: HtmlSessionDeps): {
43
+ ensureHtmlPage: (entryPath: string, pagePath: string) => Promise<void>;
44
+ setHtmlPageEdited: (entryPath: string, pagePath: string, edited: string) => void;
45
+ setHtmlActive: (entryPath: string, pagePath: string) => void;
46
+ discardHtmlPage: (entryPath: string, pagePath: string) => void;
47
+ saveHtmlPage: (entryPath: string, pagePath: string, options?: {
48
+ silent?: boolean;
49
+ }) => Promise<boolean>;
50
+ saveAllHtmlPages: (entryPath: string, options?: {
51
+ silent?: boolean;
52
+ }) => Promise<boolean>;
53
+ discardAllHtmlPages: (entryPath: string) => void;
54
+ onHtmlSaveShortcut: (entryPath: string) => void;
55
+ htmlDirtyPages: (entryPath: string) => {
56
+ path: string;
57
+ name: string;
58
+ isEntry: boolean;
59
+ }[];
60
+ htmlSaveCurrent: () => Promise<void>;
61
+ htmlSaveAll: () => Promise<void>;
62
+ htmlDiscardAll: () => void;
63
+ htmlConfirmCancel: () => void;
64
+ htmlConflictReload: () => Promise<void>;
65
+ htmlConflictKeep: () => Promise<void>;
66
+ reloadHtmlSubpage: (path: string) => void;
67
+ };
68
+ export {};