@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.
- package/CHANGELOG.md +5 -0
- package/LICENSE-APACHE +201 -0
- package/LICENSE-MIT +21 -0
- package/README.md +51 -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,584 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { scrollPosIntoView } from "@rightkit/document-core/documents/txt/cmScroll";
|
|
4
|
+
import { previewBootHtml } from "@rightkit/html-editor/documents/html/htmlInline";
|
|
5
|
+
import { useSiteRootGrant } from "@rightkit/html-editor/documents/html/useSiteRootGrant";
|
|
6
|
+
import { logEvent } from "@rightkit/document-core/state/diagnostics";
|
|
7
|
+
import { toast } from "@rightkit/platform-ui/headless";
|
|
8
|
+
import { useSettings } from "@rightkit/document-core/settings/settings";
|
|
9
|
+
import { viewportWidthPx } from "@rightkit/document-core/documents/previewViewport";
|
|
10
|
+
import { useHtmlNavigation } from "@rightkit/html-editor/documents/html/useHtmlNavigation";
|
|
11
|
+
import { useHtmlPreviewFind } from "@rightkit/html-editor/documents/html/useHtmlPreviewFind";
|
|
12
|
+
import { useHtmlSubPages } from "@rightkit/html-editor/documents/html/useHtmlSubPages";
|
|
13
|
+
import { useHtmlPreviewLifecycle } from "@rightkit/html-editor/documents/html/useHtmlPreviewLifecycle";
|
|
14
|
+
import { useHtmlLiveCssBridge } from "@rightkit/html-editor/documents/html/useHtmlLiveCssBridge";
|
|
15
|
+
import { useHtmlColdState } from "@rightkit/html-editor/documents/html/useHtmlColdState";
|
|
16
|
+
import { useHtmlBlockUndoRedo } from "@rightkit/html-editor/documents/html/useHtmlBlockUndoRedo";
|
|
17
|
+
import { useHtmlReload } from "@rightkit/html-editor/documents/html/useHtmlReload";
|
|
18
|
+
import { useHtmlInframeTarget } from "@rightkit/html-editor/documents/html/useHtmlInframeTarget";
|
|
19
|
+
import { resolveSafeBlockTarget } from "@rightkit/html-editor/documents/html/sourceMap";
|
|
20
|
+
import { useHtmlDocumentBridge } from "@rightkit/html-editor/documents/html/HtmlDocumentBridge";
|
|
21
|
+
import { HtmlDocumentLayout } from "./HtmlDocumentLayout.js";
|
|
22
|
+
import { useCloseFindOnSurfaceChange } from "@rightkit/document-core/app/useCloseFindOnSurfaceChange";
|
|
23
|
+
import { trackHtmlDocumentMount, trackHtmlUnmount } from "@rightkit/html-editor/documents/html/htmlResourceLifecycle";
|
|
24
|
+
import { useOptionalBlockDrafts } from "@rightkit/document-core/app/BlockDraftContext";
|
|
25
|
+
import { createBlockDraftRegistry } from "@rightkit/document-core/app/blockDrafts";
|
|
26
|
+
import { useHtmlPageBuffer } from "@rightkit/html-editor/documents/html/useHtmlPageBuffer";
|
|
27
|
+
import { useHtmlSafeBlockEntry } from "@rightkit/html-editor/documents/html/useHtmlSafeBlockEntry";
|
|
28
|
+
import { useHtmlBlockOps, useRecordBlockCommit } from "@rightkit/html-editor/documents/html/useHtmlBlockOps";
|
|
29
|
+
import { useHtmlSourceDrawerResize } from "@rightkit/html-editor/documents/html/useHtmlSourceDrawerResize";
|
|
30
|
+
import { useHtmlAutoViewport } from "@rightkit/html-editor/documents/html/useHtmlAutoViewport";
|
|
31
|
+
import { useHtmlPreviewControls } from "@rightkit/html-editor/documents/html/useHtmlPreviewControls";
|
|
32
|
+
import { useHtmlInspect } from "@rightkit/html-editor/documents/html/useHtmlInspect";
|
|
33
|
+
import { useHtmlBlockDrafts } from "@rightkit/html-editor/documents/html/useHtmlBlockDrafts";
|
|
34
|
+
import { useHtmlRichEditState } from "@rightkit/html-editor/documents/html/useHtmlRichEditState";
|
|
35
|
+
import { useHtmlSrcDocLifecycle } from "@rightkit/html-editor/documents/html/useHtmlSrcDocLifecycle";
|
|
36
|
+
import { initialSourceDrawerOpen } from "@rightkit/html-editor/documents/html/htmlDocumentShared";
|
|
37
|
+
/**
|
|
38
|
+
* One tab = one local-site session. The tab is identified by `entryPath`; `activePath` is the page
|
|
39
|
+
* currently shown and may roam to sub-pages as the user navigates (always under the entry folder —
|
|
40
|
+
* Rust enforces containment). Switching modes/opening the source drawer keeps this component mounted,
|
|
41
|
+
* so the nav stack and every page's edit buffer survive.
|
|
42
|
+
*
|
|
43
|
+
* This file is the mode-router shell: it owns the preview-build lifecycle (applied snapshot → srcDoc),
|
|
44
|
+
* the source drawer state, and layout. Behavior lives in focused hooks (useHtmlPreviewControls,
|
|
45
|
+
* useHtmlInspect, useHtmlBlockDrafts, useHtmlAutoViewport, plus the existing navigation/bridge/block
|
|
46
|
+
* hooks); rendering is delegated to HtmlDocumentView (preview surface), HtmlDocumentSource (source
|
|
47
|
+
* drawer), and HtmlDocumentEdit (inspect context menu).
|
|
48
|
+
*/
|
|
49
|
+
export function HtmlDocument({ entryPath, view, text, onChange, registerSearchProvider, findBar, findMode, onRequestFind, onRequestReplace, onCloseFind, onOpenPath, onChangeView, readOnly = false, active = true, pageBuffers, dirtyPagePaths, onEnsurePage, onPageChange, onSetActivePage, onSavePage, onDiscardPage, onReloadFromDisk, initialPreviewScrollY, onPreviewScroll, sourceViewStateRef: externalSourceViewStateRef, }) {
|
|
50
|
+
const optionalDrafts = useOptionalBlockDrafts();
|
|
51
|
+
const fallbackDrafts = useRef(createBlockDraftRegistry()).current;
|
|
52
|
+
const blockDrafts = optionalDrafts ?? fallbackDrafts;
|
|
53
|
+
const mountedRef = useRef(true);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
mountedRef.current = true;
|
|
56
|
+
trackHtmlDocumentMount(entryPath);
|
|
57
|
+
return () => {
|
|
58
|
+
mountedRef.current = false;
|
|
59
|
+
trackHtmlUnmount();
|
|
60
|
+
};
|
|
61
|
+
}, [entryPath]);
|
|
62
|
+
const { settings } = useSettings();
|
|
63
|
+
// Changes when the palette changes; theme CSS is hot-applied into the iframe without rebuilding it.
|
|
64
|
+
const themeKey = `${settings.themeId}:${settings.primaryAccentId ?? ""}:${settings.customPrimary ?? ""}`;
|
|
65
|
+
const sessionId = useMemo(() => typeof crypto !== "undefined" && "randomUUID" in crypto
|
|
66
|
+
? crypto.randomUUID()
|
|
67
|
+
: `${Date.now()}-${Math.random().toString(36).slice(2)}`, []);
|
|
68
|
+
const iframeRef = useRef(null);
|
|
69
|
+
const safeIframeRef = useRef(null);
|
|
70
|
+
// The element under the last right-click in the interactive iframe (recorded by the bridge without
|
|
71
|
+
// suppressing the native menu). Used when the user picks the grafted native "View source" item.
|
|
72
|
+
const lastContextTargetRef = useRef(null);
|
|
73
|
+
const [srcDoc, setSrcDoc] = useState(() => previewBootHtml());
|
|
74
|
+
// One site-root grant per tab, inferred in Rust from `entryPath` (nearest enclosing project
|
|
75
|
+
// directory). It is what lets the preview load assets that live above the document's own folder —
|
|
76
|
+
// the way a browser does — and it is revoked when the tab unmounts so the grant never outlives it.
|
|
77
|
+
// undefined = grant still resolving; null = resolved fallback without protocol grant. Never build
|
|
78
|
+
// user HTML against tauri:// while resolution is pending or root-relative assets leak into app CSP.
|
|
79
|
+
const { siteRoot, pickingRoot, chooseRoot: handleChooseSiteRoot } = useSiteRootGrant(entryPath);
|
|
80
|
+
const [nonce, setNonce] = useState(0); // bumped by Reload to force a rebuild
|
|
81
|
+
const [error, setError] = useState(null);
|
|
82
|
+
const [drawerOpen, setDrawerOpen] = useState(initialSourceDrawerOpen);
|
|
83
|
+
// Read mode keeps the source drawer (the editing surface) closed even if its state says open.
|
|
84
|
+
const drawer = drawerOpen && !readOnly;
|
|
85
|
+
// Done used to lift the inline editor the instant it committed, but rebuilding the preview is
|
|
86
|
+
// async — it reparses the document and re-inlines scripts before the new srcDoc commits. So the
|
|
87
|
+
// overlay disappeared over the STILL-OLD rendering, the pre-edit text flashed back, and only then
|
|
88
|
+
// did the edit appear. Hold the overlay until the rebuilt srcDoc lands, with a timeout so a failed
|
|
89
|
+
// or superseded build can never strand it on screen.
|
|
90
|
+
const srcDocRef = useRef("");
|
|
91
|
+
const pendingEditorCloseRef = useRef(null);
|
|
92
|
+
useCloseFindOnSurfaceChange(drawer, !!findMode, onCloseFind);
|
|
93
|
+
// The content the preview currently renders. Updated only on navigation,
|
|
94
|
+
// a sub-page's disk load completing, and Reload — NOT on every keystroke, so the running page keeps
|
|
95
|
+
// its state while you edit. Ownership is renderedRevision (sourceChecksum): preview reloads only when
|
|
96
|
+
// checksum !== renderedRevisionRef, not on save/apply nonce bumps. Live CSS hot-applies via bridge.
|
|
97
|
+
const [applied, setApplied] = useState("");
|
|
98
|
+
// Identity of the revision the preview currently renders. Sole owner of reload decisions.
|
|
99
|
+
const renderedRevisionRef = useRef(null);
|
|
100
|
+
// Page-scoped inverse history for block Done (one entry per committed plan). Cleared/rebased on
|
|
101
|
+
// external full-source replacement or explicit full-source save. Also drives Ctrl/Cmd+Z undo.
|
|
102
|
+
const blockHistoryRef = useRef([]);
|
|
103
|
+
const redoHistoryRef = useRef([]);
|
|
104
|
+
// The canonical source the draft-commit path last committed. The buffer state update is async
|
|
105
|
+
// (setCommittedSource / onPageChange re-render later), so runBlockStructuralOp must read the
|
|
106
|
+
// FRESH committed bytes here or its plan resolves against the pre-edit source and silently
|
|
107
|
+
// drops the text edit the draft just committed.
|
|
108
|
+
const lastBlockCommitSourceRef = useRef(null);
|
|
109
|
+
// The first snapshot is committed in an effect. Keep the builder dormant until that effect has run:
|
|
110
|
+
// otherwise React runs the builder once with the empty boot value and again with the real document.
|
|
111
|
+
const [initialAppliedReady, setInitialAppliedReady] = useState(false);
|
|
112
|
+
const [sourceFullscreen, setSourceFullscreen] = useState(false);
|
|
113
|
+
const [viewportMode, setViewportMode] = useState("auto");
|
|
114
|
+
const splitRef = useRef(null);
|
|
115
|
+
const autoViewport = useHtmlAutoViewport(splitRef);
|
|
116
|
+
const [previewZoomHud, setPreviewZoomHud] = useState(null);
|
|
117
|
+
// Browser-style status strip: the URL of the link currently under the pointer in the preview.
|
|
118
|
+
const [hoveredLink, setHoveredLink] = useState(null);
|
|
119
|
+
const previewZoomTimer = useRef(null);
|
|
120
|
+
const inspectScrollCancelRef = useRef(null);
|
|
121
|
+
// Seed from App's durable store so the scroll survives a tab-switch unmount; also restored
|
|
122
|
+
// across live rebuilds within a session.
|
|
123
|
+
const scrollYRef = useRef(initialPreviewScrollY ?? 0);
|
|
124
|
+
// Ref so the bridge message effect can persist scroll without resubscribing on every render.
|
|
125
|
+
const onPreviewScrollRef = useRef(onPreviewScroll);
|
|
126
|
+
onPreviewScrollRef.current = onPreviewScroll;
|
|
127
|
+
// Keep-alive diagnostic: this fires ONCE per real mount. If it fires again for the same tab after a
|
|
128
|
+
// tab switch, the component is being remounted (keep-alive broken) — visible in Settings → Diagnostics.
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
logEvent("html:mount");
|
|
131
|
+
}, []);
|
|
132
|
+
const localSourceViewStateRef = useRef({});
|
|
133
|
+
const sourceViewStateRef = externalSourceViewStateRef ?? localSourceViewStateRef;
|
|
134
|
+
const sourceEditorRef = useRef(null);
|
|
135
|
+
const pendingInspectRangeRef = useRef(null);
|
|
136
|
+
// In-tab navigation/history, local-link resolution, and the blocked-link prompt.
|
|
137
|
+
const { activePath, pendingFragment, blocked, setBlocked, navigate: rawNavigate, handleHref: rawHandleHref, goHistory: rawGoHistory, locateBlocked, copyBlocked, canGoBack, canGoForward, } = useHtmlNavigation({ entryPath, onOpenPath, scrollYRef });
|
|
138
|
+
// A modified rich draft must be committed (Done) before the page changes; it is never dropped.
|
|
139
|
+
// Returns false (navigation cancelled, draft kept) when the commit does not succeed.
|
|
140
|
+
const commitDraftBeforeLeaving = useCallback(async () => {
|
|
141
|
+
const identity = { documentPath: entryPath, pagePath: activePath };
|
|
142
|
+
if (!blockDrafts.hasModifiedDraft(identity))
|
|
143
|
+
return true;
|
|
144
|
+
const result = await blockDrafts.resolve(identity, "view-change", "done");
|
|
145
|
+
return result.outcome === "done" || result.outcome === "missing";
|
|
146
|
+
}, [activePath, blockDrafts, entryPath]);
|
|
147
|
+
const navigate = useCallback((path, fragment = null) => {
|
|
148
|
+
void commitDraftBeforeLeaving().then((ok) => {
|
|
149
|
+
if (ok)
|
|
150
|
+
rawNavigate(path, fragment);
|
|
151
|
+
});
|
|
152
|
+
}, [commitDraftBeforeLeaving, rawNavigate]);
|
|
153
|
+
const handleHref = useCallback(async (href, newTab = false) => {
|
|
154
|
+
if (!newTab && !(await commitDraftBeforeLeaving()))
|
|
155
|
+
return;
|
|
156
|
+
await rawHandleHref(href, newTab);
|
|
157
|
+
}, [commitDraftBeforeLeaving, rawHandleHref]);
|
|
158
|
+
const goHistory = useCallback((delta) => {
|
|
159
|
+
void commitDraftBeforeLeaving().then((ok) => {
|
|
160
|
+
if (ok)
|
|
161
|
+
rawGoHistory(delta);
|
|
162
|
+
});
|
|
163
|
+
}, [commitDraftBeforeLeaving, rawGoHistory]);
|
|
164
|
+
const revealSourceRange = useCallback((range) => {
|
|
165
|
+
const view = sourceEditorRef.current;
|
|
166
|
+
if (!view)
|
|
167
|
+
return false;
|
|
168
|
+
const start = Math.max(0, Math.min(view.state.doc.length, range.start));
|
|
169
|
+
const end = Math.max(start, Math.min(view.state.doc.length, range.end));
|
|
170
|
+
view.dispatch({ selection: { anchor: start, head: end } });
|
|
171
|
+
view.focus();
|
|
172
|
+
scrollPosIntoView(view, start); // CM's own scrollIntoView doesn't move the editor here — see cmScroll
|
|
173
|
+
return true;
|
|
174
|
+
}, []);
|
|
175
|
+
const { drawerWidth, startResize } = useHtmlSourceDrawerResize(splitRef);
|
|
176
|
+
// Legacy persisted visual values degrade to Interactive; both rendered modes use scoped editing.
|
|
177
|
+
const [fallbackView, setFallbackView] = useState(null);
|
|
178
|
+
const effectiveView = onChangeView ? view : (fallbackView ?? view);
|
|
179
|
+
const mode = (effectiveView === "preview" ? "preview" : "interactive");
|
|
180
|
+
// Rich-edit session state (safe target, transient view handoff, toolbar formatting, deferred
|
|
181
|
+
// inline-editor close). See useHtmlRichEditState.ts.
|
|
182
|
+
const { safeTarget, setSafeTarget, pendingSafeTargetRef, restoreInteractiveAfterEditRef, richFormatting, setRichFormatting, richEditRef, restoreInteractiveAfterTransientEdit, closeInlineEditor, clearPendingEditorClose, } = useHtmlRichEditState({ onChangeView, setFallbackView, srcDocRef, pendingEditorCloseRef });
|
|
183
|
+
// Print routing, the Interactive<->Safe swap mask, and select-all / zoom-reset / scroll-to-top.
|
|
184
|
+
const { swapping, scrollInteractivePreviewToTop, resetInteractivePreviewZoom } = useHtmlPreviewControls({
|
|
185
|
+
active,
|
|
186
|
+
drawer,
|
|
187
|
+
error,
|
|
188
|
+
mode,
|
|
189
|
+
sessionId,
|
|
190
|
+
iframeRef,
|
|
191
|
+
previewZoomTimer,
|
|
192
|
+
inspectScrollCancelRef,
|
|
193
|
+
scrollYRef,
|
|
194
|
+
});
|
|
195
|
+
// Find in the rendered interactive preview (drawer closed): registers an html-preview provider that
|
|
196
|
+
// drives the in-frame find engine; resolveFindResult settles each async postMessage round-trip.
|
|
197
|
+
const { resolveFindResult } = useHtmlPreviewFind({
|
|
198
|
+
iframeRef,
|
|
199
|
+
sessionId,
|
|
200
|
+
mode,
|
|
201
|
+
drawerOpen: drawer,
|
|
202
|
+
error,
|
|
203
|
+
registerSearchProvider,
|
|
204
|
+
});
|
|
205
|
+
const { onEntry, activeBuffer, activeBufferRef, activeDirty, subLoaded, setCommittedSource, commitSource, revisionForSource, commitPageMutation, } = useHtmlPageBuffer({
|
|
206
|
+
entryPath,
|
|
207
|
+
activePath,
|
|
208
|
+
text,
|
|
209
|
+
pageBuffers,
|
|
210
|
+
dirtyPagePaths,
|
|
211
|
+
onChange,
|
|
212
|
+
onPageChange,
|
|
213
|
+
});
|
|
214
|
+
// Cold-tab handoff: restore/park coherent rendered bytes + revision on remount/unmount.
|
|
215
|
+
useHtmlColdState({
|
|
216
|
+
entryPath,
|
|
217
|
+
activePath,
|
|
218
|
+
activeBuffer,
|
|
219
|
+
applied,
|
|
220
|
+
renderedRevisionRef,
|
|
221
|
+
setApplied,
|
|
222
|
+
setInitialAppliedReady,
|
|
223
|
+
});
|
|
224
|
+
const recordBlockCommit = useRecordBlockCommit({
|
|
225
|
+
activePath,
|
|
226
|
+
blockHistoryRef,
|
|
227
|
+
redoHistoryRef,
|
|
228
|
+
renderedRevisionRef,
|
|
229
|
+
commitSource,
|
|
230
|
+
setApplied,
|
|
231
|
+
});
|
|
232
|
+
const { handleSafeBlockTarget, handleEditRefused } = useHtmlSafeBlockEntry({
|
|
233
|
+
readOnly,
|
|
234
|
+
mode,
|
|
235
|
+
drawer,
|
|
236
|
+
entryPath,
|
|
237
|
+
activePath,
|
|
238
|
+
blockDrafts,
|
|
239
|
+
mountedRef,
|
|
240
|
+
activeBufferRef,
|
|
241
|
+
sourceEditorRef,
|
|
242
|
+
pendingInspectRangeRef,
|
|
243
|
+
richEditRef,
|
|
244
|
+
pendingEditorCloseRef,
|
|
245
|
+
pendingSafeTargetRef,
|
|
246
|
+
restoreInteractiveAfterEditRef,
|
|
247
|
+
lastBlockCommitSourceRef,
|
|
248
|
+
onChangeView,
|
|
249
|
+
setFallbackView,
|
|
250
|
+
setDrawerOpen,
|
|
251
|
+
setSafeTarget,
|
|
252
|
+
revealSourceRange,
|
|
253
|
+
restoreInteractiveAfterTransientEdit,
|
|
254
|
+
revisionForSource,
|
|
255
|
+
commitPageMutation,
|
|
256
|
+
recordBlockCommit,
|
|
257
|
+
});
|
|
258
|
+
// Contextual structural/rich operations from the block editor (one atomic transaction each).
|
|
259
|
+
const { runBlockStructuralOp, runBlockRichOp, canRunRichOp, canRunStructuralOp, propertyAttributes } = useHtmlBlockOps({
|
|
260
|
+
entryPath,
|
|
261
|
+
activePath,
|
|
262
|
+
activeBuffer,
|
|
263
|
+
activeBufferRef,
|
|
264
|
+
mountedRef,
|
|
265
|
+
blockDrafts,
|
|
266
|
+
safeTarget,
|
|
267
|
+
lastBlockCommitSourceRef,
|
|
268
|
+
closeInlineEditor,
|
|
269
|
+
revisionForSource,
|
|
270
|
+
commitPageMutation,
|
|
271
|
+
recordBlockCommit,
|
|
272
|
+
});
|
|
273
|
+
// Draft lifecycle for the active page (navigation/source-change resolution, read-mode release,
|
|
274
|
+
// block snapshot for the authoring row and overlay).
|
|
275
|
+
const { blockIdentity, blockSnapshot } = useHtmlBlockDrafts({
|
|
276
|
+
readOnly,
|
|
277
|
+
drawerOpen,
|
|
278
|
+
setDrawerOpen,
|
|
279
|
+
entryPath,
|
|
280
|
+
activePath,
|
|
281
|
+
activeBuffer,
|
|
282
|
+
blockDrafts,
|
|
283
|
+
safeTarget,
|
|
284
|
+
setSafeTarget,
|
|
285
|
+
restoreInteractiveAfterTransientEdit,
|
|
286
|
+
revisionForSource,
|
|
287
|
+
blockHistoryRef,
|
|
288
|
+
redoHistoryRef,
|
|
289
|
+
pendingEditorCloseRef,
|
|
290
|
+
pendingSafeTargetRef,
|
|
291
|
+
});
|
|
292
|
+
// Page-scoped block undo/redo + its global event/shortcut wiring.
|
|
293
|
+
useHtmlBlockUndoRedo({
|
|
294
|
+
active,
|
|
295
|
+
readOnly,
|
|
296
|
+
blockDrafts,
|
|
297
|
+
entryPath,
|
|
298
|
+
activePath,
|
|
299
|
+
blockHistoryRef,
|
|
300
|
+
redoHistoryRef,
|
|
301
|
+
activeBufferRef,
|
|
302
|
+
commitSource,
|
|
303
|
+
commitPageMutation,
|
|
304
|
+
renderedRevisionRef,
|
|
305
|
+
setApplied,
|
|
306
|
+
setSafeTarget,
|
|
307
|
+
});
|
|
308
|
+
// Inspect-to-source (View source) and its element context menu.
|
|
309
|
+
const { inspectMenu, setInspectMenu, handleInspectTarget, openInspectMenu, inspectFromMenu, copyMenuValue, } = useHtmlInspect({
|
|
310
|
+
readOnly,
|
|
311
|
+
activeBuffer,
|
|
312
|
+
mode,
|
|
313
|
+
sessionId,
|
|
314
|
+
iframeRef,
|
|
315
|
+
sourceEditorRef,
|
|
316
|
+
pendingInspectRangeRef,
|
|
317
|
+
inspectScrollCancelRef,
|
|
318
|
+
revealSourceRange,
|
|
319
|
+
setDrawerOpen,
|
|
320
|
+
});
|
|
321
|
+
// Seed the sub-page buffer on navigation, and report the active page up to App.
|
|
322
|
+
useHtmlSubPages({ entryPath, activePath, onEntry, onEnsurePage, onSetActivePage });
|
|
323
|
+
// Preview lifecycle: applied-snapshot gating + interactive srcDoc rebuild.
|
|
324
|
+
useHtmlPreviewLifecycle({
|
|
325
|
+
active,
|
|
326
|
+
mode,
|
|
327
|
+
entryPath,
|
|
328
|
+
activePath,
|
|
329
|
+
onEntry,
|
|
330
|
+
subLoaded,
|
|
331
|
+
drawerOpen: drawer,
|
|
332
|
+
applied,
|
|
333
|
+
activeBuffer,
|
|
334
|
+
nonce,
|
|
335
|
+
sessionId,
|
|
336
|
+
siteRoot,
|
|
337
|
+
initialAppliedReady,
|
|
338
|
+
pendingFragment,
|
|
339
|
+
pageBuffers,
|
|
340
|
+
activeBufferRef,
|
|
341
|
+
blockHistoryRef,
|
|
342
|
+
redoHistoryRef,
|
|
343
|
+
renderedRevisionRef,
|
|
344
|
+
scrollYRef,
|
|
345
|
+
mountedRef,
|
|
346
|
+
setApplied,
|
|
347
|
+
setSrcDoc,
|
|
348
|
+
setError,
|
|
349
|
+
setInitialAppliedReady,
|
|
350
|
+
});
|
|
351
|
+
// Live CSS/theme hot-apply bridge while the drawer is open.
|
|
352
|
+
useHtmlLiveCssBridge({
|
|
353
|
+
mode,
|
|
354
|
+
sessionId,
|
|
355
|
+
drawerOpen: drawer,
|
|
356
|
+
activeBuffer,
|
|
357
|
+
iframeRef,
|
|
358
|
+
});
|
|
359
|
+
// srcDoc lifecycle: debounced live rebuild, srcDoc ref sync, and pending inline-editor close.
|
|
360
|
+
// See useHtmlSrcDocLifecycle.ts.
|
|
361
|
+
useHtmlSrcDocLifecycle({
|
|
362
|
+
drawer,
|
|
363
|
+
mode,
|
|
364
|
+
activeBuffer,
|
|
365
|
+
applied,
|
|
366
|
+
setApplied,
|
|
367
|
+
srcDoc,
|
|
368
|
+
srcDocRef,
|
|
369
|
+
pendingEditorCloseRef,
|
|
370
|
+
clearPendingEditorClose,
|
|
371
|
+
});
|
|
372
|
+
// Interactive-preview postMessage bridge + native context-menu Tauri event listeners (View source /
|
|
373
|
+
// Open link in new tab / Open link externally). See HtmlDocumentBridge.tsx.
|
|
374
|
+
useHtmlDocumentBridge({
|
|
375
|
+
iframeRef,
|
|
376
|
+
sessionId,
|
|
377
|
+
lastContextTargetRef,
|
|
378
|
+
handleHref,
|
|
379
|
+
onRequestFind,
|
|
380
|
+
resolveFindResult,
|
|
381
|
+
handleInspectTarget,
|
|
382
|
+
openInspectMenu,
|
|
383
|
+
onPreviewScrollRef,
|
|
384
|
+
scrollYRef,
|
|
385
|
+
setPreviewZoomHud,
|
|
386
|
+
previewZoomTimer,
|
|
387
|
+
onEnterVisual: handleSafeBlockTarget,
|
|
388
|
+
onEditRefused: handleEditRefused,
|
|
389
|
+
onLinkHover: setHoveredLink,
|
|
390
|
+
});
|
|
391
|
+
useEffect(() => {
|
|
392
|
+
if (!drawer)
|
|
393
|
+
setSourceFullscreen(false);
|
|
394
|
+
}, [drawer]);
|
|
395
|
+
const toggleSourceDrawer = useCallback(() => {
|
|
396
|
+
// Read mode: the source drawer is the editing surface — the toggle is hidden in chrome and
|
|
397
|
+
// any programmatic call (viewright:html-toggle-source) must also be a no-op.
|
|
398
|
+
if (readOnly)
|
|
399
|
+
return;
|
|
400
|
+
const identity = { documentPath: entryPath, pagePath: activePath };
|
|
401
|
+
if (blockDrafts.get(identity)) {
|
|
402
|
+
toast("Finish the current HTML edit before opening Source.", "error");
|
|
403
|
+
richEditRef.current?.focus();
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
setDrawerOpen((open) => !open);
|
|
407
|
+
}, [activePath, blockDrafts, entryPath, readOnly, richEditRef]);
|
|
408
|
+
// Source drawer remains an explicit HTML control; F12 and inspect chords open HTML DevTools.
|
|
409
|
+
useEffect(() => {
|
|
410
|
+
if (!active)
|
|
411
|
+
return;
|
|
412
|
+
const onToggleSource = toggleSourceDrawer;
|
|
413
|
+
window.addEventListener("viewright:html-toggle-source", onToggleSource);
|
|
414
|
+
return () => window.removeEventListener("viewright:html-toggle-source", onToggleSource);
|
|
415
|
+
}, [active, toggleSourceDrawer]);
|
|
416
|
+
// Browser-style reload (viewright:html-reload) + the reload-pending buffer snapshot.
|
|
417
|
+
const { doReload } = useHtmlReload({
|
|
418
|
+
active,
|
|
419
|
+
activePath,
|
|
420
|
+
activeBuffer,
|
|
421
|
+
activeBufferRef,
|
|
422
|
+
renderedRevisionRef,
|
|
423
|
+
setApplied,
|
|
424
|
+
setNonce,
|
|
425
|
+
onReloadFromDisk,
|
|
426
|
+
});
|
|
427
|
+
// Source-drawer edit/save/discard for the active page (entry vs sub routed by App).
|
|
428
|
+
// Same ownership problem as a rendered-pane commit: typing here writes through a ref that does not
|
|
429
|
+
// re-render App, so this pane's `text` prop lags. Route it through the identical path so the drawer
|
|
430
|
+
// and the rendered pane can never disagree about which bytes are current.
|
|
431
|
+
const onActiveSourceChange = commitSource;
|
|
432
|
+
// Save the active page through App's session save (handles entry vs sub) so the preview reloads
|
|
433
|
+
// when the saved bytes differ — consistent for the entry, sub-pages, and Ctrl+S.
|
|
434
|
+
const onActiveSave = useCallback(() => {
|
|
435
|
+
onSavePage(entryPath, activePath);
|
|
436
|
+
}, [onSavePage, entryPath, activePath]);
|
|
437
|
+
const activeName = activePath.split(/[\\/]/).pop() ?? activePath;
|
|
438
|
+
const effectiveViewport = viewportMode === "auto" ? autoViewport : viewportMode;
|
|
439
|
+
const viewportWidth = viewportWidthPx(effectiveViewport);
|
|
440
|
+
const editRichSource = useCallback(async () => {
|
|
441
|
+
const identity = { documentPath: entryPath, pagePath: activePath };
|
|
442
|
+
// A modified draft is committed (Done) first so typed text survives; if the commit fails the
|
|
443
|
+
// draft stays open and Source is not opened.
|
|
444
|
+
const modified = blockDrafts.hasModifiedDraft(identity);
|
|
445
|
+
const current = activeBufferRef.current;
|
|
446
|
+
const exactRange = safeTarget && !modified ? (resolveSafeBlockTarget(current, safeTarget)?.range ?? null) : null;
|
|
447
|
+
const result = await blockDrafts.resolve(identity, "view-change", modified ? "done" : "discard");
|
|
448
|
+
if (result.outcome === "discarded" ||
|
|
449
|
+
result.outcome === "missing" ||
|
|
450
|
+
result.outcome === "done") {
|
|
451
|
+
setSafeTarget(null);
|
|
452
|
+
restoreInteractiveAfterTransientEdit();
|
|
453
|
+
if (exactRange)
|
|
454
|
+
pendingInspectRangeRef.current = exactRange;
|
|
455
|
+
setDrawerOpen(true);
|
|
456
|
+
if (exactRange && sourceEditorRef.current) {
|
|
457
|
+
window.requestAnimationFrame(() => {
|
|
458
|
+
const pending = pendingInspectRangeRef.current;
|
|
459
|
+
if (pending && revealSourceRange(pending))
|
|
460
|
+
pendingInspectRangeRef.current = null;
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}, [
|
|
465
|
+
activeBufferRef,
|
|
466
|
+
activePath,
|
|
467
|
+
blockDrafts,
|
|
468
|
+
entryPath,
|
|
469
|
+
restoreInteractiveAfterTransientEdit,
|
|
470
|
+
revealSourceRange,
|
|
471
|
+
safeTarget,
|
|
472
|
+
setSafeTarget,
|
|
473
|
+
]);
|
|
474
|
+
// In-frame ProseMirror mount target: resolve safeTarget.childPath inside the Safe iframe's DOM.
|
|
475
|
+
const { inframeTarget, setInframeTarget, iframeGeneration } = useHtmlInframeTarget({
|
|
476
|
+
safeIframeRef,
|
|
477
|
+
safeTarget,
|
|
478
|
+
mode,
|
|
479
|
+
blockSnapshot,
|
|
480
|
+
activePath,
|
|
481
|
+
applied,
|
|
482
|
+
});
|
|
483
|
+
return (_jsx(HtmlDocumentLayout, { flags: { readOnly, active, drawer, sourceFullscreen, mode }, address: {
|
|
484
|
+
activePath,
|
|
485
|
+
activeDirty,
|
|
486
|
+
subpageStale: !onEntry && !!pageBuffers[activePath]?.stale,
|
|
487
|
+
viewport: effectiveViewport,
|
|
488
|
+
canGoBack,
|
|
489
|
+
canGoForward,
|
|
490
|
+
goHistory,
|
|
491
|
+
setViewportMode,
|
|
492
|
+
onReload: doReload,
|
|
493
|
+
findBar,
|
|
494
|
+
findMode,
|
|
495
|
+
onRequestFind,
|
|
496
|
+
onRequestReplace,
|
|
497
|
+
onToggleSource: toggleSourceDrawer,
|
|
498
|
+
}, rich: {
|
|
499
|
+
safeTarget,
|
|
500
|
+
blockSnapshot: blockSnapshot ?? undefined,
|
|
501
|
+
blockIdentity,
|
|
502
|
+
hasChangeView: !!onChangeView,
|
|
503
|
+
richEditRef,
|
|
504
|
+
richFormatting,
|
|
505
|
+
setRichFormatting,
|
|
506
|
+
runBlockRichOp,
|
|
507
|
+
runBlockStructuralOp,
|
|
508
|
+
canRunRichOp,
|
|
509
|
+
canRunStructuralOp,
|
|
510
|
+
propertyAttributes,
|
|
511
|
+
editRichSource,
|
|
512
|
+
closeInlineEditor,
|
|
513
|
+
inframeTarget,
|
|
514
|
+
setInframeTarget,
|
|
515
|
+
iframeGeneration,
|
|
516
|
+
}, preview: {
|
|
517
|
+
splitRef,
|
|
518
|
+
hoveredLink,
|
|
519
|
+
pickingRoot,
|
|
520
|
+
onChooseSiteRoot: () => void handleChooseSiteRoot(),
|
|
521
|
+
showSiteRootNotice: !!siteRoot && siteRoot.markerFound === false,
|
|
522
|
+
error,
|
|
523
|
+
nonce,
|
|
524
|
+
srcDoc,
|
|
525
|
+
iframeRef,
|
|
526
|
+
safeIframeRef,
|
|
527
|
+
activePath,
|
|
528
|
+
entryPath,
|
|
529
|
+
siteRoot: siteRoot ?? null,
|
|
530
|
+
resourcesReady: siteRoot !== undefined,
|
|
531
|
+
applied,
|
|
532
|
+
themeKey,
|
|
533
|
+
registerSearchProvider,
|
|
534
|
+
onInspectTarget: handleInspectTarget,
|
|
535
|
+
onInspectMenu: openInspectMenu,
|
|
536
|
+
onRequestFind,
|
|
537
|
+
navigate,
|
|
538
|
+
onOpenPath,
|
|
539
|
+
viewportWidth,
|
|
540
|
+
previewZoomHud,
|
|
541
|
+
swapping,
|
|
542
|
+
onBackToTop: scrollInteractivePreviewToTop,
|
|
543
|
+
onResetPreviewZoom: resetInteractivePreviewZoom,
|
|
544
|
+
onSafeBlockTarget: handleSafeBlockTarget,
|
|
545
|
+
onLinkHover: setHoveredLink,
|
|
546
|
+
}, source: {
|
|
547
|
+
subLoaded,
|
|
548
|
+
activePath,
|
|
549
|
+
activeBuffer,
|
|
550
|
+
activeName,
|
|
551
|
+
activeDirty,
|
|
552
|
+
drawerWidth,
|
|
553
|
+
onStartResize: startResize,
|
|
554
|
+
onToggleFullscreen: () => setSourceFullscreen((value) => !value),
|
|
555
|
+
onActiveSourceChange,
|
|
556
|
+
onActiveSave,
|
|
557
|
+
onDiscardPage: () => {
|
|
558
|
+
// An entry discard reverts App's store without re-rendering this pane's `text`
|
|
559
|
+
// prop, so the parked local commit must be dropped here or it stays on screen.
|
|
560
|
+
if (onEntry)
|
|
561
|
+
setCommittedSource(null);
|
|
562
|
+
onDiscardPage(entryPath, activePath);
|
|
563
|
+
},
|
|
564
|
+
registerSearchProvider,
|
|
565
|
+
findBar,
|
|
566
|
+
findMode,
|
|
567
|
+
onRequestFind,
|
|
568
|
+
onRequestReplace,
|
|
569
|
+
sourceViewStateRef,
|
|
570
|
+
sourceEditorRef,
|
|
571
|
+
pendingInspectRangeRef,
|
|
572
|
+
revealSourceRange,
|
|
573
|
+
}, overlays: {
|
|
574
|
+
inspectMenu,
|
|
575
|
+
setInspectMenu,
|
|
576
|
+
handleHref,
|
|
577
|
+
copyMenuValue,
|
|
578
|
+
inspectFromMenu,
|
|
579
|
+
blocked,
|
|
580
|
+
setBlocked,
|
|
581
|
+
locateBlocked,
|
|
582
|
+
copyBlocked,
|
|
583
|
+
} }));
|
|
584
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { ComponentProps, Dispatch, ReactNode, RefObject, SetStateAction } from "react";
|
|
2
|
+
import type { ViewportMode } from "@rightkit/html-editor/documents/html/htmlDocumentShared";
|
|
3
|
+
import type { HtmlSafeBlockTarget } from "@rightkit/html-editor/documents/html/sourceMap";
|
|
4
|
+
import type { InspectMenuState } from "@rightkit/html-editor/documents/html/useHtmlInspect";
|
|
5
|
+
import type { HtmlSafeBlockEditorHandle, HtmlEditorToolbarState } from "@rightkit/html-editor/documents/html/HtmlSafeBlockEditor";
|
|
6
|
+
import { HtmlDocumentView } from "@rightkit/html-editor/documents/html/HtmlDocumentView";
|
|
7
|
+
import { HtmlDocumentSource } from "./HtmlDocumentSource.js";
|
|
8
|
+
import { HtmlAddressRow, HtmlRichEditRow } from "@rightkit/html-editor/documents/html/HtmlDocumentToolbars";
|
|
9
|
+
import { HtmlSafeBlockEditor } from "@rightkit/html-editor/documents/html/HtmlSafeBlockEditor";
|
|
10
|
+
import type { useHtmlNavigation } from "@rightkit/html-editor/documents/html/useHtmlNavigation";
|
|
11
|
+
type Blocked = ReturnType<typeof useHtmlNavigation>["blocked"];
|
|
12
|
+
type RichEditRef = RefObject<HtmlSafeBlockEditorHandle | null>;
|
|
13
|
+
type ViewportChoice = ComponentProps<typeof HtmlAddressRow>["viewport"];
|
|
14
|
+
export interface HtmlDocumentLayoutProps {
|
|
15
|
+
/** Mode and visibility flags. */
|
|
16
|
+
flags: {
|
|
17
|
+
readOnly: boolean;
|
|
18
|
+
active: boolean;
|
|
19
|
+
drawer: boolean;
|
|
20
|
+
sourceFullscreen: boolean;
|
|
21
|
+
mode: "interactive" | "preview";
|
|
22
|
+
};
|
|
23
|
+
/** Top address capsule (or the editing capsule row when a block is open). */
|
|
24
|
+
address: {
|
|
25
|
+
activePath: string;
|
|
26
|
+
activeDirty: boolean;
|
|
27
|
+
subpageStale?: boolean;
|
|
28
|
+
viewport: ViewportChoice;
|
|
29
|
+
canGoBack: boolean;
|
|
30
|
+
canGoForward: boolean;
|
|
31
|
+
goHistory: (delta: number) => void;
|
|
32
|
+
setViewportMode: Dispatch<SetStateAction<ViewportMode>>;
|
|
33
|
+
onReload: () => void;
|
|
34
|
+
findBar: ReactNode;
|
|
35
|
+
findMode?: "find" | "replace";
|
|
36
|
+
onRequestFind?: () => void;
|
|
37
|
+
onRequestReplace?: () => void;
|
|
38
|
+
onToggleSource: () => void;
|
|
39
|
+
};
|
|
40
|
+
/** Rich-edit session: authoring row, inline overlay, and their operations. */
|
|
41
|
+
rich: {
|
|
42
|
+
safeTarget: HtmlSafeBlockTarget | null;
|
|
43
|
+
blockSnapshot: ComponentProps<typeof HtmlRichEditRow>["snapshot"] | undefined;
|
|
44
|
+
blockIdentity: ComponentProps<typeof HtmlSafeBlockEditor>["identity"];
|
|
45
|
+
hasChangeView: boolean;
|
|
46
|
+
richEditRef: RichEditRef;
|
|
47
|
+
richFormatting: HtmlEditorToolbarState | undefined;
|
|
48
|
+
setRichFormatting: ComponentProps<typeof HtmlSafeBlockEditor>["onToolbarStateChange"];
|
|
49
|
+
runBlockRichOp: ComponentProps<typeof HtmlRichEditRow>["onRichOp"];
|
|
50
|
+
runBlockStructuralOp: ComponentProps<typeof HtmlRichEditRow>["onStructuralOp"];
|
|
51
|
+
canRunRichOp: ComponentProps<typeof HtmlRichEditRow>["canRichOp"];
|
|
52
|
+
canRunStructuralOp: ComponentProps<typeof HtmlRichEditRow>["canStructuralOp"];
|
|
53
|
+
propertyAttributes: ComponentProps<typeof HtmlSafeBlockEditor>["propertyAttributes"];
|
|
54
|
+
editRichSource: () => void;
|
|
55
|
+
closeInlineEditor: () => void;
|
|
56
|
+
inframeTarget: ComponentProps<typeof HtmlSafeBlockEditor>["iframeTarget"];
|
|
57
|
+
setInframeTarget: ComponentProps<typeof HtmlSafeBlockEditor>["onIframeTargetChange"];
|
|
58
|
+
iframeGeneration: ComponentProps<typeof HtmlSafeBlockEditor>["iframeGeneration"];
|
|
59
|
+
};
|
|
60
|
+
/** Preview surface (interactive iframe / Safe iframe) and its split container. */
|
|
61
|
+
preview: Omit<ComponentProps<typeof HtmlDocumentView>, "mode" | "drawerOpen" | "overlay" | "active"> & {
|
|
62
|
+
splitRef: RefObject<HTMLDivElement | null>;
|
|
63
|
+
hoveredLink: string | null;
|
|
64
|
+
pickingRoot: boolean;
|
|
65
|
+
onChooseSiteRoot: () => void;
|
|
66
|
+
showSiteRootNotice: boolean;
|
|
67
|
+
};
|
|
68
|
+
/** Source drawer (CodeMirror). */
|
|
69
|
+
source: Omit<ComponentProps<typeof HtmlDocumentSource>, "active" | "sourceFullscreen"> & {
|
|
70
|
+
onToggleFullscreen: () => void;
|
|
71
|
+
};
|
|
72
|
+
/** Element context menu and blocked-link prompt. */
|
|
73
|
+
overlays: {
|
|
74
|
+
inspectMenu: InspectMenuState | null;
|
|
75
|
+
setInspectMenu: (menu: InspectMenuState | null) => void;
|
|
76
|
+
handleHref: (href: string, background: boolean) => Promise<void> | void;
|
|
77
|
+
copyMenuValue: (value: string) => void;
|
|
78
|
+
inspectFromMenu: () => void;
|
|
79
|
+
blocked: Blocked;
|
|
80
|
+
setBlocked: (value: Blocked) => void;
|
|
81
|
+
locateBlocked: () => Promise<void> | void;
|
|
82
|
+
copyBlocked: () => Promise<void> | void;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Pure render tree for the HTML document: toolbars, preview split, source drawer, and overlays. */
|
|
86
|
+
export declare function HtmlDocumentLayout({ flags, address, rich, preview, source, overlays }: HtmlDocumentLayoutProps): import("react").JSX.Element;
|
|
87
|
+
export {};
|