@rightkit/document-workspace 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE-APACHE +201 -0
- package/LICENSE-MIT +21 -0
- package/README.md +74 -2
- package/dist/app/App.d.ts +1 -0
- package/dist/app/App.js +6 -0
- package/dist/app/AppDialogs.d.ts +52 -0
- package/dist/app/AppDialogs.js +23 -0
- package/dist/app/AppDialogsHost.d.ts +31 -0
- package/dist/app/AppDialogsHost.js +30 -0
- package/dist/app/AppLifecycle.d.ts +19 -0
- package/dist/app/AppLifecycle.js +87 -0
- package/dist/app/AppProvider.d.ts +317 -0
- package/dist/app/AppProvider.js +217 -0
- package/dist/app/AppRoot.d.ts +8 -0
- package/dist/app/AppRoot.js +159 -0
- package/dist/app/AppShell.d.ts +2 -0
- package/dist/app/AppShell.js +81 -0
- package/dist/app/CommandPalette.d.ts +13 -0
- package/dist/app/CommandPalette.js +47 -0
- package/dist/app/DocActionBar.d.ts +36 -0
- package/dist/app/DocActionBar.js +300 -0
- package/dist/app/DocumentContextMenu.d.ts +29 -0
- package/dist/app/DocumentContextMenu.js +122 -0
- package/dist/app/DocumentPane.d.ts +52 -0
- package/dist/app/DocumentPane.js +30 -0
- package/dist/app/DocumentRouterTable.d.ts +58 -0
- package/dist/app/DocumentRouterTable.js +143 -0
- package/dist/app/ErrorBoundary.d.ts +12 -0
- package/dist/app/ErrorBoundary.js +16 -0
- package/dist/app/FindBar.d.ts +12 -0
- package/dist/app/FindBar.js +199 -0
- package/dist/app/LiveTitle.d.ts +14 -0
- package/dist/app/LiveTitle.js +14 -0
- package/dist/app/OpeningProgress.d.ts +13 -0
- package/dist/app/OpeningProgress.js +21 -0
- package/dist/app/PrintPreviewWindow.d.ts +2 -0
- package/dist/app/PrintPreviewWindow.js +57 -0
- package/dist/app/ShortcutHelp.d.ts +3 -0
- package/dist/app/ShortcutHelp.js +99 -0
- package/dist/app/Sidebar.d.ts +36 -0
- package/dist/app/Sidebar.js +121 -0
- package/dist/app/ToastViewport.d.ts +1 -0
- package/dist/app/ToastViewport.js +31 -0
- package/dist/app/Toolbar.d.ts +26 -0
- package/dist/app/Toolbar.js +63 -0
- package/dist/app/activeFormatSavers.d.ts +7 -0
- package/dist/app/activeFormatSavers.js +4 -0
- package/dist/app/clipboardPaths.d.ts +1 -0
- package/dist/app/clipboardPaths.js +31 -0
- package/dist/app/documentDrafts.d.ts +17 -0
- package/dist/app/documentDrafts.js +104 -0
- package/dist/app/draftResolution.d.ts +5 -0
- package/dist/app/draftResolution.js +25 -0
- package/dist/app/markdownPaletteActions.d.ts +8 -0
- package/dist/app/markdownPaletteActions.js +107 -0
- package/dist/app/resourceCensusDev.d.ts +41 -0
- package/dist/app/resourceCensusDev.js +518 -0
- package/dist/app/setupRecovery.d.ts +34 -0
- package/dist/app/setupRecovery.js +70 -0
- package/dist/app/shell/DocStatsPill.d.ts +18 -0
- package/dist/app/shell/DocStatsPill.js +32 -0
- package/dist/app/shell/DocumentTools.d.ts +9 -0
- package/dist/app/shell/DocumentTools.js +73 -0
- package/dist/app/shell/InfoInspector.d.ts +9 -0
- package/dist/app/shell/InfoInspector.js +67 -0
- package/dist/app/shell/StartPage.d.ts +9 -0
- package/dist/app/shell/StartPage.js +49 -0
- package/dist/app/shell/readEdit.d.ts +6 -0
- package/dist/app/shell/readEdit.js +6 -0
- package/dist/app/sidebar/SidebarDocumentMenu.d.ts +20 -0
- package/dist/app/sidebar/SidebarDocumentMenu.js +56 -0
- package/dist/app/sidebar/SidebarExpandedPanel.d.ts +9 -0
- package/dist/app/sidebar/SidebarExpandedPanel.js +78 -0
- package/dist/app/sidebar/SidebarIcons.d.ts +3 -0
- package/dist/app/sidebar/SidebarIcons.js +18 -0
- package/dist/app/sidebar/SidebarMenus.d.ts +19 -0
- package/dist/app/sidebar/SidebarMenus.js +64 -0
- package/dist/app/sidebar/SidebarPathUtils.d.ts +10 -0
- package/dist/app/sidebar/SidebarPathUtils.js +55 -0
- package/dist/app/sidebar/SidebarPrimitives.d.ts +12 -0
- package/dist/app/sidebar/SidebarPrimitives.js +45 -0
- package/dist/app/sidebar/SidebarRail.d.ts +5 -0
- package/dist/app/sidebar/SidebarRail.js +37 -0
- package/dist/app/sidebar/explorer/ExplorerRowMenu.d.ts +21 -0
- package/dist/app/sidebar/explorer/ExplorerRowMenu.js +37 -0
- package/dist/app/sidebar/explorer/ExplorerSections.d.ts +16 -0
- package/dist/app/sidebar/explorer/ExplorerSections.js +259 -0
- package/dist/app/sidebar/explorer/ExplorerTree.d.ts +46 -0
- package/dist/app/sidebar/explorer/ExplorerTree.js +387 -0
- package/dist/app/sidebar/explorer/explorerState.d.ts +37 -0
- package/dist/app/sidebar/explorer/explorerState.js +135 -0
- package/dist/app/tabMountPolicy.d.ts +45 -0
- package/dist/app/tabMountPolicy.js +104 -0
- package/dist/app/tabWarmOrder.d.ts +7 -0
- package/dist/app/tabWarmOrder.js +48 -0
- package/dist/app/tabs/TabFuseCurves.d.ts +3 -0
- package/dist/app/tabs/TabFuseCurves.js +15 -0
- package/dist/app/tabs/TabOverview.d.ts +24 -0
- package/dist/app/tabs/TabOverview.js +121 -0
- package/dist/app/tabs/TabStrip.d.ts +42 -0
- package/dist/app/tabs/TabStrip.js +380 -0
- package/dist/app/tabs/tabIds.d.ts +5 -0
- package/dist/app/tabs/tabIds.js +7 -0
- package/dist/app/tabs/useTabDirty.d.ts +3 -0
- package/dist/app/tabs/useTabDirty.js +11 -0
- package/dist/app/useAppChromeState.d.ts +21 -0
- package/dist/app/useAppChromeState.js +48 -0
- package/dist/app/useAppCommands.d.ts +66 -0
- package/dist/app/useAppCommands.js +71 -0
- package/dist/app/useAppDocumentCore.d.ts +210 -0
- package/dist/app/useAppDocumentCore.js +40 -0
- package/dist/app/useAppEffects.d.ts +18 -0
- package/dist/app/useAppEffects.js +52 -0
- package/dist/app/useAppPaneSearch.d.ts +37 -0
- package/dist/app/useAppPaneSearch.js +74 -0
- package/dist/app/useAppShellSetup.d.ts +40 -0
- package/dist/app/useAppShellSetup.js +52 -0
- package/dist/app/useAppSlots.d.ts +28 -0
- package/dist/app/useAppSlots.js +40 -0
- package/dist/app/useAppTabChrome.d.ts +51 -0
- package/dist/app/useAppTabChrome.js +66 -0
- package/dist/app/useAutoSave.d.ts +34 -0
- package/dist/app/useAutoSave.js +116 -0
- package/dist/app/useCloseAll.d.ts +52 -0
- package/dist/app/useCloseAll.js +295 -0
- package/dist/app/useClosedTabEviction.d.ts +10 -0
- package/dist/app/useClosedTabEviction.js +38 -0
- package/dist/app/useCommandPalette.d.ts +44 -0
- package/dist/app/useCommandPalette.js +254 -0
- package/dist/app/useCrossDocSearch.d.ts +7 -0
- package/dist/app/useCrossDocSearch.js +94 -0
- package/dist/app/useDistractionFree.d.ts +21 -0
- package/dist/app/useDistractionFree.js +73 -0
- package/dist/app/useDocumentCreation.d.ts +18 -0
- package/dist/app/useDocumentCreation.js +63 -0
- package/dist/app/useDocumentDirty.d.ts +31 -0
- package/dist/app/useDocumentDirty.js +46 -0
- package/dist/app/useDocumentLoader.d.ts +55 -0
- package/dist/app/useDocumentLoader.js +267 -0
- package/dist/app/useDocumentOutputActions.d.ts +6 -0
- package/dist/app/useDocumentOutputActions.js +45 -0
- package/dist/app/useDocumentRuntimeEffects.d.ts +36 -0
- package/dist/app/useDocumentRuntimeEffects.js +458 -0
- package/dist/app/useDocumentSaver.d.ts +58 -0
- package/dist/app/useDocumentSaver.js +511 -0
- package/dist/app/useDocumentTabs.d.ts +41 -0
- package/dist/app/useDocumentTabs.js +207 -0
- package/dist/app/useDocumentWatcher.d.ts +83 -0
- package/dist/app/useDocumentWatcher.js +393 -0
- package/dist/app/useDocumentZoom.d.ts +24 -0
- package/dist/app/useDocumentZoom.js +104 -0
- package/dist/app/useDocuments.d.ts +169 -0
- package/dist/app/useDocuments.js +455 -0
- package/dist/app/useDraftConfirmGate.d.ts +27 -0
- package/dist/app/useDraftConfirmGate.js +47 -0
- package/dist/app/useFileDragOverlay.d.ts +12 -0
- package/dist/app/useFileDragOverlay.js +49 -0
- package/dist/app/useFormatApis.d.ts +13 -0
- package/dist/app/useFormatApis.js +62 -0
- package/dist/app/useFormatDirtyState.d.ts +29 -0
- package/dist/app/useFormatDirtyState.js +81 -0
- package/dist/app/useGlobalShortcuts.d.ts +47 -0
- package/dist/app/useGlobalShortcuts.js +359 -0
- package/dist/app/useHtmlSession.d.ts +68 -0
- package/dist/app/useHtmlSession.js +463 -0
- package/dist/app/useHtmlSessionProps.d.ts +33 -0
- package/dist/app/useHtmlSessionProps.js +57 -0
- package/dist/app/useLibrary.d.ts +21 -0
- package/dist/app/useLibrary.js +81 -0
- package/dist/app/useOpenFromClipboard.d.ts +7 -0
- package/dist/app/useOpenFromClipboard.js +44 -0
- package/dist/app/usePaneLiveness.d.ts +29 -0
- package/dist/app/usePaneLiveness.js +199 -0
- package/dist/app/usePendingSavePaths.d.ts +19 -0
- package/dist/app/usePendingSavePaths.js +67 -0
- package/dist/app/useReadyShow.d.ts +12 -0
- package/dist/app/useReadyShow.js +142 -0
- package/dist/app/useSearchController.d.ts +22 -0
- package/dist/app/useSearchController.js +114 -0
- package/dist/app/useSetupRecovery.d.ts +41 -0
- package/dist/app/useSetupRecovery.js +153 -0
- package/dist/app/useTabChrome.d.ts +40 -0
- package/dist/app/useTabChrome.js +115 -0
- package/dist/app/useViewState.d.ts +27 -0
- package/dist/app/useViewState.js +160 -0
- package/dist/appName.d.ts +2 -0
- package/dist/appName.js +8 -0
- package/dist/documents/DocumentRouter.d.ts +102 -0
- package/dist/documents/DocumentRouter.js +153 -0
- package/dist/documents/FileTypeIcon.d.ts +6 -0
- package/dist/documents/FileTypeIcon.js +93 -0
- package/dist/documents/ImageDocument.d.ts +14 -0
- package/dist/documents/ImageDocument.js +61 -0
- package/dist/documents/capabilities.d.ts +17 -0
- package/dist/documents/capabilities.js +18 -0
- package/dist/documents/html/HtmlDocument.d.ts +15 -0
- package/dist/documents/html/HtmlDocument.js +584 -0
- package/dist/documents/html/HtmlDocumentLayout.d.ts +87 -0
- package/dist/documents/html/HtmlDocumentLayout.js +25 -0
- package/dist/documents/html/HtmlDocumentProps.d.ts +60 -0
- package/dist/documents/html/HtmlDocumentProps.js +1 -0
- package/dist/documents/html/HtmlDocumentSource.d.ts +34 -0
- package/dist/documents/html/HtmlDocumentSource.js +28 -0
- package/dist/documents/markdown/MarkdownSplitPane.d.ts +115 -0
- package/dist/documents/markdown/MarkdownSplitPane.js +352 -0
- package/dist/documents/mdx/MdxSplitPane.d.ts +32 -0
- package/dist/documents/mdx/MdxSplitPane.js +60 -0
- package/dist/documents/txt/LinkDialog.d.ts +8 -0
- package/dist/documents/txt/LinkDialog.js +34 -0
- package/dist/documents/txt/MarkdownSourceToolbar.d.ts +8 -0
- package/dist/documents/txt/MarkdownSourceToolbar.js +25 -0
- package/dist/documents/txt/SourceEditorToolbar.d.ts +12 -0
- package/dist/documents/txt/SourceEditorToolbar.js +4 -0
- package/dist/documents/txt/TxtEditor.d.ts +39 -0
- package/dist/documents/txt/TxtEditor.js +186 -0
- package/dist/documents/txt/sourceEditorTypes.d.ts +49 -0
- package/dist/documents/txt/sourceEditorTypes.js +1 -0
- package/dist/documents/txt/sourceExtensions.d.ts +38 -0
- package/dist/documents/txt/sourceExtensions.js +444 -0
- package/dist/documents/txt/sourceFormatting.d.ts +18 -0
- package/dist/documents/txt/sourceFormatting.js +183 -0
- package/dist/documents/txt/sourceTheme.d.ts +5 -0
- package/dist/documents/txt/sourceTheme.js +220 -0
- package/dist/documents/txt/useCodeMirrorSourceEditor.d.ts +69 -0
- package/dist/documents/txt/useCodeMirrorSourceEditor.js +546 -0
- package/dist/documents/txt/useSourceSearch.d.ts +39 -0
- package/dist/documents/txt/useSourceSearch.js +122 -0
- package/dist/documents/txt/useTextEditorCommands.d.ts +26 -0
- package/dist/documents/txt/useTextEditorCommands.js +151 -0
- package/dist/documents/web/LivePreviewPane.d.ts +11 -0
- package/dist/documents/web/LivePreviewPane.js +58 -0
- package/dist/env.d.ts +66 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +123 -0
- package/dist/settings/AppearanceMenu.d.ts +9 -0
- package/dist/settings/AppearanceMenu.js +54 -0
- package/dist/settings/SettingsPanel.d.ts +7 -0
- package/dist/settings/SettingsPanel.js +104 -0
- package/dist/settings/publishedSections.d.ts +22 -0
- package/dist/settings/publishedSections.js +79 -0
- package/dist/settings/sections/AboutSection.d.ts +1 -0
- package/dist/settings/sections/AboutSection.js +13 -0
- package/dist/settings/sections/DiagnosticsSection.d.ts +1 -0
- package/dist/settings/sections/DiagnosticsSection.js +42 -0
- package/dist/settings/sections/PrivacySection.d.ts +3 -0
- package/dist/settings/sections/PrivacySection.js +51 -0
- package/dist/settings/sections/UpdateLicenseBlock.d.ts +10 -0
- package/dist/settings/sections/UpdateLicenseBlock.js +158 -0
- package/dist/state/explorer.d.ts +32 -0
- package/dist/state/explorer.js +111 -0
- package/dist/state/legal.d.ts +51 -0
- package/dist/state/legal.js +130 -0
- package/dist/state/library.d.ts +33 -0
- package/dist/state/library.js +110 -0
- package/dist/state/updateLicense.d.ts +31 -0
- package/dist/state/updateLicense.js +340 -0
- package/dist/styles/explorer.css +219 -0
- package/dist/styles/index.css +1477 -0
- package/dist/styles/tabs.css +467 -0
- package/dist/styles.css +6 -0
- package/package.json +88 -3
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { type Dispatch, type MutableRefObject, type SetStateAction } from "react";
|
|
2
|
+
import { type LoadedDocument, type ViewMeta, type ViewMode } from "@rightkit/document-core/documents/types";
|
|
3
|
+
import type { DocumentTabs } from "./useDocumentTabs.js";
|
|
4
|
+
import { type HtmlConfirmState, type HtmlConflictState } from "./useHtmlSession.js";
|
|
5
|
+
import { pickNextActive } from "./useDocumentWatcher.js";
|
|
6
|
+
export { pickNextActive };
|
|
7
|
+
interface ViewStateDeps {
|
|
8
|
+
setViews: Dispatch<SetStateAction<Record<string, ViewMode>>>;
|
|
9
|
+
viewsRef: MutableRefObject<Record<string, ViewMode>>;
|
|
10
|
+
viewMetaRef: MutableRefObject<Record<string, ViewMeta>>;
|
|
11
|
+
dropViewState: (path: string) => void;
|
|
12
|
+
}
|
|
13
|
+
interface LibraryDeps {
|
|
14
|
+
refreshLibrary: () => Promise<void>;
|
|
15
|
+
syncPinned: (path: string) => Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The document lifecycle orchestrator: composes useDocumentLoader (open/read), useDocumentSaver
|
|
19
|
+
* (save/save-as), and useDocumentWatcher (close/teardown/reopen + external-change reload) around the
|
|
20
|
+
* shared `tabs` state and view-state/library setters (passed in to avoid a hook-ordering cycle).
|
|
21
|
+
* Bodies are unchanged from when everything lived in one 862-line hook — this file now just wires the
|
|
22
|
+
* pieces together and owns the state/refs genuinely shared across all three (fingerprints, the
|
|
23
|
+
* open-docs/activation-order mirrors, and the dialog state the HTML session drives).
|
|
24
|
+
*/
|
|
25
|
+
export declare function useDocuments(deps: {
|
|
26
|
+
tabs: DocumentTabs;
|
|
27
|
+
viewState: ViewStateDeps;
|
|
28
|
+
library: LibraryDeps;
|
|
29
|
+
blockDrafts?: import("@rightkit/document-core/app/blockDrafts").BlockDraftRegistry;
|
|
30
|
+
}): {
|
|
31
|
+
ensureHtmlPage: (entryPath: string, pagePath: string) => Promise<void>;
|
|
32
|
+
setHtmlPageEdited: (entryPath: string, pagePath: string, edited: string) => void;
|
|
33
|
+
setHtmlActive: (entryPath: string, pagePath: string) => void;
|
|
34
|
+
discardHtmlPage: (entryPath: string, pagePath: string) => void;
|
|
35
|
+
saveHtmlPage: (entryPath: string, pagePath: string, options?: {
|
|
36
|
+
silent?: boolean;
|
|
37
|
+
}) => Promise<boolean>;
|
|
38
|
+
saveAllHtmlPages: (entryPath: string, options?: {
|
|
39
|
+
silent?: boolean;
|
|
40
|
+
}) => Promise<boolean>;
|
|
41
|
+
discardAllHtmlPages: (entryPath: string) => void;
|
|
42
|
+
onHtmlSaveShortcut: (entryPath: string) => void;
|
|
43
|
+
htmlDirtyPages: (entryPath: string) => {
|
|
44
|
+
path: string;
|
|
45
|
+
name: string;
|
|
46
|
+
isEntry: boolean;
|
|
47
|
+
}[];
|
|
48
|
+
htmlSaveCurrent: () => Promise<void>;
|
|
49
|
+
htmlSaveAll: () => Promise<void>;
|
|
50
|
+
htmlDiscardAll: () => void;
|
|
51
|
+
htmlConfirmCancel: () => void;
|
|
52
|
+
htmlConflictReload: () => Promise<void>;
|
|
53
|
+
htmlConflictKeep: () => Promise<void>;
|
|
54
|
+
reloadHtmlSubpage: (path: string) => void;
|
|
55
|
+
blockDrafts: import("@rightkit/document-core/app/blockDrafts").BlockDraftRegistry;
|
|
56
|
+
activate: (path: string) => Promise<void>;
|
|
57
|
+
open: (path: string, opts?: import("./useDocumentLoader.js").OpenDocumentOptions) => Promise<void>;
|
|
58
|
+
openLiveUrl: (input: string, opts?: {
|
|
59
|
+
background?: boolean;
|
|
60
|
+
}) => Promise<void>;
|
|
61
|
+
openRecent: (entry: import("../index.js").FileEntry) => Promise<void>;
|
|
62
|
+
onOpenDialog: () => Promise<void>;
|
|
63
|
+
newDocument: (format?: "txt" | "md" | "docx") => void;
|
|
64
|
+
duplicateAsDraft: (text: string, toastMsg?: string) => void;
|
|
65
|
+
requestClose: (path: string) => void;
|
|
66
|
+
closeAll: () => void;
|
|
67
|
+
closeMany: (paths: string[]) => void;
|
|
68
|
+
reopenLastClosed: () => void;
|
|
69
|
+
openImageSibling: (currentPath: string, targetPath: string) => Promise<void>;
|
|
70
|
+
onTxtChange: (path: string, content: string, text: string) => void;
|
|
71
|
+
onSave: (doc: LoadedDocument, options?: {
|
|
72
|
+
silent?: boolean;
|
|
73
|
+
}) => Promise<string | null>;
|
|
74
|
+
onSaveAs: (doc: LoadedDocument) => Promise<string | null>;
|
|
75
|
+
onDocxSaveAs: (doc: LoadedDocument, buffer?: ArrayBuffer) => Promise<string | null>;
|
|
76
|
+
onPrint: (doc: LoadedDocument | null) => void;
|
|
77
|
+
onDocxSave: (path: string, buffer: ArrayBuffer) => Promise<void>;
|
|
78
|
+
onDocxChange: (path: string) => void;
|
|
79
|
+
onPdfDirtyChange: (path: string, dirty: boolean) => void;
|
|
80
|
+
docxSaver: import("react").RefObject<(() => Promise<ArrayBuffer | null>) | null>;
|
|
81
|
+
docxSaversRef: import("react").RefObject<Map<string, () => Promise<ArrayBuffer | null>>>;
|
|
82
|
+
pdfSaversRef: import("react").RefObject<Map<string, import("@rightkit/document-core/documents/pdf/pdfEditor").PdfSaveFunction>>;
|
|
83
|
+
pdfSavePlansRef: import("react").RefObject<Map<string, () => Promise<import("@rightkit/document-core/documents/pdf/pdfEditModel").PdfSavePlan>>>;
|
|
84
|
+
onImageChange: (path: string) => void;
|
|
85
|
+
imageSaver: import("react").RefObject<import("@rightkit/media-ui").ImageSaveFunction | null>;
|
|
86
|
+
imageSaversRef: import("react").RefObject<Map<string, import("@rightkit/media-ui").ImageSaveFunction>>;
|
|
87
|
+
onEditImageExternal: (doc: LoadedDocument | null) => void;
|
|
88
|
+
isDirty: (doc: LoadedDocument) => boolean;
|
|
89
|
+
hasModifiedDraft: (path: string) => boolean;
|
|
90
|
+
snapshotModified: (path?: string) => Readonly<{
|
|
91
|
+
identity: import("@rightkit/document-core/app/blockDrafts").BlockDraftIdentity;
|
|
92
|
+
blockKind: string;
|
|
93
|
+
originalRevision: string | number;
|
|
94
|
+
sourceRange?: import("@rightkit/document-core/app/blockDrafts").BlockDraftSourceRange;
|
|
95
|
+
sourceChecksum?: string;
|
|
96
|
+
originalText: string;
|
|
97
|
+
currentText: string;
|
|
98
|
+
targetTag?: string;
|
|
99
|
+
selectionBookmark?: import("@rightkit/document-core/app/blockDrafts").BlockDraftSelectionBookmark;
|
|
100
|
+
status: import("@rightkit/document-core/app/blockDrafts").BlockDraftStatus;
|
|
101
|
+
reason?: string;
|
|
102
|
+
error?: string;
|
|
103
|
+
}>[];
|
|
104
|
+
snapshotAll: (path?: string) => Readonly<{
|
|
105
|
+
identity: import("@rightkit/document-core/app/blockDrafts").BlockDraftIdentity;
|
|
106
|
+
blockKind: string;
|
|
107
|
+
originalRevision: string | number;
|
|
108
|
+
sourceRange?: import("@rightkit/document-core/app/blockDrafts").BlockDraftSourceRange;
|
|
109
|
+
sourceChecksum?: string;
|
|
110
|
+
originalText: string;
|
|
111
|
+
currentText: string;
|
|
112
|
+
targetTag?: string;
|
|
113
|
+
selectionBookmark?: import("@rightkit/document-core/app/blockDrafts").BlockDraftSelectionBookmark;
|
|
114
|
+
status: import("@rightkit/document-core/app/blockDrafts").BlockDraftStatus;
|
|
115
|
+
reason?: string;
|
|
116
|
+
error?: string;
|
|
117
|
+
}>[];
|
|
118
|
+
pendingSavePaths: Set<string>;
|
|
119
|
+
titleFor: (doc: LoadedDocument) => string;
|
|
120
|
+
error: string | null;
|
|
121
|
+
openingPath: string | null;
|
|
122
|
+
restoringSession: boolean;
|
|
123
|
+
setError: Dispatch<SetStateAction<string | null>>;
|
|
124
|
+
confirmClose: string | null;
|
|
125
|
+
setConfirmClose: Dispatch<SetStateAction<string | null>>;
|
|
126
|
+
confirmCloseAll: {
|
|
127
|
+
orderedPaths: string[];
|
|
128
|
+
affectedPaths: string[];
|
|
129
|
+
} | null;
|
|
130
|
+
setConfirmCloseAll: Dispatch<SetStateAction<{
|
|
131
|
+
orderedPaths: string[];
|
|
132
|
+
affectedPaths: string[];
|
|
133
|
+
} | null>>;
|
|
134
|
+
confirmCloseAllSaveAll: () => Promise<void>;
|
|
135
|
+
confirmCloseAllDontSave: () => Promise<void>;
|
|
136
|
+
confirmCloseAllCancel: () => void;
|
|
137
|
+
confirmQuit: boolean;
|
|
138
|
+
setConfirmQuit: Dispatch<SetStateAction<boolean>>;
|
|
139
|
+
conflict: string | null;
|
|
140
|
+
setConflict: Dispatch<SetStateAction<string | null>>;
|
|
141
|
+
keepConflict: (path: string) => Promise<void>;
|
|
142
|
+
reload: (path: string, options?: {
|
|
143
|
+
force?: boolean;
|
|
144
|
+
replayDeferred?: boolean;
|
|
145
|
+
}) => void;
|
|
146
|
+
confirmSave: () => Promise<void>;
|
|
147
|
+
confirmDontSave: () => Promise<void>;
|
|
148
|
+
applyReload: (path: string) => void;
|
|
149
|
+
quitNow: () => Promise<void>;
|
|
150
|
+
quitSaveAll: () => Promise<void>;
|
|
151
|
+
quitDiscardAll: () => Promise<void>;
|
|
152
|
+
draftConfirm: {
|
|
153
|
+
documentPath: string;
|
|
154
|
+
intent: import("@rightkit/document-core/app/blockDrafts").BlockDraftIntent;
|
|
155
|
+
onResolved: () => void;
|
|
156
|
+
} | null;
|
|
157
|
+
setDraftConfirm: Dispatch<SetStateAction<{
|
|
158
|
+
documentPath: string;
|
|
159
|
+
intent: import("@rightkit/document-core/app/blockDrafts").BlockDraftIntent;
|
|
160
|
+
onResolved: () => void;
|
|
161
|
+
} | null>>;
|
|
162
|
+
confirmDraftDone: () => Promise<void>;
|
|
163
|
+
confirmDraftDiscard: () => Promise<void>;
|
|
164
|
+
confirmDraftCancel: () => void;
|
|
165
|
+
requestDraftAwareViewChange: (path: string, proceed: () => void) => void;
|
|
166
|
+
htmlConfirm: HtmlConfirmState;
|
|
167
|
+
htmlConflict: HtmlConflictState;
|
|
168
|
+
trackMdxGrant: (entryPath: string, grantedPath: string) => void;
|
|
169
|
+
};
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState, } from "react";
|
|
2
|
+
import { isUntitled, } from "@rightkit/document-core/documents/types";
|
|
3
|
+
import { isWebTabKey } from "@rightkit/document-core/documents/web/webUrl";
|
|
4
|
+
import { readDocument, revokePath, } from "@rightkit/document-core/state/tauriBridge";
|
|
5
|
+
import { clearFileDraft, flushDraft, } from "./documentDrafts.js";
|
|
6
|
+
import { errorMessage } from "@rightkit/document-core/state/errors";
|
|
7
|
+
import { useDocumentRuntimeEffects } from "./useDocumentRuntimeEffects.js";
|
|
8
|
+
import { useFormatDirtyState } from "./useFormatDirtyState.js";
|
|
9
|
+
import { useHtmlSession } from "./useHtmlSession.js";
|
|
10
|
+
import { useDocumentLoader } from "./useDocumentLoader.js";
|
|
11
|
+
import { useDocumentSaver } from "./useDocumentSaver.js";
|
|
12
|
+
import { useDocumentWatcher, pickNextActive } from "./useDocumentWatcher.js";
|
|
13
|
+
import { useSettings } from "@rightkit/document-core/settings/settings";
|
|
14
|
+
import { createBlockDraftRegistry } from "@rightkit/document-core/app/blockDrafts";
|
|
15
|
+
import { useAutoSave } from "./useAutoSave.js";
|
|
16
|
+
import { useCloseAll } from "./useCloseAll.js";
|
|
17
|
+
import { useDraftConfirmGate } from "./useDraftConfirmGate.js";
|
|
18
|
+
import { usePendingSavePaths } from "./usePendingSavePaths.js";
|
|
19
|
+
import { useSetupRecovery } from "./useSetupRecovery.js";
|
|
20
|
+
import { useDocumentDirty } from "./useDocumentDirty.js";
|
|
21
|
+
import { useDocumentCreation } from "./useDocumentCreation.js";
|
|
22
|
+
import { useDocumentOutputActions } from "./useDocumentOutputActions.js";
|
|
23
|
+
const EMPTY_PENDING_SAVE_PATHS = new Set();
|
|
24
|
+
// Re-exported so the existing unit test (useDocuments.pickNextActive.test.ts) keeps importing this
|
|
25
|
+
// module without a signature change; the implementation now lives in useDocumentWatcher.ts.
|
|
26
|
+
export { pickNextActive };
|
|
27
|
+
/**
|
|
28
|
+
* The document lifecycle orchestrator: composes useDocumentLoader (open/read), useDocumentSaver
|
|
29
|
+
* (save/save-as), and useDocumentWatcher (close/teardown/reopen + external-change reload) around the
|
|
30
|
+
* shared `tabs` state and view-state/library setters (passed in to avoid a hook-ordering cycle).
|
|
31
|
+
* Bodies are unchanged from when everything lived in one 862-line hook — this file now just wires the
|
|
32
|
+
* pieces together and owns the state/refs genuinely shared across all three (fingerprints, the
|
|
33
|
+
* open-docs/activation-order mirrors, and the dialog state the HTML session drives).
|
|
34
|
+
*/
|
|
35
|
+
export function useDocuments(deps) {
|
|
36
|
+
const [internalDrafts] = useState(() => createBlockDraftRegistry());
|
|
37
|
+
const blockDrafts = deps.blockDrafts ?? internalDrafts;
|
|
38
|
+
const { settings } = useSettings();
|
|
39
|
+
const { openDocs, setOpenDocs, activePath, setActivePath, editsRef, writeEdits, writeEditsLive, docxDirtyRef, setDocxDirty, pdfDirtyRef, setPdfDirty, imageDirtyRef, setImageDirty, htmlPagesRef, writeHtmlPages, htmlActivePage, setHtmlActivePage, mdxGrantsRef, trackMdxGrant, } = deps.tabs;
|
|
40
|
+
const { setViews, viewsRef, viewMetaRef } = deps.viewState;
|
|
41
|
+
const { refreshLibrary, syncPinned } = deps.library;
|
|
42
|
+
const [error, setError] = useState(null);
|
|
43
|
+
const [openingPath, setOpeningPath] = useState(null);
|
|
44
|
+
// True while the launch effect's session restore is in flight (file-backed tabs loading,
|
|
45
|
+
// active tab being chosen). App.tsx renders a small "Restoring session…" indicator in the
|
|
46
|
+
// active-pane slot while true so the user sees feedback instead of a blank pane that reads
|
|
47
|
+
// as "the app isn't loaded". Starts false so the first render shows the EmptyState (or the
|
|
48
|
+
// active doc) — the launch effect flips it true on entry, false in `finally` on exit.
|
|
49
|
+
const [restoringSession, setRestoringSession] = useState(false);
|
|
50
|
+
const untitledSeq = useRef(1);
|
|
51
|
+
const hydrated = useRef(false); // becomes true once the launch restore has read the saved session
|
|
52
|
+
const [confirmClose, setConfirmClose] = useState(null);
|
|
53
|
+
const [conflict, setConflict] = useState(null); // file changed on disk while dirty
|
|
54
|
+
// HTML session dialogs: the page-aware close/save chooser, and a sub-page on-disk conflict. State
|
|
55
|
+
// lives here (not in useHtmlSession) because requestClose opens the chooser before that hook runs.
|
|
56
|
+
const [htmlConfirm, setHtmlConfirm] = useState(null);
|
|
57
|
+
const [htmlConflict, setHtmlConflict] = useState(null);
|
|
58
|
+
// Last-seen on-disk fingerprint per open file, captured at read/save time and compared on
|
|
59
|
+
// activation to catch background-tab edits the active-file-only watcher can't see.
|
|
60
|
+
const fingerprints = useRef(new Map());
|
|
61
|
+
const tabSeq = useRef(1);
|
|
62
|
+
const openDocsRef = useRef(openDocs);
|
|
63
|
+
const activePathRef = useRef(activePath);
|
|
64
|
+
// queueAutoSave must exist before useAutoSave's deps (docxSaver/onSave/htmlSession) do — stable
|
|
65
|
+
// forwarder into the scheduler slot useAutoSave populates each render.
|
|
66
|
+
const autoSaveSchedulerRef = useRef(() => { });
|
|
67
|
+
const queueAutoSave = useCallback((path) => autoSaveSchedulerRef.current(path), []);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
openDocsRef.current = openDocs;
|
|
70
|
+
}, [openDocs]);
|
|
71
|
+
activePathRef.current = activePath;
|
|
72
|
+
// MRU activation history (most-recent LAST). Closing the active tab focuses the most-recently-used
|
|
73
|
+
// still-open tab — VS Code's `focusRecentEditorAfterClose` default — not nothing. `doClose` falls
|
|
74
|
+
// back to the spatial neighbour if there's no usable history (shouldn't happen once a tab has ever
|
|
75
|
+
// been active). Stale entries are harmless: `pickNextActive` filters against the remaining set.
|
|
76
|
+
const activationOrderRef = useRef([]);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (!activePath)
|
|
79
|
+
return;
|
|
80
|
+
const order = activationOrderRef.current;
|
|
81
|
+
const at = order.indexOf(activePath);
|
|
82
|
+
if (at !== -1)
|
|
83
|
+
order.splice(at, 1);
|
|
84
|
+
order.push(activePath);
|
|
85
|
+
}, [activePath]);
|
|
86
|
+
const withTabKey = useCallback((doc, existingKey) => ({
|
|
87
|
+
...doc,
|
|
88
|
+
tabKey: existingKey ?? doc.tabKey ?? `tab:${tabSeq.current++}`,
|
|
89
|
+
}), []);
|
|
90
|
+
const releaseReplacedBackingPath = useCallback((oldPath, newPath) => {
|
|
91
|
+
if (oldPath === newPath || isUntitled(oldPath) || isWebTabKey(oldPath))
|
|
92
|
+
return;
|
|
93
|
+
fingerprints.current.delete(oldPath);
|
|
94
|
+
clearFileDraft(oldPath);
|
|
95
|
+
void revokePath(oldPath);
|
|
96
|
+
}, []);
|
|
97
|
+
// markSelfSaved/refreshFingerprint are owned by useDocumentSaver, constructed below — but
|
|
98
|
+
// useFormatDirtyState (docx/image dirty-set + onDocxSave/writeImagePayload) needs them and must be
|
|
99
|
+
// constructed BEFORE useDocumentSaver (the saver takes writeImagePayload as a dep). Break the cycle
|
|
100
|
+
// with a stable ref indirection: the ref is populated once the saver exists, and these thin
|
|
101
|
+
// forwarding callbacks never change identity, so downstream memoization is unaffected.
|
|
102
|
+
const saverHandlesRef = useRef({
|
|
103
|
+
markSelfSaved: () => { },
|
|
104
|
+
refreshFingerprint: () => { },
|
|
105
|
+
});
|
|
106
|
+
const markSelfSavedForward = useCallback((path) => saverHandlesRef.current.markSelfSaved(path), []);
|
|
107
|
+
const refreshFingerprintForward = useCallback((path) => saverHandlesRef.current.refreshFingerprint(path), []);
|
|
108
|
+
const { docxSaver, imageSaver, docxSaversRef, pdfSaversRef, pdfSavePlansRef, imageSaversRef, onDocxSave: persistDocx, onDocxChange, onPdfDirtyChange, onImageChange, clearImageDirty, restoreImageDirty, writeImagePayload, } = useFormatDirtyState({
|
|
109
|
+
setError,
|
|
110
|
+
setDocxDirty,
|
|
111
|
+
setPdfDirty,
|
|
112
|
+
setImageDirty,
|
|
113
|
+
markSelfSaved: markSelfSavedForward,
|
|
114
|
+
refreshFingerprint: refreshFingerprintForward,
|
|
115
|
+
onDirty: queueAutoSave,
|
|
116
|
+
});
|
|
117
|
+
const { hasModifiedDraft, snapshotModified, isDirty, titleFor } = useDocumentDirty({
|
|
118
|
+
blockDrafts,
|
|
119
|
+
pdfDirtyRef,
|
|
120
|
+
docxDirtyRef,
|
|
121
|
+
imageDirtyRef,
|
|
122
|
+
editsRef,
|
|
123
|
+
htmlPagesRef,
|
|
124
|
+
});
|
|
125
|
+
// Setup-replacement recovery (snapshot before window destroy + rehydrate on next launch) —
|
|
126
|
+
// extracted to useSetupRecovery; the pure (de)serialization stays in setupRecovery.ts.
|
|
127
|
+
const { prepareSetupRecovery, restoreSetupRecovery } = useSetupRecovery({
|
|
128
|
+
blockDrafts,
|
|
129
|
+
setError,
|
|
130
|
+
openDocsRef,
|
|
131
|
+
activePathRef,
|
|
132
|
+
viewsRef,
|
|
133
|
+
isDirty,
|
|
134
|
+
editsRef,
|
|
135
|
+
htmlPagesRef,
|
|
136
|
+
docxSaversRef,
|
|
137
|
+
imageSaversRef,
|
|
138
|
+
setOpenDocs,
|
|
139
|
+
writeEdits,
|
|
140
|
+
writeHtmlPages,
|
|
141
|
+
setViews,
|
|
142
|
+
setDocxDirty,
|
|
143
|
+
restoreImageDirty,
|
|
144
|
+
fingerprints,
|
|
145
|
+
withTabKey,
|
|
146
|
+
});
|
|
147
|
+
const loader = useDocumentLoader({
|
|
148
|
+
openDocs,
|
|
149
|
+
setOpenDocs,
|
|
150
|
+
setViews,
|
|
151
|
+
viewsRef,
|
|
152
|
+
viewMetaRef,
|
|
153
|
+
writeEdits,
|
|
154
|
+
setError,
|
|
155
|
+
setOpeningPath,
|
|
156
|
+
setActivePath,
|
|
157
|
+
fingerprints,
|
|
158
|
+
refreshLibrary,
|
|
159
|
+
syncPinned,
|
|
160
|
+
isDirty,
|
|
161
|
+
clearImageDirty,
|
|
162
|
+
withTabKey,
|
|
163
|
+
});
|
|
164
|
+
const { activate, open, openLiveUrl, openRecent, onOpenDialog, openImageSibling } = loader;
|
|
165
|
+
const saver = useDocumentSaver({
|
|
166
|
+
editsRef,
|
|
167
|
+
writeEdits,
|
|
168
|
+
setDocxDirty,
|
|
169
|
+
setOpenDocs,
|
|
170
|
+
setActivePath,
|
|
171
|
+
setViews,
|
|
172
|
+
setError,
|
|
173
|
+
setConflict,
|
|
174
|
+
fingerprints,
|
|
175
|
+
refreshLibrary,
|
|
176
|
+
imageSaver,
|
|
177
|
+
imageSaversRef,
|
|
178
|
+
docxSaver,
|
|
179
|
+
docxSaversRef,
|
|
180
|
+
pdfSaversRef,
|
|
181
|
+
pdfSavePlansRef,
|
|
182
|
+
setPdfDirty,
|
|
183
|
+
pdfDirtyRef,
|
|
184
|
+
clearImageDirty,
|
|
185
|
+
writeImagePayload,
|
|
186
|
+
releaseReplacedBackingPath,
|
|
187
|
+
withTabKey,
|
|
188
|
+
blockDrafts,
|
|
189
|
+
});
|
|
190
|
+
const { onSave, onSaveAs, onDocxSaveAs, markSelfSaved, refreshFingerprint, selfSaved, pendingSavePaths: saverPendingSavePaths = EMPTY_PENDING_SAVE_PATHS, pendingSavePathsRef: saverPendingSavePathsRef, } = saver;
|
|
191
|
+
// In-flight save paths across all three save surfaces (saver's own set + tracked docx writes +
|
|
192
|
+
// per-page HTML session writes) — extracted to usePendingSavePaths.
|
|
193
|
+
const { onDocxSave, onHtmlSaveActivity, pendingSavePaths, pendingSavePathsRef: formatPendingSavePathsRef, } = usePendingSavePaths({
|
|
194
|
+
persistDocx,
|
|
195
|
+
saverPendingSavePaths,
|
|
196
|
+
});
|
|
197
|
+
saverHandlesRef.current.markSelfSaved = markSelfSaved;
|
|
198
|
+
saverHandlesRef.current.refreshFingerprint = refreshFingerprint;
|
|
199
|
+
// T2-1 data-loss guard, explicit save path: flush any pending debounced draft write for this doc
|
|
200
|
+
// before saving. Save itself reads the live editsRef (always current, unaffected by the draft
|
|
201
|
+
// debounce), so this isn't required for save correctness — it just guarantees the recovery draft
|
|
202
|
+
// in localStorage can't hold text older than what's about to hit disk if something inspects it
|
|
203
|
+
// mid-save. clearDraft/clearFileDraft (called after a successful save) already cancel the pending
|
|
204
|
+
// write outright, so this and that together fully close the window.
|
|
205
|
+
const onSaveFlushed = useCallback((doc, options) => {
|
|
206
|
+
flushDraft(doc.path);
|
|
207
|
+
return onSave(doc, options);
|
|
208
|
+
}, [onSave]);
|
|
209
|
+
const onSaveAsFlushed = useCallback((doc) => {
|
|
210
|
+
flushDraft(doc.path);
|
|
211
|
+
return onSaveAs(doc);
|
|
212
|
+
}, [onSaveAs]);
|
|
213
|
+
const { newDocument, duplicateAsDraft, onTxtChange } = useDocumentCreation({
|
|
214
|
+
untitledSeq,
|
|
215
|
+
withTabKey,
|
|
216
|
+
setOpenDocs,
|
|
217
|
+
setActivePath,
|
|
218
|
+
setViews,
|
|
219
|
+
writeEdits,
|
|
220
|
+
writeEditsLive,
|
|
221
|
+
queueAutoSave,
|
|
222
|
+
});
|
|
223
|
+
// doClose (from useDocumentWatcher, constructed below) and reloadHtmlSubpage (from useHtmlSession,
|
|
224
|
+
// constructed here) are mutually dependent, exactly as in the original single-hook version — broken
|
|
225
|
+
// with the same stable-ref-forwarding pattern used above.
|
|
226
|
+
const doCloseRef = useRef(() => { });
|
|
227
|
+
const doCloseForward = useCallback((path) => doCloseRef.current(path), []);
|
|
228
|
+
// ── HTML site sessions ──────────────────────────────────────────────────────────────────────
|
|
229
|
+
// The navigated SUB-page buffers, their save/discard/dirty model, the page-aware close chooser, the
|
|
230
|
+
// sub-page conflict flow, and sub-page reload reconciliation all live in useHtmlSession. The ENTRY
|
|
231
|
+
// page still uses the shared text path above (edits + onSave). Dialog state stays here (above) so
|
|
232
|
+
// requestClose can open the chooser before this hook is constructed.
|
|
233
|
+
const htmlSession = useHtmlSession({
|
|
234
|
+
openDocs,
|
|
235
|
+
editsRef,
|
|
236
|
+
writeEdits,
|
|
237
|
+
htmlPagesRef,
|
|
238
|
+
writeHtmlPages,
|
|
239
|
+
htmlActivePage,
|
|
240
|
+
setHtmlActivePage,
|
|
241
|
+
htmlConfirm,
|
|
242
|
+
setHtmlConfirm,
|
|
243
|
+
htmlConflict,
|
|
244
|
+
setHtmlConflict,
|
|
245
|
+
onSave,
|
|
246
|
+
doClose: doCloseForward,
|
|
247
|
+
markSelfSaved,
|
|
248
|
+
setError,
|
|
249
|
+
onDirty: queueAutoSave,
|
|
250
|
+
onSaveActivity: onHtmlSaveActivity,
|
|
251
|
+
blockDrafts,
|
|
252
|
+
});
|
|
253
|
+
const { reloadHtmlSubpage } = htmlSession;
|
|
254
|
+
// Idle-delay autosave for file-backed tabs + the T2-1 draft-flush guards on unload/hide —
|
|
255
|
+
// extracted to useAutoSave. `autoSaveSchedulerRef` stays here: `queueAutoSave` (above, consumed by
|
|
256
|
+
// useFormatDirtyState/useHtmlSession/onTxtChange) must exist before this hook's deps do.
|
|
257
|
+
useAutoSave({
|
|
258
|
+
autoSave: settings.autoSave,
|
|
259
|
+
openDocs,
|
|
260
|
+
openDocsRef,
|
|
261
|
+
activePath,
|
|
262
|
+
activePathRef,
|
|
263
|
+
isDirty,
|
|
264
|
+
docxSaver,
|
|
265
|
+
onDocxSave,
|
|
266
|
+
onSave,
|
|
267
|
+
saveAllHtmlPages: htmlSession.saveAllHtmlPages,
|
|
268
|
+
autoSaveSchedulerRef,
|
|
269
|
+
});
|
|
270
|
+
const watcher = useDocumentWatcher({
|
|
271
|
+
openDocs,
|
|
272
|
+
openDocsRef,
|
|
273
|
+
activationOrderRef,
|
|
274
|
+
setOpenDocs,
|
|
275
|
+
setActivePath,
|
|
276
|
+
activePath,
|
|
277
|
+
writeEdits,
|
|
278
|
+
setDocxDirty,
|
|
279
|
+
setPdfDirty,
|
|
280
|
+
htmlPagesRef,
|
|
281
|
+
writeHtmlPages,
|
|
282
|
+
setHtmlActivePage,
|
|
283
|
+
mdxGrantsRef,
|
|
284
|
+
clearImageDirty,
|
|
285
|
+
isDirty,
|
|
286
|
+
openLiveUrl,
|
|
287
|
+
activate,
|
|
288
|
+
open,
|
|
289
|
+
fingerprints,
|
|
290
|
+
selfSaved,
|
|
291
|
+
pendingSavePaths,
|
|
292
|
+
reloadHtmlSubpage,
|
|
293
|
+
setHtmlConfirm,
|
|
294
|
+
setConfirmClose,
|
|
295
|
+
confirmClose,
|
|
296
|
+
setConflict,
|
|
297
|
+
onSave,
|
|
298
|
+
onDocxSave,
|
|
299
|
+
docxSaver,
|
|
300
|
+
docxSaversRef,
|
|
301
|
+
onDocxSaveAs,
|
|
302
|
+
withTabKey,
|
|
303
|
+
blockDrafts,
|
|
304
|
+
dropViewState: deps.viewState.dropViewState,
|
|
305
|
+
synchronousPendingSavePathsRef: saverPendingSavePathsRef,
|
|
306
|
+
synchronousPendingSavePathsRefs: [saverPendingSavePathsRef, formatPendingSavePathsRef],
|
|
307
|
+
});
|
|
308
|
+
const { doClose, reopenLastClosed, requestClose, confirmSave, confirmDontSave, applyReload, reload, teardownDoc, } = watcher;
|
|
309
|
+
doCloseRef.current = doClose;
|
|
310
|
+
// Keeping local edits after an external change must refresh the backend's expected source hash.
|
|
311
|
+
// The next save then overwrites only the exact bytes just acknowledged, while the backend guard
|
|
312
|
+
// still catches a second external write that races that save.
|
|
313
|
+
const keepConflict = useCallback(async (path) => {
|
|
314
|
+
const doc = openDocs.find((candidate) => candidate.path === path);
|
|
315
|
+
if (doc && !["txt", "md", "mdx", "html"].includes(doc.format)) {
|
|
316
|
+
// Binary/PDF saves have no source hash guard; preserve their existing Keep behavior.
|
|
317
|
+
setConflict(null);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
const loaded = await readDocument(path);
|
|
322
|
+
if (!loaded.sourceSha256) {
|
|
323
|
+
setError("Couldn't refresh file identity before overwrite.");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (loaded.fingerprint)
|
|
327
|
+
fingerprints.current.set(path, loaded.fingerprint);
|
|
328
|
+
setOpenDocs((prev) => prev.map((doc) => doc.path === path
|
|
329
|
+
? {
|
|
330
|
+
...doc,
|
|
331
|
+
sourceSha256: loaded.sourceSha256,
|
|
332
|
+
fingerprint: loaded.fingerprint ?? doc.fingerprint,
|
|
333
|
+
}
|
|
334
|
+
: doc));
|
|
335
|
+
setConflict(null);
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
setError(errorMessage(error));
|
|
339
|
+
}
|
|
340
|
+
}, [openDocs, setOpenDocs]);
|
|
341
|
+
// Bulk Close All + the Save-All/Discard-All quit flow — extracted to useCloseAll. The hook also
|
|
342
|
+
// owns the confirmQuit/confirmCloseAll dialog state (only consumed after requestClose exists, so
|
|
343
|
+
// unlike the other dialog state it doesn't need to stay at the top of this hook).
|
|
344
|
+
const { confirmQuit, setConfirmQuit, confirmCloseAll, setConfirmCloseAll, closeAll, closeMany, confirmCloseAllSaveAll, confirmCloseAllDontSave, confirmCloseAllCancel, quitNow, quitSaveAll, quitDiscardAll, } = useCloseAll({
|
|
345
|
+
openDocsRef,
|
|
346
|
+
isDirty,
|
|
347
|
+
setOpenDocs,
|
|
348
|
+
setActivePath,
|
|
349
|
+
teardownDoc,
|
|
350
|
+
blockDrafts,
|
|
351
|
+
htmlSession,
|
|
352
|
+
onSaveFlushed,
|
|
353
|
+
docxSaver,
|
|
354
|
+
docxSaversRef,
|
|
355
|
+
onDocxSave,
|
|
356
|
+
onDocxSaveAs,
|
|
357
|
+
});
|
|
358
|
+
const { onEditImageExternal, onPrint } = useDocumentOutputActions(setError);
|
|
359
|
+
useDocumentRuntimeEffects({
|
|
360
|
+
openDocs,
|
|
361
|
+
activePath,
|
|
362
|
+
hydrated,
|
|
363
|
+
untitledSeq,
|
|
364
|
+
refreshLibrary,
|
|
365
|
+
setOpenDocs,
|
|
366
|
+
writeEdits,
|
|
367
|
+
setViews,
|
|
368
|
+
activate,
|
|
369
|
+
open,
|
|
370
|
+
reload,
|
|
371
|
+
isDirty,
|
|
372
|
+
setConfirmQuit,
|
|
373
|
+
prepareSetupRecovery,
|
|
374
|
+
restoreSetupRecovery,
|
|
375
|
+
restoreSession: settings.restoreSession,
|
|
376
|
+
setRestoringSession,
|
|
377
|
+
blockDrafts,
|
|
378
|
+
});
|
|
379
|
+
// Draft-confirm dialog (view changes with a modified draft): Done commits, Discard drops,
|
|
380
|
+
// Cancel stays on the current view with the editor open — extracted to useDraftConfirmGate.
|
|
381
|
+
const { draftConfirm, setDraftConfirm, confirmDraftDone, confirmDraftDiscard, confirmDraftCancel, requestDraftAwareViewChange, } = useDraftConfirmGate({ blockDrafts });
|
|
382
|
+
return {
|
|
383
|
+
blockDrafts,
|
|
384
|
+
activate,
|
|
385
|
+
open,
|
|
386
|
+
openLiveUrl,
|
|
387
|
+
openRecent,
|
|
388
|
+
onOpenDialog,
|
|
389
|
+
newDocument,
|
|
390
|
+
duplicateAsDraft,
|
|
391
|
+
requestClose,
|
|
392
|
+
closeAll,
|
|
393
|
+
closeMany,
|
|
394
|
+
reopenLastClosed,
|
|
395
|
+
openImageSibling,
|
|
396
|
+
onTxtChange,
|
|
397
|
+
onSave: onSaveFlushed,
|
|
398
|
+
onSaveAs: onSaveAsFlushed,
|
|
399
|
+
onDocxSaveAs,
|
|
400
|
+
onPrint,
|
|
401
|
+
onDocxSave,
|
|
402
|
+
onDocxChange,
|
|
403
|
+
onPdfDirtyChange,
|
|
404
|
+
docxSaver,
|
|
405
|
+
docxSaversRef,
|
|
406
|
+
pdfSaversRef,
|
|
407
|
+
pdfSavePlansRef,
|
|
408
|
+
onImageChange,
|
|
409
|
+
imageSaver,
|
|
410
|
+
imageSaversRef,
|
|
411
|
+
onEditImageExternal,
|
|
412
|
+
isDirty,
|
|
413
|
+
hasModifiedDraft,
|
|
414
|
+
snapshotModified,
|
|
415
|
+
snapshotAll: (path) => blockDrafts.snapshotAll(path),
|
|
416
|
+
pendingSavePaths,
|
|
417
|
+
titleFor,
|
|
418
|
+
error,
|
|
419
|
+
openingPath,
|
|
420
|
+
restoringSession,
|
|
421
|
+
setError,
|
|
422
|
+
confirmClose,
|
|
423
|
+
setConfirmClose,
|
|
424
|
+
confirmCloseAll,
|
|
425
|
+
setConfirmCloseAll,
|
|
426
|
+
confirmCloseAllSaveAll,
|
|
427
|
+
confirmCloseAllDontSave,
|
|
428
|
+
confirmCloseAllCancel,
|
|
429
|
+
confirmQuit,
|
|
430
|
+
setConfirmQuit,
|
|
431
|
+
conflict,
|
|
432
|
+
setConflict,
|
|
433
|
+
keepConflict,
|
|
434
|
+
reload,
|
|
435
|
+
confirmSave,
|
|
436
|
+
confirmDontSave,
|
|
437
|
+
applyReload,
|
|
438
|
+
quitNow,
|
|
439
|
+
quitSaveAll,
|
|
440
|
+
quitDiscardAll,
|
|
441
|
+
draftConfirm,
|
|
442
|
+
setDraftConfirm,
|
|
443
|
+
confirmDraftDone,
|
|
444
|
+
confirmDraftDiscard,
|
|
445
|
+
confirmDraftCancel,
|
|
446
|
+
requestDraftAwareViewChange,
|
|
447
|
+
// HTML site sessions — dialog state owned here; behavior from useHtmlSession.
|
|
448
|
+
htmlConfirm,
|
|
449
|
+
htmlConflict,
|
|
450
|
+
...htmlSession,
|
|
451
|
+
// MDX component-import grant tracking — reported by the resolver/preview frame, revoked in
|
|
452
|
+
// teardownDoc above.
|
|
453
|
+
trackMdxGrant,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { BlockDraftIntent, BlockDraftRegistry } from "@rightkit/document-core/app/blockDrafts";
|
|
2
|
+
interface DraftConfirmGateDeps {
|
|
3
|
+
blockDrafts: BlockDraftRegistry;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The draft-confirm chooser state + its gate. `requestDraftAwareViewChange` wraps a view change so
|
|
7
|
+
* a modified block draft first opens the Done/Discard/Cancel chooser (Done commits, Discard drops,
|
|
8
|
+
* Cancel stays on the current view with the editor open); a draft-free document proceeds
|
|
9
|
+
* immediately. Extracted verbatim from useDocuments; bodies are unchanged.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useDraftConfirmGate({ blockDrafts }: DraftConfirmGateDeps): {
|
|
12
|
+
draftConfirm: {
|
|
13
|
+
documentPath: string;
|
|
14
|
+
intent: BlockDraftIntent;
|
|
15
|
+
onResolved: () => void;
|
|
16
|
+
} | null;
|
|
17
|
+
setDraftConfirm: import("react").Dispatch<import("react").SetStateAction<{
|
|
18
|
+
documentPath: string;
|
|
19
|
+
intent: BlockDraftIntent;
|
|
20
|
+
onResolved: () => void;
|
|
21
|
+
} | null>>;
|
|
22
|
+
confirmDraftDone: () => Promise<void>;
|
|
23
|
+
confirmDraftDiscard: () => Promise<void>;
|
|
24
|
+
confirmDraftCancel: () => void;
|
|
25
|
+
requestDraftAwareViewChange: (path: string, proceed: () => void) => void;
|
|
26
|
+
};
|
|
27
|
+
export {};
|