@open-press/cli 0.7.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +29 -13
  2. package/dist/cli.js +44 -195
  3. package/package.json +4 -5
  4. package/template/core/AGENTS.md +18 -14
  5. package/template/core/CHANGELOG.md +57 -9
  6. package/template/core/README.md +6 -3
  7. package/template/core/engine/cli.mjs +8 -8
  8. package/template/core/engine/commands/_shared.mjs +37 -15
  9. package/template/core/engine/commands/dev.mjs +2 -2
  10. package/template/core/engine/commands/image.mjs +29 -0
  11. package/template/core/engine/commands/skills-sync.mjs +71 -0
  12. package/template/core/engine/commands/typecheck.mjs +63 -1
  13. package/template/core/engine/commands/upgrade.mjs +3 -3
  14. package/template/core/engine/document-export.mjs +1 -1
  15. package/template/core/engine/output/chrome-pdf.mjs +110 -3
  16. package/template/core/engine/output/static-server.mjs +87 -9
  17. package/template/core/engine/react/comment-endpoint.mjs +13 -39
  18. package/template/core/engine/react/comment-marker.mjs +43 -19
  19. package/template/core/engine/react/document-entry.mjs +46 -28
  20. package/template/core/engine/react/document-export.mjs +328 -164
  21. package/template/core/engine/react/http-json.mjs +24 -0
  22. package/template/core/engine/react/mdx-compile.mjs +126 -3
  23. package/template/core/engine/react/measurement-css.mjs +114 -1
  24. package/template/core/engine/react/object-entities.mjs +204 -0
  25. package/template/core/engine/react/pagination/allocator.mjs +48 -3
  26. package/template/core/engine/react/pagination.mjs +1 -1
  27. package/template/core/engine/react/pipeline/allocate.mjs +41 -72
  28. package/template/core/engine/react/pipeline/frame-measurement.mjs +6 -0
  29. package/template/core/engine/react/press-tree-inspection.mjs +172 -0
  30. package/template/core/engine/react/project-asset-endpoint.mjs +6 -24
  31. package/template/core/engine/react/source-edit-endpoint.d.mts +10 -0
  32. package/template/core/engine/react/source-edit-endpoint.mjs +75 -0
  33. package/template/core/engine/react/sources/mdx-resolver.mjs +13 -15
  34. package/template/core/engine/react/style-discovery.mjs +23 -8
  35. package/template/core/engine/runtime/config.d.mts +8 -0
  36. package/template/core/engine/runtime/config.mjs +57 -60
  37. package/template/core/engine/runtime/file-utils.mjs +9 -1
  38. package/template/core/engine/runtime/file-walk.mjs +22 -0
  39. package/template/core/engine/runtime/inspection.mjs +1 -20
  40. package/template/core/engine/runtime/page-geometry.mjs +131 -0
  41. package/template/core/engine/runtime/path-utils.mjs +20 -0
  42. package/template/core/engine/runtime/source-text-tools.d.mts +102 -0
  43. package/template/core/engine/runtime/source-text-tools.mjs +551 -16
  44. package/template/core/engine/runtime/source-workspace.mjs +16 -34
  45. package/template/core/engine/runtime/validation.mjs +19 -10
  46. package/template/core/openpress.config.mjs +3 -7
  47. package/template/core/package.json +3 -5
  48. package/template/core/src/main.tsx +2 -2
  49. package/template/core/src/openpress/app/OpenPressApp.tsx +296 -0
  50. package/template/core/src/openpress/{renderer.tsx → app/OpenPressRuntime.tsx} +20 -9
  51. package/template/core/src/openpress/app/WorkspaceGalleryPage.tsx +219 -0
  52. package/template/core/src/openpress/app/index.ts +2 -0
  53. package/template/core/src/openpress/core/Frame.tsx +26 -15
  54. package/template/core/src/openpress/core/FrameContext.tsx +10 -3
  55. package/template/core/src/openpress/core/MdxArea.tsx +11 -12
  56. package/template/core/src/openpress/core/Press.tsx +25 -4
  57. package/template/core/src/openpress/core/Workspace.tsx +36 -0
  58. package/template/core/src/openpress/core/cn.ts +4 -0
  59. package/template/core/src/openpress/core/index.tsx +11 -3
  60. package/template/core/src/openpress/core/primitives.tsx +74 -6
  61. package/template/core/src/openpress/core/types.ts +94 -41
  62. package/template/core/src/openpress/core/useSource.ts +1 -1
  63. package/template/core/src/openpress/{anchorMap.ts → document-model/anchorMapModel.ts} +1 -1
  64. package/template/core/src/openpress/{indexes.ts → document-model/documentIndexes.ts} +1 -1
  65. package/template/core/src/openpress/{types.ts → document-model/documentTypes.ts} +51 -0
  66. package/template/core/src/openpress/document-model/index.ts +7 -0
  67. package/template/core/src/openpress/document-model/objectEntityModel.ts +55 -0
  68. package/template/core/src/openpress/{projectIdentity.ts → document-model/projectIdentityModel.ts} +1 -1
  69. package/template/core/src/openpress/{reactDocumentMetadata.ts → document-model/reactDocumentMetadataModel.ts} +1 -1
  70. package/template/core/src/openpress/document-model/workspaceManifestModel.ts +57 -0
  71. package/template/core/src/openpress/manuscript/index.tsx +49 -7
  72. package/template/core/src/openpress/mdx/index.ts +15 -7
  73. package/template/core/src/openpress/reader/PageThumbnailsPanel.tsx +168 -0
  74. package/template/core/src/openpress/{publicPage.tsx → reader/PublicReaderPage.tsx} +31 -51
  75. package/template/core/src/openpress/{workbenchPanels.tsx → reader/ReaderNavigationPanel.tsx} +6 -5
  76. package/template/core/src/openpress/reader/index.ts +11 -0
  77. package/template/core/src/openpress/reader/pageViewportScaleModel.ts +73 -0
  78. package/template/core/src/openpress/reader/readerTypes.ts +4 -0
  79. package/template/core/src/openpress/reader/usePageViewportScale.ts +119 -0
  80. package/template/core/src/openpress/reader/usePanelState.ts +56 -0
  81. package/template/core/src/openpress/reader/useReaderHashSync.ts +61 -0
  82. package/template/core/src/openpress/reader/useReaderKeyboardNav.ts +48 -0
  83. package/template/core/src/openpress/reader/useReaderRuntime.ts +146 -0
  84. package/template/core/src/openpress/reader/useReaderScrollAnchor.ts +64 -0
  85. package/template/core/src/openpress/shared/Panel.tsx +77 -0
  86. package/template/core/src/openpress/shared/index.ts +4 -0
  87. package/template/core/src/openpress/shared/numberUtils.ts +3 -0
  88. package/template/core/src/openpress/{runtimeMode.ts → shared/runtimeMode.ts} +0 -11
  89. package/template/core/src/openpress/workbench/Workbench.tsx +506 -0
  90. package/template/core/src/openpress/workbench/actions/DeploymentControl.tsx +157 -0
  91. package/template/core/src/openpress/workbench/actions/ExportImageControl.tsx +96 -0
  92. package/template/core/src/openpress/workbench/actions/PageZoomControl.tsx +182 -0
  93. package/template/core/src/openpress/workbench/actions/SearchControl.tsx +345 -0
  94. package/template/core/src/openpress/workbench/actions/deploymentStatusModel.ts +112 -0
  95. package/template/core/src/openpress/workbench/actions/index.ts +6 -0
  96. package/template/core/src/openpress/workbench/actions/useDeploymentWorkbench.ts +136 -0
  97. package/template/core/src/openpress/workbench/dialog/WorkbenchDialog.tsx +72 -0
  98. package/template/core/src/openpress/workbench/dialog/index.ts +1 -0
  99. package/template/core/src/openpress/workbench/document/components/DocumentPanel.tsx +127 -0
  100. package/template/core/src/openpress/workbench/document/components/InlineSourceEditorLayer.tsx +207 -0
  101. package/template/core/src/openpress/workbench/document/components/ReaderStage.tsx +9 -0
  102. package/template/core/src/openpress/workbench/document/hooks/useDocumentWorkbenchModel.ts +34 -0
  103. package/template/core/src/openpress/workbench/document/hooks/useInlineDocumentEditor.ts +525 -0
  104. package/template/core/src/openpress/workbench/document/index.ts +10 -0
  105. package/template/core/src/openpress/workbench/index.ts +2 -0
  106. package/template/core/src/openpress/workbench/inspector/InlineInspectorLayer.tsx +459 -0
  107. package/template/core/src/openpress/workbench/inspector/index.ts +5 -0
  108. package/template/core/src/openpress/workbench/inspector/inlineCommentModel.ts +125 -0
  109. package/template/core/src/openpress/workbench/inspector/inspectorGeometryModel.ts +160 -0
  110. package/template/core/src/openpress/workbench/inspector/inspectorModel.ts +408 -0
  111. package/template/core/src/openpress/workbench/inspector/useInspectorComments.ts +254 -0
  112. package/template/core/src/openpress/workbench/mentions/MentionSuggestionList.tsx +41 -0
  113. package/template/core/src/openpress/workbench/mentions/index.ts +2 -0
  114. package/template/core/src/openpress/{composerMentions.ts → workbench/mentions/useComposerMentions.ts} +1 -4
  115. package/template/core/src/openpress/workbench/panels/Panel.tsx +1 -0
  116. package/template/core/src/openpress/workbench/panels/PendingCommentsPanel.tsx +80 -0
  117. package/template/core/src/openpress/workbench/panels/WorkbenchControlPanel.tsx +29 -0
  118. package/template/core/src/openpress/workbench/panels/index.ts +3 -0
  119. package/template/core/src/openpress/workbench/project/ProjectEntryPanel.tsx +525 -0
  120. package/template/core/src/openpress/workbench/project/ProjectPreviewDialog.tsx +35 -0
  121. package/template/core/src/openpress/workbench/project/index.ts +2 -0
  122. package/template/core/src/openpress/workbench/project/projectPreviewTypes.ts +11 -0
  123. package/template/core/src/openpress/workbench/shell/WorkbenchShell.tsx +167 -0
  124. package/template/core/src/openpress/workbench/shell/index.ts +1 -0
  125. package/template/core/src/openpress/workbench/workbenchFormatters.ts +120 -0
  126. package/template/core/src/openpress/workbench/workbenchTypes.ts +35 -0
  127. package/template/core/src/styles/openpress/print-route.css +0 -2
  128. package/template/core/src/styles/openpress/{project-workspace.css → project-preview-panel.css} +13 -407
  129. package/template/core/src/styles/openpress/public-viewer.css +25 -320
  130. package/template/core/src/styles/openpress/reader-runtime.css +252 -55
  131. package/template/core/src/styles/openpress/responsive.css +145 -270
  132. package/template/core/src/styles/openpress/workbench-panels.css +327 -178
  133. package/template/core/src/styles/openpress/workbench.css +986 -451
  134. package/template/core/src/styles/openpress/workspace-gallery.css +300 -0
  135. package/template/core/src/styles/openpress.css +2 -1
  136. package/template/core/tsconfig.json +1 -1
  137. package/template/core/vite.config.ts +50 -0
  138. package/template/core/engine/commands/init.mjs +0 -24
  139. package/template/core/engine/init.mjs +0 -90
  140. package/template/core/src/openpress/App.tsx +0 -127
  141. package/template/core/src/openpress/inspector.ts +0 -282
  142. package/template/core/src/openpress/projectWorkspace.tsx +0 -919
  143. package/template/core/src/openpress/readerRuntime.ts +0 -230
  144. package/template/core/src/openpress/workbench.tsx +0 -1265
  145. package/template/core/src/openpress/workbenchTypes.ts +0 -4
  146. package/template/packs/academic-paper/document/chapters/01-introduction/content/01-introduction.mdx +0 -35
  147. package/template/packs/academic-paper/document/chapters/02-methods/content/01-methods.mdx +0 -50
  148. package/template/packs/academic-paper/document/chapters/03-results-and-discussion/content/01-results.mdx +0 -47
  149. package/template/packs/academic-paper/document/chapters/04-acknowledgment/content/01-acknowledgment.mdx +0 -26
  150. package/template/packs/academic-paper/document/chapters/05-references/content/01-references.mdx +0 -32
  151. package/template/packs/academic-paper/document/components/ChapterOpenerVisual/index.tsx +0 -76
  152. package/template/packs/academic-paper/document/components/Page.tsx +0 -60
  153. package/template/packs/academic-paper/document/components/TokenSwatchGrid/index.tsx +0 -46
  154. package/template/packs/academic-paper/document/components/TokenSwatchGrid/style.css +0 -63
  155. package/template/packs/academic-paper/document/components/TypeSpecimen/index.tsx +0 -38
  156. package/template/packs/academic-paper/document/components/TypeSpecimen/style.css +0 -111
  157. package/template/packs/academic-paper/document/design.md +0 -279
  158. package/template/packs/academic-paper/document/index.tsx +0 -123
  159. package/template/packs/academic-paper/document/media/README.md +0 -13
  160. package/template/packs/academic-paper/document/media/figure-placeholder.svg +0 -9
  161. package/template/packs/academic-paper/document/openpress.config.mjs +0 -26
  162. package/template/packs/academic-paper/document/theme/README.md +0 -11
  163. package/template/packs/academic-paper/document/theme/base/page-contract.css +0 -522
  164. package/template/packs/academic-paper/document/theme/base/print.css +0 -93
  165. package/template/packs/academic-paper/document/theme/base/typography.css +0 -333
  166. package/template/packs/academic-paper/document/theme/fonts.css +0 -3
  167. package/template/packs/academic-paper/document/theme/page-surfaces/back-cover.css +0 -43
  168. package/template/packs/academic-paper/document/theme/page-surfaces/chapter-opener.css +0 -205
  169. package/template/packs/academic-paper/document/theme/page-surfaces/cover.css +0 -294
  170. package/template/packs/academic-paper/document/theme/page-surfaces/toc.css +0 -149
  171. package/template/packs/academic-paper/document/theme/patterns/_chart-frame.css +0 -49
  172. package/template/packs/academic-paper/document/theme/patterns/figure-grid.css +0 -68
  173. package/template/packs/academic-paper/document/theme/patterns/table-utilities.css +0 -66
  174. package/template/packs/academic-paper/document/theme/shell/reader-controls.css +0 -761
  175. package/template/packs/academic-paper/document/theme/tokens.css +0 -80
  176. package/template/packs/academic-paper/openpress.config.mjs +0 -5
  177. package/template/packs/claude-document/document/chapters/01-document-shape/content/01-document-shape.mdx +0 -51
  178. package/template/packs/claude-document/document/chapters/02-review-loop/content/01-review-loop.mdx +0 -31
  179. package/template/packs/claude-document/document/components/ChapterOpenerVisual.tsx +0 -96
  180. package/template/packs/claude-document/document/components/Page.tsx +0 -37
  181. package/template/packs/claude-document/document/design.md +0 -142
  182. package/template/packs/claude-document/document/index.tsx +0 -94
  183. package/template/packs/claude-document/document/media/README.md +0 -13
  184. package/template/packs/claude-document/document/openpress.config.mjs +0 -26
  185. package/template/packs/claude-document/document/theme/README.md +0 -15
  186. package/template/packs/claude-document/document/theme/base/page-contract.css +0 -525
  187. package/template/packs/claude-document/document/theme/base/print.css +0 -93
  188. package/template/packs/claude-document/document/theme/base/typography.css +0 -612
  189. package/template/packs/claude-document/document/theme/fonts.css +0 -4
  190. package/template/packs/claude-document/document/theme/page-surfaces/back-cover.css +0 -72
  191. package/template/packs/claude-document/document/theme/page-surfaces/chapter-opener.css +0 -236
  192. package/template/packs/claude-document/document/theme/page-surfaces/cover.css +0 -309
  193. package/template/packs/claude-document/document/theme/page-surfaces/toc.css +0 -225
  194. package/template/packs/claude-document/document/theme/patterns/_chart-frame.css +0 -53
  195. package/template/packs/claude-document/document/theme/patterns/figure-grid.css +0 -68
  196. package/template/packs/claude-document/document/theme/patterns/table-utilities.css +0 -66
  197. package/template/packs/claude-document/document/theme/shell/reader-controls.css +0 -789
  198. package/template/packs/claude-document/document/theme/tokens.css +0 -89
  199. package/template/packs/claude-document/openpress.config.mjs +0 -5
  200. package/template/packs/editorial-monograph/document/chapters/01-product-and-use-cases/content/01-product-and-use-cases.mdx +0 -31
  201. package/template/packs/editorial-monograph/document/chapters/02-workflow/content/01-workflow.mdx +0 -89
  202. package/template/packs/editorial-monograph/document/chapters/03-agent-skills-contributors/content/01-agent-skills-contributors.mdx +0 -51
  203. package/template/packs/editorial-monograph/document/chapters/04-validation-deploy/content/01-validation-deploy.mdx +0 -39
  204. package/template/packs/editorial-monograph/document/components/ChapterOpenerVisual/index.tsx +0 -76
  205. package/template/packs/editorial-monograph/document/components/Page.tsx +0 -37
  206. package/template/packs/editorial-monograph/document/components/TokenSwatchGrid/index.tsx +0 -46
  207. package/template/packs/editorial-monograph/document/components/TokenSwatchGrid/style.css +0 -63
  208. package/template/packs/editorial-monograph/document/components/TypeSpecimen/index.tsx +0 -38
  209. package/template/packs/editorial-monograph/document/components/TypeSpecimen/style.css +0 -111
  210. package/template/packs/editorial-monograph/document/design.md +0 -279
  211. package/template/packs/editorial-monograph/document/index.tsx +0 -97
  212. package/template/packs/editorial-monograph/document/media/README.md +0 -13
  213. package/template/packs/editorial-monograph/document/openpress.config.mjs +0 -26
  214. package/template/packs/editorial-monograph/document/theme/README.md +0 -11
  215. package/template/packs/editorial-monograph/document/theme/base/page-contract.css +0 -505
  216. package/template/packs/editorial-monograph/document/theme/base/print.css +0 -93
  217. package/template/packs/editorial-monograph/document/theme/base/typography.css +0 -336
  218. package/template/packs/editorial-monograph/document/theme/fonts.css +0 -3
  219. package/template/packs/editorial-monograph/document/theme/page-surfaces/back-cover.css +0 -43
  220. package/template/packs/editorial-monograph/document/theme/page-surfaces/chapter-opener.css +0 -205
  221. package/template/packs/editorial-monograph/document/theme/page-surfaces/cover.css +0 -147
  222. package/template/packs/editorial-monograph/document/theme/page-surfaces/toc.css +0 -149
  223. package/template/packs/editorial-monograph/document/theme/patterns/_chart-frame.css +0 -49
  224. package/template/packs/editorial-monograph/document/theme/patterns/figure-grid.css +0 -68
  225. package/template/packs/editorial-monograph/document/theme/patterns/table-utilities.css +0 -66
  226. package/template/packs/editorial-monograph/document/theme/shell/reader-controls.css +0 -761
  227. package/template/packs/editorial-monograph/document/theme/tokens.css +0 -80
  228. package/template/packs/editorial-monograph/openpress.config.mjs +0 -5
  229. /package/template/core/src/openpress/{readerPageRegistry.ts → reader/readerPageRegistry.ts} +0 -0
  230. /package/template/core/src/openpress/{pageRoute.ts → reader/readerPageRoute.ts} +0 -0
  231. /package/template/core/src/openpress/{readerScroll.ts → reader/readerScroll.ts} +0 -0
  232. /package/template/core/src/openpress/{readerState.ts → reader/readerStateModel.ts} +0 -0
  233. /package/template/core/src/openpress/{frameScheduler.ts → shared/frameScheduler.ts} +0 -0
  234. /package/template/core/src/openpress/{projectSources.ts → workbench/project/projectSourceModel.ts} +0 -0
@@ -1,282 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useState, type MouseEvent as ReactMouseEvent } from "react";
2
- import { getSourceBlockMap } from "./reactDocumentMetadata";
3
- import type { ReaderDocument, SourceBlock } from "./types";
4
-
5
- const DEFAULT_INSPECTOR_STORAGE_KEY = "openpress:inspector-mode";
6
-
7
- export type InspectorIntent = "edit" | "delete" | "add";
8
- export type InspectorPlacement = "block" | "before";
9
-
10
- export interface InspectorTarget {
11
- blockId: string;
12
- placement: InspectorPlacement;
13
- }
14
-
15
- export interface InspectorState {
16
- enabled: boolean;
17
- inspectorMode: boolean;
18
- selectedBlockId: string | null;
19
- selectedBlock: SourceBlock | null;
20
- selectedTarget: InspectorTarget | null;
21
- commentIntent: InspectorIntent;
22
- setInspectorMode: (enabled: boolean) => void;
23
- toggleInspectorMode: () => void;
24
- setCommentIntent: (intent: InspectorIntent) => void;
25
- selectTarget: (target: InspectorTarget | null) => SourceBlock | null;
26
- inspectTarget: (target: EventTarget | null) => SourceBlock | null;
27
- handleClick: (event: ReactMouseEvent) => boolean;
28
- }
29
-
30
- export interface InspectorCommentResult {
31
- ok: boolean;
32
- comment?: {
33
- id?: string;
34
- timestamp?: string;
35
- path?: string;
36
- line?: number;
37
- note?: string;
38
- hint?: string;
39
- };
40
- message?: string;
41
- }
42
-
43
- export interface PendingComment {
44
- id: string;
45
- timestamp?: string;
46
- path: string;
47
- absolutePath?: string;
48
- line: number;
49
- marker?: string;
50
- note: string;
51
- hint?: string;
52
- }
53
-
54
- export interface CommentListResult {
55
- ok: boolean;
56
- comments?: PendingComment[];
57
- message?: string;
58
- }
59
-
60
- export interface CommentClearResult {
61
- ok: boolean;
62
- removedCount: number;
63
- comments?: PendingComment[];
64
- message?: string;
65
- }
66
-
67
- export async function submitInspectorComment({
68
- block,
69
- note,
70
- intent,
71
- placement,
72
- endpoint = "/__openpress/comment",
73
- fetchImpl = globalThis.fetch?.bind(globalThis),
74
- }: {
75
- block: SourceBlock | null;
76
- note: string;
77
- intent?: InspectorIntent;
78
- placement?: InspectorPlacement;
79
- endpoint?: string;
80
- fetchImpl?: typeof fetch;
81
- }): Promise<InspectorCommentResult> {
82
- if (!block) throw new Error("OpenPress inspector comment requires a selected block.");
83
- const normalizedNote = note.trim();
84
- if (!normalizedNote) throw new Error("OpenPress inspector comment note must not be empty.");
85
- if (!block.path || !block.source?.line) throw new Error("OpenPress inspector selected block has no editable source location.");
86
- if (typeof fetchImpl !== "function") throw new Error("OpenPress inspector comment endpoint is unavailable.");
87
-
88
- const response = await fetchImpl(endpoint, {
89
- method: "POST",
90
- headers: { "Content-Type": "application/json" },
91
- body: JSON.stringify({
92
- target: {
93
- blockId: block.id,
94
- path: block.path,
95
- source: block.source,
96
- },
97
- note: normalizedNote,
98
- hint: formatInspectorHint({ intent, placement }),
99
- }),
100
- });
101
- const result = await response.json().catch(() => null) as InspectorCommentResult | null;
102
- if (!response.ok) {
103
- throw new Error(result?.message ?? `OpenPress inspector comment failed with status ${response.status}`);
104
- }
105
- return result ?? { ok: true };
106
- }
107
-
108
- export async function fetchInspectorComments({
109
- endpoint = "/__openpress/comment",
110
- fetchImpl = globalThis.fetch?.bind(globalThis),
111
- }: {
112
- endpoint?: string;
113
- fetchImpl?: typeof fetch;
114
- } = {}): Promise<PendingComment[]> {
115
- if (typeof fetchImpl !== "function") throw new Error("OpenPress inspector comment endpoint is unavailable.");
116
-
117
- const response = await fetchImpl(endpoint, { method: "GET" });
118
- const result = await response.json().catch(() => null) as CommentListResult | null;
119
- if (!response.ok) {
120
- throw new Error(result?.message ?? `OpenPress inspector comment list failed with status ${response.status}`);
121
- }
122
- return Array.isArray(result?.comments) ? result.comments : [];
123
- }
124
-
125
- export async function clearInspectorComment({
126
- id,
127
- all = false,
128
- endpoint = "/__openpress/comment",
129
- fetchImpl = globalThis.fetch?.bind(globalThis),
130
- }: {
131
- id?: string;
132
- all?: boolean;
133
- endpoint?: string;
134
- fetchImpl?: typeof fetch;
135
- } = {}): Promise<CommentClearResult> {
136
- if (typeof fetchImpl !== "function") throw new Error("OpenPress inspector comment endpoint is unavailable.");
137
- if (!all && !id) throw new Error("OpenPress inspector comment clear requires an id or all=true.");
138
-
139
- const response = await fetchImpl(endpoint, {
140
- method: "DELETE",
141
- headers: { "Content-Type": "application/json" },
142
- body: JSON.stringify(all ? { all: true } : { id }),
143
- });
144
- const result = await response.json().catch(() => null) as CommentClearResult | null;
145
- if (!response.ok) {
146
- throw new Error(result?.message ?? `OpenPress inspector comment clear failed with status ${response.status}`);
147
- }
148
- return result ?? { ok: true, removedCount: 0 };
149
- }
150
-
151
- export async function updateInspectorComment({
152
- id,
153
- note,
154
- intent,
155
- placement,
156
- endpoint = "/__openpress/comment",
157
- fetchImpl = globalThis.fetch?.bind(globalThis),
158
- }: {
159
- id: string;
160
- note: string;
161
- intent?: InspectorIntent;
162
- placement?: InspectorPlacement;
163
- endpoint?: string;
164
- fetchImpl?: typeof fetch;
165
- }): Promise<InspectorCommentResult> {
166
- const normalizedNote = note.trim();
167
- if (!id.trim()) throw new Error("OpenPress inspector comment update requires an id.");
168
- if (!normalizedNote) throw new Error("OpenPress inspector comment note must not be empty.");
169
- if (typeof fetchImpl !== "function") throw new Error("OpenPress inspector comment endpoint is unavailable.");
170
-
171
- const response = await fetchImpl(endpoint, {
172
- method: "PATCH",
173
- headers: { "Content-Type": "application/json" },
174
- body: JSON.stringify({
175
- id,
176
- note: normalizedNote,
177
- hint: formatInspectorHint({ intent, placement }),
178
- }),
179
- });
180
- const result = await response.json().catch(() => null) as InspectorCommentResult | null;
181
- if (!response.ok) {
182
- throw new Error(result?.message ?? `OpenPress inspector comment update failed with status ${response.status}`);
183
- }
184
- return result ?? { ok: true };
185
- }
186
-
187
- export function useInspector(
188
- document: ReaderDocument,
189
- {
190
- enabled = false,
191
- storageKey = DEFAULT_INSPECTOR_STORAGE_KEY,
192
- }: {
193
- enabled?: boolean;
194
- storageKey?: string;
195
- } = {},
196
- ): InspectorState {
197
- const blockMap = useMemo(() => getSourceBlockMap(document), [document]);
198
- const [inspectorMode, setInspectorModeState] = useState(() => {
199
- if (!enabled || typeof window === "undefined") return false;
200
- return window.localStorage.getItem(storageKey) === "on";
201
- });
202
- const [selectedTarget, setSelectedTarget] = useState<InspectorTarget | null>(null);
203
- const [commentIntent, setCommentIntent] = useState<InspectorIntent>("edit");
204
-
205
- useEffect(() => {
206
- if (!enabled && inspectorMode) setInspectorModeState(false);
207
- }, [enabled, inspectorMode]);
208
-
209
- const setInspectorMode = useCallback((nextEnabled: boolean) => {
210
- setInspectorModeState(nextEnabled);
211
- if (typeof window !== "undefined") {
212
- window.localStorage.setItem(storageKey, nextEnabled ? "on" : "off");
213
- }
214
- if (!nextEnabled) setSelectedTarget(null);
215
- }, [storageKey]);
216
-
217
- const selectTarget = useCallback((target: InspectorTarget | null) => {
218
- setSelectedTarget(target);
219
- if (!target) return null;
220
- setCommentIntent(target.placement === "before" ? "add" : "edit");
221
- const sourceBlock = blockMap[target.blockId] ?? null;
222
- return sourceBlock;
223
- }, [blockMap]);
224
-
225
- const inspectTarget = useCallback((target: EventTarget | null) => {
226
- const inspectorTarget = findInspectorTarget(target);
227
- return selectTarget(inspectorTarget);
228
- }, [selectTarget]);
229
-
230
- const handleClick = useCallback((event: ReactMouseEvent) => {
231
- if (!enabled || !inspectorMode) return false;
232
- const inspectorTarget = findInspectorTarget(event.target);
233
- if (!inspectorTarget) return false;
234
- selectTarget(inspectorTarget);
235
- event.preventDefault();
236
- event.stopPropagation();
237
- return true;
238
- }, [enabled, inspectorMode, selectTarget]);
239
-
240
- const selectedBlockId = selectedTarget?.blockId ?? null;
241
- const selectedBlock = selectedBlockId ? (blockMap[selectedBlockId] ?? null) : null;
242
-
243
- return {
244
- enabled,
245
- inspectorMode: enabled && inspectorMode,
246
- selectedBlockId,
247
- selectedBlock,
248
- selectedTarget,
249
- commentIntent,
250
- setInspectorMode,
251
- toggleInspectorMode: () => setInspectorMode(!inspectorMode),
252
- setCommentIntent,
253
- selectTarget,
254
- inspectTarget,
255
- handleClick,
256
- };
257
- }
258
-
259
- export function findInspectorTarget(target: EventTarget | null): InspectorTarget | null {
260
- if (typeof Element === "undefined") return null;
261
- if (!(target instanceof Element)) return null;
262
- const insertTarget = target.closest<HTMLElement>("[data-openpress-insert-before-block-id]");
263
- const insertBeforeBlockId = insertTarget?.dataset.openpressInsertBeforeBlockId;
264
- if (insertBeforeBlockId) return { blockId: insertBeforeBlockId, placement: "before" };
265
-
266
- const element = target.closest<HTMLElement>("[data-openpress-block-id]");
267
- const blockId = element?.dataset.openpressBlockId;
268
- return blockId ? { blockId, placement: "block" } : null;
269
- }
270
-
271
- export function formatInspectorHint({
272
- intent,
273
- placement,
274
- }: {
275
- intent?: InspectorIntent;
276
- placement?: InspectorPlacement;
277
- } = {}) {
278
- const parts = ["openpress-react-inspector"];
279
- if (intent) parts.push(`intent=${intent}`);
280
- if (placement) parts.push(`placement=${placement}`);
281
- return parts.join(" ");
282
- }