@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,4 +1,5 @@
1
1
  import type { HTMLAttributes, ReactNode } from "react";
2
+ import type { EditableSourceRef, ObjectEntityKind } from "../document-model/documentTypes";
2
3
 
3
4
  // ---------------------------------------------------------------------------
4
5
  // Frame / MdxArea / Press primitives
@@ -25,8 +26,72 @@ export type MdxAreaProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
25
26
  className?: string;
26
27
  };
27
28
 
29
+ // PageGeometry — a custom fixed-size geometry passed to <Press page>.
30
+ // Same shape as the engine's normalized geometry (CSS lengths,
31
+ // matching units between width / height).
32
+ export interface PageGeometry {
33
+ id?: string;
34
+ label?: string;
35
+ preset?: string;
36
+ width: string;
37
+ height: string;
38
+ }
39
+
40
+ // Source descriptor passed inside <Press sources>. The actual type is
41
+ // the return value of mdxSource() from @open-press/core/mdx; we accept
42
+ // "unknown" at the core boundary to avoid a circular type dependency.
43
+ // The engine validates the shape at render time.
44
+ export type PressSource = unknown;
45
+
28
46
  export interface PressProps {
47
+ // Document tree — Frames, manuscript helpers, etc.
48
+ children: ReactNode;
49
+ // -------------------------------------------------------------------------
50
+ // 1.0 metadata props — optional during v0.x deprecation, required in v1.0.
51
+ // -------------------------------------------------------------------------
52
+ // Document title. Required in 1.0. Used for PDF metadata, HTML <title>,
53
+ // OG tags, and the Workspace gallery / tab-bar label.
54
+ title?: string;
55
+ // Page geometry preset name or a custom geometry object. Optional;
56
+ // workspace default applies if not set.
57
+ page?: "a4" | "social-square" | "slide-16-9" | PageGeometry;
58
+ // Array of source registrations from mdxSource(). Replaces the v0.x
59
+ // `export const sources` named export.
60
+ sources?: ReadonlyArray<PressSource>;
61
+ // URL / output slug for this Press inside a Workspace. Defaults to
62
+ // "/" when only one Press exists in the Workspace; required when the
63
+ // Workspace has multiple Press children.
64
+ slug?: string;
65
+ // Optional per-Press theme directory. Defaults to "./theme" relative
66
+ // to the document file; inherits from <Workspace theme> if not set.
67
+ theme?: string;
68
+ // Optional per-Press components directory. Default "./components".
69
+ componentsDir?: string;
70
+ // Optional caption numbering overrides. Engine defaults to
71
+ // { figure: "Figure", table: "Table", separator: " " }.
72
+ captionNumbering?: {
73
+ figure?: string;
74
+ table?: string;
75
+ separator?: string;
76
+ };
77
+ }
78
+
79
+ // ---------------------------------------------------------------------------
80
+ // Workspace — root component holding one or more Press children
81
+ // ---------------------------------------------------------------------------
82
+
83
+ export interface WorkspaceProps {
84
+ // One or more <Press> children. 1 child = single-doc workspace; N
85
+ // children = multi-doc workspace (proposal + pitch + social, etc).
29
86
  children: ReactNode;
87
+ // Project label surfaced in the gallery header, tab bar, and PDF
88
+ // metadata. Optional.
89
+ name?: string;
90
+ // Workspace-level shared theme directory. Press children that don't
91
+ // set their own `theme` prop inherit from this. Default "./theme".
92
+ theme?: string;
93
+ // Workspace-level shared media directory. Default "./media".
94
+ media?: string;
30
95
  }
31
96
 
32
97
  // ---------------------------------------------------------------------------
@@ -38,6 +103,14 @@ export type BaseFigureProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
38
103
  children: ReactNode;
39
104
  };
40
105
 
106
+ export type MediaFigureProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
107
+ src: string;
108
+ alt: string;
109
+ caption: ReactNode;
110
+ imgClassName?: string;
111
+ loading?: "eager" | "lazy";
112
+ };
113
+
41
114
  export type BaseCalloutKind = "info" | "warn" | "success" | "error" | (string & {});
42
115
 
43
116
  export type BaseCalloutProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
@@ -45,6 +118,27 @@ export type BaseCalloutProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
45
118
  children: ReactNode;
46
119
  };
47
120
 
121
+ export type ObjectEntityElement = "span" | "div" | "section" | "article" | "figure" | "p";
122
+
123
+ export type ObjectEntityProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
124
+ as?: ObjectEntityElement;
125
+ objectId: string;
126
+ kind: ObjectEntityKind;
127
+ label: string;
128
+ parentId?: string;
129
+ pageId?: string;
130
+ blockId?: string;
131
+ frameKey?: string;
132
+ chainId?: string;
133
+ source?: EditableSourceRef;
134
+ metadata?: Record<string, string | number | boolean | null>;
135
+ children?: ReactNode;
136
+ };
137
+
138
+ export type TextProps = Omit<ObjectEntityProps, "kind"> & {
139
+ as?: "span" | "div" | "p";
140
+ };
141
+
48
142
  // ---------------------------------------------------------------------------
49
143
  // Source descriptors and resolved sources
50
144
  // ---------------------------------------------------------------------------
@@ -140,44 +234,3 @@ export interface ResolvedSource {
140
234
  // MdxArea by area index.
141
235
  export type FrameAllocation = Record<string, Record<string, ReactNode[]>>;
142
236
 
143
- // ---------------------------------------------------------------------------
144
- // Manifest
145
- // ---------------------------------------------------------------------------
146
-
147
- export interface Manifest {
148
- title: string;
149
- subtitle?: string;
150
- organization?: string;
151
- workspaceLabel?: string;
152
- documentDir?: string;
153
- sourceDir?: string;
154
- componentsDir?: string;
155
- mediaDir?: string;
156
- themeDir?: string;
157
- designDoc?: string;
158
- publicDir?: string;
159
- outputDir?: string;
160
- captionNumbering?: {
161
- figure?: string;
162
- table?: string;
163
- separator?: string;
164
- };
165
- pdf?: {
166
- filename?: string;
167
- };
168
- deploy?: {
169
- adapter?: string;
170
- source?: string;
171
- projectName?: string | null;
172
- commitDirty?: boolean;
173
- requiresConfirmation?: boolean;
174
- };
175
- paths?: {
176
- chaptersDir?: string;
177
- sourceDir?: string;
178
- componentsDir?: string;
179
- mediaDir?: string;
180
- themeDir?: string;
181
- designDoc?: string;
182
- };
183
- }
@@ -21,7 +21,7 @@ export function useSource<T extends ResolvedSource = ResolvedSource>(id: string)
21
21
  const knownText = known.length > 0 ? known.join(", ") : "(none)";
22
22
  throw new Error(
23
23
  `Unknown source "${id}". Available sources: ${knownText}. ` +
24
- `Register it under \`export const sources\` in document/index.tsx.`,
24
+ `Register it as a <Press sources={[mdxSource({ id: "${id}", ... })]}> entry in press/index.tsx.`,
25
25
  );
26
26
  }
27
27
  return source as T;
@@ -3,7 +3,7 @@
3
3
  // `PublicPage` / `HtmlWorkbench` HMR-clean (Fast Refresh expects component
4
4
  // files to export only components).
5
5
 
6
- import type { DisplayPage } from "./workbenchTypes";
6
+ import type { DisplayPage } from "../reader";
7
7
 
8
8
  export function createAnchorPageMap(pages: DisplayPage[]) {
9
9
  const map = new Map<string, number>();
@@ -1,4 +1,4 @@
1
- import type { BlockSource } from "./types";
1
+ import type { BlockSource } from "./documentTypes";
2
2
 
3
3
  export type MediaAssetKind = "image" | "svg";
4
4
 
@@ -25,6 +25,7 @@ export interface DocumentSource {
25
25
  editMode?: string;
26
26
  styles?: DocumentStyle[];
27
27
  blockMap?: Record<string, SourceBlock>;
28
+ objectEntities?: Record<string, ObjectEntity>;
28
29
  }
29
30
 
30
31
  export interface DocumentStyle {
@@ -49,6 +50,9 @@ export interface SourceBlock {
49
50
  pageIndex?: number;
50
51
  pageNumber?: number;
51
52
  source?: SourceLocation;
53
+ frameKey?: string;
54
+ chainId?: string;
55
+ sectionSlug?: string;
52
56
  }
53
57
 
54
58
  export interface DocumentMeta {
@@ -61,8 +65,12 @@ export interface DocumentMeta {
61
65
  }
62
66
 
63
67
  export interface Theme {
68
+ pagePreset?: string;
69
+ pageLabel?: string;
64
70
  pageWidth?: string;
65
71
  pageHeight?: string;
72
+ pageAspectRatio?: string;
73
+ pageHeightRatio?: string;
66
74
  pagePadding?: string;
67
75
  fontFamily?: string;
68
76
  accentColor?: string;
@@ -93,4 +101,47 @@ export interface HtmlPageBlock {
93
101
  anchors?: string[];
94
102
  className?: string;
95
103
  source?: BlockSource;
104
+ frameKey?: string;
105
+ role?: string | null;
106
+ chrome?: boolean;
107
+ blockIds?: string[];
108
+ }
109
+
110
+ export type ObjectEntityKind =
111
+ | "page"
112
+ | "frame"
113
+ | "mdx-area"
114
+ | "mdx-block"
115
+ | "text"
116
+ | "component"
117
+ | "media";
118
+
119
+ export interface EditableSourceRef {
120
+ path: string;
121
+ file?: string;
122
+ kind?: string;
123
+ objectId?: string;
124
+ scope?: string;
125
+ component?: string;
126
+ source?: SourceLocation;
127
+ line?: number;
128
+ column?: number;
129
+ }
130
+
131
+ export interface ObjectEntityRef {
132
+ id: string;
133
+ kind: ObjectEntityKind;
134
+ }
135
+
136
+ export interface ObjectEntity {
137
+ id: string;
138
+ kind: ObjectEntityKind;
139
+ label: string;
140
+ parentId?: string;
141
+ pageId?: string;
142
+ blockId?: string;
143
+ frameKey?: string;
144
+ chainId?: string;
145
+ source?: EditableSourceRef;
146
+ metadata?: Record<string, string | number | boolean | null>;
96
147
  }
@@ -0,0 +1,7 @@
1
+ export * from "./anchorMapModel";
2
+ export * from "./documentIndexes";
3
+ export * from "./documentTypes";
4
+ export * from "./objectEntityModel";
5
+ export * from "./projectIdentityModel";
6
+ export * from "./reactDocumentMetadataModel";
7
+ export * from "./workspaceManifestModel";
@@ -0,0 +1,55 @@
1
+ import type { ObjectEntity, ObjectEntityKind, ReaderDocument, SourceBlock } from "./documentTypes";
2
+
3
+ export function createObjectEntityId(kind: ObjectEntityKind, ...parts: Array<string | number>) {
4
+ return [kind, ...parts.map((part) => encodeURIComponent(String(part)))].join(":");
5
+ }
6
+
7
+ export function createScopedObjectEntityId(kind: ObjectEntityKind, parentId: string | undefined, objectId: string) {
8
+ return parentId ? createObjectEntityId(kind, parentId, objectId) : createObjectEntityId(kind, objectId);
9
+ }
10
+
11
+ export function createBlockObjectEntityId(blockId: string) {
12
+ return createObjectEntityId("mdx-block", blockId);
13
+ }
14
+
15
+ export function createFrameObjectEntityId(frameKey: string) {
16
+ return createObjectEntityId("frame", frameKey);
17
+ }
18
+
19
+ export function createPageObjectEntityId(frameKey: string) {
20
+ return createObjectEntityId("page", frameKey);
21
+ }
22
+
23
+ export function createMdxAreaObjectEntityId(frameKey: string, chainId: string, indexInFrame: number) {
24
+ return createObjectEntityId("mdx-area", frameKey, chainId, indexInFrame);
25
+ }
26
+
27
+ export function getObjectEntityMap(document: Pick<ReaderDocument, "source"> | null | undefined): Record<string, ObjectEntity> {
28
+ return document?.source?.objectEntities ?? {};
29
+ }
30
+
31
+ export function getObjectEntity(document: Pick<ReaderDocument, "source"> | null | undefined, objectId: string): ObjectEntity | null {
32
+ return getObjectEntityMap(document)[objectId] ?? null;
33
+ }
34
+
35
+ export function sourceBlockToObjectEntity(block: SourceBlock): ObjectEntity {
36
+ return {
37
+ id: createBlockObjectEntityId(block.id),
38
+ kind: "mdx-block",
39
+ label: block.name ? `${block.name} ${block.id}` : block.id,
40
+ blockId: block.id,
41
+ frameKey: block.frameKey,
42
+ chainId: block.chainId,
43
+ pageId: block.frameKey ? createPageObjectEntityId(block.frameKey) : undefined,
44
+ source: {
45
+ path: block.path,
46
+ source: block.source,
47
+ line: block.source?.line,
48
+ column: block.source?.column,
49
+ },
50
+ metadata: {
51
+ blockKind: block.kind ?? null,
52
+ sectionSlug: block.sectionSlug ?? block.chapterSlug ?? null,
53
+ },
54
+ };
55
+ }
@@ -1,4 +1,4 @@
1
- import type { DocumentMeta } from "./types";
1
+ import type { DocumentMeta } from "./documentTypes";
2
2
 
3
3
  export interface ProjectIdentity {
4
4
  name: string;
@@ -1,7 +1,7 @@
1
1
  import type {
2
2
  ReaderDocument,
3
3
  SourceBlock,
4
- } from "./types";
4
+ } from "./documentTypes";
5
5
 
6
6
  export const PRESS_TREE_MDX_SOURCE_TYPE = "openpress-press-tree-mdx";
7
7
 
@@ -0,0 +1,57 @@
1
+ // Shape of /openpress/workspace.json — the reader fetches this on
2
+ // boot to decide between gallery routing (multi-Press) and direct
3
+ // load (single Press). One entry per <Press> child of <Workspace>.
4
+ //
5
+ // Single-Press workspaces emit one entry with slug = "" and the
6
+ // legacy /openpress/document.json path. Multi-Press emits one entry
7
+ // per slug; each `documentUrl` resolves to /openpress/<slug>/document.json.
8
+
9
+ export interface WorkspaceManifest {
10
+ version: 1;
11
+ // <Workspace name="..."> prop. Null when the user did not set one.
12
+ // Surfaced as the gallery header in the reader.
13
+ name: string | null;
14
+ presses: WorkspaceManifestPress[];
15
+ }
16
+
17
+ export interface WorkspaceManifestPress {
18
+ // Slug for this Press. Empty string for single-Press workspaces
19
+ // (legacy root); slug-shaped string for multi-Press.
20
+ slug: string;
21
+ // <Press title="..."> prop. Required in v1.0 contract.
22
+ title: string;
23
+ // Page geometry summary. Same shape as the reader's
24
+ // ReaderDocument.theme — readers can show a thumb in the gallery
25
+ // without loading the full document.json.
26
+ page: {
27
+ pagePreset?: string;
28
+ pageLabel?: string;
29
+ pageWidth?: string;
30
+ pageHeight?: string;
31
+ pageAspectRatio?: string;
32
+ pageHeightRatio?: string;
33
+ } | null;
34
+ // Number of pages produced for this Press.
35
+ pageCount: number;
36
+ // Absolute path the reader fetches for this Press's full document.json.
37
+ documentUrl: string;
38
+ }
39
+
40
+ // True when the reader should render the gallery first instead of
41
+ // going straight into a single Press's document.
42
+ export function manifestHasMultiplePresses(manifest: WorkspaceManifest): boolean {
43
+ return manifest.presses.length > 1;
44
+ }
45
+
46
+ // Find a Press entry by slug. Returns null when the slug is unknown.
47
+ export function findManifestPress(
48
+ manifest: WorkspaceManifest,
49
+ slug: string,
50
+ ): WorkspaceManifestPress | null {
51
+ const normalized = slug.replace(/^\/+|\/+$/g, "");
52
+ for (const press of manifest.presses) {
53
+ const normalizedSlug = press.slug.replace(/^\/+|\/+$/g, "");
54
+ if (normalizedSlug === normalized) return press;
55
+ }
56
+ return null;
57
+ }
@@ -9,9 +9,10 @@
9
9
  // document type that wants section flow imports from here; documents that
10
10
  // do not (slides, folios, calendars) skip this module entirely.
11
11
 
12
- import { Fragment, useContext, type ReactNode } from "react";
13
- import { Frame, FrameContext, PressContext, useSource } from "../core";
12
+ import { Fragment, useContext, type ComponentType, type ReactNode } from "react";
13
+ import { Frame, FrameContext, MdxArea, PressContext, useSource } from "../core";
14
14
  import type { MdxAreaOverflow, ResolvedSource } from "../core";
15
+ import { createMdxAreaObjectEntityId } from "../document-model/objectEntityModel";
15
16
 
16
17
  // ---------------------------------------------------------------------------
17
18
  // <Sections>
@@ -38,11 +39,11 @@ export interface SectionsOpenerProps {
38
39
 
39
40
  export interface SectionsProps {
40
41
  source: string;
41
- page: React.ComponentType<SectionsPageProps>;
42
- opener?: React.ComponentType<SectionsOpenerProps>;
42
+ page?: ComponentType<SectionsPageProps>;
43
+ opener?: ComponentType<SectionsOpenerProps>;
43
44
  }
44
45
 
45
- export function Sections({ source: sourceId, page: Page, opener: Opener }: SectionsProps) {
46
+ export function Sections({ source: sourceId, page: Page = DefaultSectionPage, opener: Opener }: SectionsProps) {
46
47
  const source = useSource(sourceId);
47
48
  const press = useContext(PressContext);
48
49
  const hints = press?.hints ?? null;
@@ -92,6 +93,41 @@ export function Sections({ source: sourceId, page: Page, opener: Opener }: Secti
92
93
  export const Chapters = Sections;
93
94
  export type ChaptersProps = SectionsProps;
94
95
 
96
+ export function DefaultSectionPage({
97
+ frameKey,
98
+ chainId,
99
+ pageIndex,
100
+ totalPages,
101
+ sectionSlug,
102
+ sectionTitle,
103
+ sectionTone,
104
+ }: SectionsPageProps) {
105
+ return (
106
+ <Frame
107
+ frameKey={frameKey}
108
+ role="manuscript.content"
109
+ className="reader-page--content"
110
+ data-page-index={pageIndex}
111
+ data-total-pages={totalPages}
112
+ data-section-id={sectionSlug}
113
+ data-chapter-tone={sectionTone}
114
+ >
115
+ <div className="page-frame">
116
+ <header className="page-header" aria-hidden="true" />
117
+ <main className="page-body">
118
+ <MdxArea chainId={chainId} />
119
+ </main>
120
+ <footer className="page-footer" aria-hidden="true">
121
+ <span className="footer-left">{sectionTitle}</span>
122
+ <span className="footer-right">
123
+ {totalPages > 1 ? `${pageIndex + 1}/${totalPages}` : pageIndex + 1}
124
+ </span>
125
+ </footer>
126
+ </div>
127
+ </Frame>
128
+ );
129
+ }
130
+
95
131
  // ---------------------------------------------------------------------------
96
132
  // <Toc>
97
133
  // ---------------------------------------------------------------------------
@@ -178,15 +214,21 @@ function DefaultTocPage({ frameKey, chainId, pageIndex, totalPages, heading, cla
178
214
 
179
215
  export function TocArea({ chainId, maxLevel, overflow = "extend", className }: TocAreaProps) {
180
216
  const frame = useContext(FrameContext);
181
- const blocks = frame?.consumeArea(chainId) ?? null;
217
+ const consumed = frame?.consumeArea(chainId) ?? null;
218
+ const blocks = consumed?.blocks ?? null;
219
+ const objectId = frame && consumed
220
+ ? createMdxAreaObjectEntityId(frame.frameKey, chainId, consumed.indexInFrame)
221
+ : undefined;
182
222
  return (
183
223
  <div
184
224
  className="openpress-mdx-area openpress-toc-area"
185
225
  data-openpress-mdx-area="true"
186
226
  data-openpress-mdx-area-chain={chainId}
227
+ data-openpress-mdx-area-index={consumed?.indexInFrame}
228
+ data-openpress-object-id={objectId}
187
229
  data-openpress-toc-max-level={maxLevel}
188
230
  data-openpress-mdx-area-overflow={overflow}
189
- data-openpress-mdx-area-empty={blocks == null ? "true" : undefined}
231
+ data-openpress-mdx-area-empty={blocks == null ? "true" : "false"}
190
232
  >
191
233
  <ol className={["toc-list", className].filter(Boolean).join(" ") || undefined}>
192
234
  {blocks}
@@ -27,14 +27,17 @@ export type {
27
27
  SourceNode,
28
28
  } from "../core/types";
29
29
 
30
+ // All presets accept an optional `id` for the 1.0 contract where sources
31
+ // are an array passed via <Press sources>. In v0.x the id came from the
32
+ // record key in `export const sources = { story: mdxSource(...) }`.
30
33
  type MdxSourceOptions =
31
- | { preset: "section-folders"; root?: string }
32
- | { preset: "section-files"; root?: string }
33
- | { preset: "file-list"; files: string[] };
34
+ | { id?: string; preset: "section-folders"; root?: string }
35
+ | { id?: string; preset: "section-files"; root?: string }
36
+ | { id?: string; preset: "file-list"; files: string[] };
34
37
 
35
38
  const VALID_PRESETS = new Set(["section-folders", "section-files", "file-list"]);
36
39
 
37
- export function mdxSource(options: MdxSourceOptions): MdxSourceDescriptor {
40
+ export function mdxSource(options: MdxSourceOptions): MdxSourceDescriptor & { id?: string } {
38
41
  if (!options || typeof options !== "object") {
39
42
  throw new Error("mdxSource() requires an options object.");
40
43
  }
@@ -46,11 +49,15 @@ export function mdxSource(options: MdxSourceOptions): MdxSourceDescriptor {
46
49
  );
47
50
  }
48
51
 
52
+ const id = typeof options.id === "string" && options.id.trim() ? options.id.trim() : undefined;
53
+
49
54
  if (options.preset === "section-folders") {
50
- return normalizeRooted("section-folders", options.root, "chapters") as MdxSourceDescriptorSectionFolders;
55
+ const desc = normalizeRooted("section-folders", options.root, "chapters") as MdxSourceDescriptorSectionFolders;
56
+ return id ? { ...desc, id } : desc;
51
57
  }
52
58
  if (options.preset === "section-files") {
53
- return normalizeRooted("section-files", options.root, "content") as MdxSourceDescriptorSectionFiles;
59
+ const desc = normalizeRooted("section-files", options.root, "content") as MdxSourceDescriptorSectionFiles;
60
+ return id ? { ...desc, id } : desc;
54
61
  }
55
62
 
56
63
  // file-list
@@ -69,7 +76,8 @@ export function mdxSource(options: MdxSourceOptions): MdxSourceDescriptor {
69
76
  if (files.length === 0) {
70
77
  throw new Error('mdxSource({ preset: "file-list" }) requires at least one file.');
71
78
  }
72
- return { type: "mdx", preset: "file-list", files };
79
+ const desc: MdxSourceDescriptor = { type: "mdx", preset: "file-list", files };
80
+ return id ? { ...desc, id } : desc;
73
81
  }
74
82
 
75
83
  function normalizeRooted(