@open-press/cli 0.8.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/README.md +33 -23
  2. package/dist/cli.js +320 -252
  3. package/package.json +9 -8
  4. package/template/core/AGENTS.md +0 -126
  5. package/template/core/CHANGELOG.md +0 -215
  6. package/template/core/README.md +0 -40
  7. package/template/core/engine/cli.mjs +0 -96
  8. package/template/core/engine/commands/_shared.mjs +0 -177
  9. package/template/core/engine/commands/deploy.mjs +0 -31
  10. package/template/core/engine/commands/dev.mjs +0 -49
  11. package/template/core/engine/commands/doctor.mjs +0 -229
  12. package/template/core/engine/commands/export.mjs +0 -8
  13. package/template/core/engine/commands/init.mjs +0 -24
  14. package/template/core/engine/commands/inspect.mjs +0 -35
  15. package/template/core/engine/commands/pdf.mjs +0 -26
  16. package/template/core/engine/commands/preview.mjs +0 -26
  17. package/template/core/engine/commands/render.mjs +0 -17
  18. package/template/core/engine/commands/replace.mjs +0 -41
  19. package/template/core/engine/commands/search.mjs +0 -33
  20. package/template/core/engine/commands/typecheck.mjs +0 -5
  21. package/template/core/engine/commands/upgrade.mjs +0 -159
  22. package/template/core/engine/commands/validate.mjs +0 -17
  23. package/template/core/engine/document-export.mjs +0 -15
  24. package/template/core/engine/init.mjs +0 -90
  25. package/template/core/engine/output/chrome-pdf.d.mts +0 -34
  26. package/template/core/engine/output/chrome-pdf.mjs +0 -358
  27. package/template/core/engine/output/deploy-sync.mjs +0 -15
  28. package/template/core/engine/output/fonts.mjs +0 -62
  29. package/template/core/engine/output/katex-assets.mjs +0 -45
  30. package/template/core/engine/output/page-block.mjs +0 -30
  31. package/template/core/engine/output/pdf-media.mjs +0 -45
  32. package/template/core/engine/output/public-assets.mjs +0 -19
  33. package/template/core/engine/output/static-server.mjs +0 -532
  34. package/template/core/engine/react/caption-numbering.mjs +0 -73
  35. package/template/core/engine/react/comment-endpoint.d.mts +0 -11
  36. package/template/core/engine/react/comment-endpoint.mjs +0 -102
  37. package/template/core/engine/react/comment-marker.mjs +0 -374
  38. package/template/core/engine/react/document-entry.mjs +0 -324
  39. package/template/core/engine/react/document-export.mjs +0 -373
  40. package/template/core/engine/react/http-json.mjs +0 -24
  41. package/template/core/engine/react/mdx-compile.mjs +0 -599
  42. package/template/core/engine/react/measurement-css.mjs +0 -136
  43. package/template/core/engine/react/object-entities.mjs +0 -119
  44. package/template/core/engine/react/pagination/allocator.mjs +0 -122
  45. package/template/core/engine/react/pagination/regions.mjs +0 -81
  46. package/template/core/engine/react/pagination-constants.mjs +0 -3
  47. package/template/core/engine/react/pagination.mjs +0 -9
  48. package/template/core/engine/react/pipeline/allocate.mjs +0 -251
  49. package/template/core/engine/react/pipeline/final-render.mjs +0 -94
  50. package/template/core/engine/react/pipeline/frame-measurement.mjs +0 -302
  51. package/template/core/engine/react/pipeline/press-tree.mjs +0 -135
  52. package/template/core/engine/react/project-asset-endpoint.d.mts +0 -10
  53. package/template/core/engine/react/project-asset-endpoint.mjs +0 -361
  54. package/template/core/engine/react/section-css.mjs +0 -56
  55. package/template/core/engine/react/source-edit-endpoint.d.mts +0 -10
  56. package/template/core/engine/react/source-edit-endpoint.mjs +0 -75
  57. package/template/core/engine/react/sources/heading-numbering.mjs +0 -132
  58. package/template/core/engine/react/sources/mdx-resolver.mjs +0 -439
  59. package/template/core/engine/react/style-discovery.mjs +0 -142
  60. package/template/core/engine/runtime/config.d.mts +0 -40
  61. package/template/core/engine/runtime/config.mjs +0 -175
  62. package/template/core/engine/runtime/file-utils.mjs +0 -106
  63. package/template/core/engine/runtime/file-walk.mjs +0 -22
  64. package/template/core/engine/runtime/inspection.mjs +0 -328
  65. package/template/core/engine/runtime/issue-report.mjs +0 -44
  66. package/template/core/engine/runtime/path-utils.mjs +0 -20
  67. package/template/core/engine/runtime/source-text-tools.d.mts +0 -102
  68. package/template/core/engine/runtime/source-text-tools.mjs +0 -832
  69. package/template/core/engine/runtime/source-workspace.mjs +0 -159
  70. package/template/core/engine/runtime/validation.mjs +0 -174
  71. package/template/core/index.html +0 -13
  72. package/template/core/openpress.config.mjs +0 -12
  73. package/template/core/package.json +0 -91
  74. package/template/core/src/main.tsx +0 -16
  75. package/template/core/src/openpress/app/OpenPressApp.tsx +0 -140
  76. package/template/core/src/openpress/app/OpenPressRuntime.tsx +0 -94
  77. package/template/core/src/openpress/app/index.ts +0 -2
  78. package/template/core/src/openpress/core/Frame.tsx +0 -78
  79. package/template/core/src/openpress/core/FrameContext.tsx +0 -24
  80. package/template/core/src/openpress/core/MdxArea.tsx +0 -34
  81. package/template/core/src/openpress/core/Press.tsx +0 -34
  82. package/template/core/src/openpress/core/cn.ts +0 -4
  83. package/template/core/src/openpress/core/index.tsx +0 -40
  84. package/template/core/src/openpress/core/primitives.tsx +0 -44
  85. package/template/core/src/openpress/core/types.ts +0 -191
  86. package/template/core/src/openpress/core/useSource.ts +0 -28
  87. package/template/core/src/openpress/document-model/anchorMapModel.ts +0 -27
  88. package/template/core/src/openpress/document-model/documentIndexes.ts +0 -329
  89. package/template/core/src/openpress/document-model/documentTypes.ts +0 -138
  90. package/template/core/src/openpress/document-model/index.ts +0 -6
  91. package/template/core/src/openpress/document-model/objectEntityModel.ts +0 -51
  92. package/template/core/src/openpress/document-model/projectIdentityModel.ts +0 -15
  93. package/template/core/src/openpress/document-model/reactDocumentMetadataModel.ts +0 -27
  94. package/template/core/src/openpress/manuscript/index.tsx +0 -238
  95. package/template/core/src/openpress/mdx/index.ts +0 -88
  96. package/template/core/src/openpress/numbering/index.ts +0 -294
  97. package/template/core/src/openpress/reader/PublicReaderPage.tsx +0 -267
  98. package/template/core/src/openpress/reader/ReaderNavigationPanel.tsx +0 -123
  99. package/template/core/src/openpress/reader/index.ts +0 -10
  100. package/template/core/src/openpress/reader/pageViewportScaleModel.ts +0 -73
  101. package/template/core/src/openpress/reader/readerPageRegistry.ts +0 -41
  102. package/template/core/src/openpress/reader/readerPageRoute.ts +0 -21
  103. package/template/core/src/openpress/reader/readerScroll.ts +0 -92
  104. package/template/core/src/openpress/reader/readerStateModel.ts +0 -15
  105. package/template/core/src/openpress/reader/readerTypes.ts +0 -4
  106. package/template/core/src/openpress/reader/usePageViewportScale.ts +0 -119
  107. package/template/core/src/openpress/reader/usePanelState.ts +0 -56
  108. package/template/core/src/openpress/reader/useReaderHashSync.ts +0 -61
  109. package/template/core/src/openpress/reader/useReaderKeyboardNav.ts +0 -48
  110. package/template/core/src/openpress/reader/useReaderRuntime.ts +0 -146
  111. package/template/core/src/openpress/reader/useReaderScrollAnchor.ts +0 -64
  112. package/template/core/src/openpress/shared/Panel.tsx +0 -77
  113. package/template/core/src/openpress/shared/frameScheduler.ts +0 -32
  114. package/template/core/src/openpress/shared/index.ts +0 -4
  115. package/template/core/src/openpress/shared/numberUtils.ts +0 -3
  116. package/template/core/src/openpress/shared/runtimeMode.ts +0 -11
  117. package/template/core/src/openpress/workbench/Workbench.tsx +0 -407
  118. package/template/core/src/openpress/workbench/actions/DeploymentControl.tsx +0 -157
  119. package/template/core/src/openpress/workbench/actions/PageZoomControl.tsx +0 -182
  120. package/template/core/src/openpress/workbench/actions/SearchControl.tsx +0 -345
  121. package/template/core/src/openpress/workbench/actions/deploymentStatusModel.ts +0 -112
  122. package/template/core/src/openpress/workbench/actions/index.ts +0 -5
  123. package/template/core/src/openpress/workbench/actions/useDeploymentWorkbench.ts +0 -136
  124. package/template/core/src/openpress/workbench/dialog/WorkbenchDialog.tsx +0 -72
  125. package/template/core/src/openpress/workbench/dialog/index.ts +0 -1
  126. package/template/core/src/openpress/workbench/document/components/DocumentPanel.tsx +0 -127
  127. package/template/core/src/openpress/workbench/document/components/InlineSourceEditorLayer.tsx +0 -207
  128. package/template/core/src/openpress/workbench/document/components/ReaderStage.tsx +0 -9
  129. package/template/core/src/openpress/workbench/document/hooks/useDocumentWorkbenchModel.ts +0 -34
  130. package/template/core/src/openpress/workbench/document/hooks/useInlineDocumentEditor.ts +0 -525
  131. package/template/core/src/openpress/workbench/document/index.ts +0 -10
  132. package/template/core/src/openpress/workbench/index.ts +0 -2
  133. package/template/core/src/openpress/workbench/inspector/InlineInspectorLayer.tsx +0 -459
  134. package/template/core/src/openpress/workbench/inspector/index.ts +0 -5
  135. package/template/core/src/openpress/workbench/inspector/inlineCommentModel.ts +0 -125
  136. package/template/core/src/openpress/workbench/inspector/inspectorGeometryModel.ts +0 -160
  137. package/template/core/src/openpress/workbench/inspector/inspectorModel.ts +0 -408
  138. package/template/core/src/openpress/workbench/inspector/useInspectorComments.ts +0 -248
  139. package/template/core/src/openpress/workbench/mentions/MentionSuggestionList.tsx +0 -41
  140. package/template/core/src/openpress/workbench/mentions/index.ts +0 -2
  141. package/template/core/src/openpress/workbench/mentions/useComposerMentions.ts +0 -185
  142. package/template/core/src/openpress/workbench/panels/Panel.tsx +0 -1
  143. package/template/core/src/openpress/workbench/panels/PendingCommentsPanel.tsx +0 -76
  144. package/template/core/src/openpress/workbench/panels/WorkbenchControlPanel.tsx +0 -29
  145. package/template/core/src/openpress/workbench/panels/index.ts +0 -3
  146. package/template/core/src/openpress/workbench/project/ProjectEntryPanel.tsx +0 -523
  147. package/template/core/src/openpress/workbench/project/ProjectPreviewDialog.tsx +0 -35
  148. package/template/core/src/openpress/workbench/project/index.ts +0 -2
  149. package/template/core/src/openpress/workbench/project/projectPreviewTypes.ts +0 -11
  150. package/template/core/src/openpress/workbench/project/projectSourceModel.ts +0 -24
  151. package/template/core/src/openpress/workbench/shell/WorkbenchShell.tsx +0 -167
  152. package/template/core/src/openpress/workbench/shell/index.ts +0 -1
  153. package/template/core/src/openpress/workbench/workbenchFormatters.ts +0 -120
  154. package/template/core/src/openpress/workbench/workbenchTypes.ts +0 -35
  155. package/template/core/src/styles/openpress/app-shell.css +0 -251
  156. package/template/core/src/styles/openpress/media-workspace.css +0 -230
  157. package/template/core/src/styles/openpress/print-route.css +0 -184
  158. package/template/core/src/styles/openpress/project-preview-panel.css +0 -924
  159. package/template/core/src/styles/openpress/public-viewer.css +0 -688
  160. package/template/core/src/styles/openpress/reader-runtime.css +0 -980
  161. package/template/core/src/styles/openpress/responsive.css +0 -245
  162. package/template/core/src/styles/openpress/workbench-panels.css +0 -594
  163. package/template/core/src/styles/openpress/workbench.css +0 -1255
  164. package/template/core/src/styles/openpress.css +0 -14
  165. package/template/core/src/vite-env.d.ts +0 -9
  166. package/template/core/tsconfig.json +0 -40
  167. package/template/core/vite.config.ts +0 -584
  168. package/template/packs/academic-paper/document/chapters/01-introduction/content/01-introduction.mdx +0 -35
  169. package/template/packs/academic-paper/document/chapters/02-methods/content/01-methods.mdx +0 -50
  170. package/template/packs/academic-paper/document/chapters/03-results-and-discussion/content/01-results.mdx +0 -47
  171. package/template/packs/academic-paper/document/chapters/04-acknowledgment/content/01-acknowledgment.mdx +0 -26
  172. package/template/packs/academic-paper/document/chapters/05-references/content/01-references.mdx +0 -32
  173. package/template/packs/academic-paper/document/components/ChapterOpenerVisual/index.tsx +0 -76
  174. package/template/packs/academic-paper/document/components/Page.tsx +0 -60
  175. package/template/packs/academic-paper/document/components/TokenSwatchGrid/index.tsx +0 -46
  176. package/template/packs/academic-paper/document/components/TokenSwatchGrid/style.css +0 -63
  177. package/template/packs/academic-paper/document/components/TypeSpecimen/index.tsx +0 -38
  178. package/template/packs/academic-paper/document/components/TypeSpecimen/style.css +0 -111
  179. package/template/packs/academic-paper/document/design.md +0 -279
  180. package/template/packs/academic-paper/document/index.tsx +0 -123
  181. package/template/packs/academic-paper/document/media/README.md +0 -13
  182. package/template/packs/academic-paper/document/media/figure-placeholder.svg +0 -9
  183. package/template/packs/academic-paper/document/openpress.config.mjs +0 -26
  184. package/template/packs/academic-paper/document/theme/README.md +0 -11
  185. package/template/packs/academic-paper/document/theme/base/page-contract.css +0 -522
  186. package/template/packs/academic-paper/document/theme/base/print.css +0 -93
  187. package/template/packs/academic-paper/document/theme/base/typography.css +0 -333
  188. package/template/packs/academic-paper/document/theme/fonts.css +0 -3
  189. package/template/packs/academic-paper/document/theme/page-surfaces/back-cover.css +0 -43
  190. package/template/packs/academic-paper/document/theme/page-surfaces/chapter-opener.css +0 -205
  191. package/template/packs/academic-paper/document/theme/page-surfaces/cover.css +0 -294
  192. package/template/packs/academic-paper/document/theme/page-surfaces/toc.css +0 -149
  193. package/template/packs/academic-paper/document/theme/patterns/_chart-frame.css +0 -49
  194. package/template/packs/academic-paper/document/theme/patterns/figure-grid.css +0 -68
  195. package/template/packs/academic-paper/document/theme/patterns/table-utilities.css +0 -66
  196. package/template/packs/academic-paper/document/theme/shell/reader-controls.css +0 -761
  197. package/template/packs/academic-paper/document/theme/tokens.css +0 -80
  198. package/template/packs/academic-paper/openpress.config.mjs +0 -5
  199. package/template/packs/claude-document/document/chapters/01-document-shape/content/01-document-shape.mdx +0 -51
  200. package/template/packs/claude-document/document/chapters/02-review-loop/content/01-review-loop.mdx +0 -31
  201. package/template/packs/claude-document/document/components/ChapterOpenerVisual.tsx +0 -96
  202. package/template/packs/claude-document/document/components/Page.tsx +0 -37
  203. package/template/packs/claude-document/document/design.md +0 -142
  204. package/template/packs/claude-document/document/index.tsx +0 -94
  205. package/template/packs/claude-document/document/media/README.md +0 -13
  206. package/template/packs/claude-document/document/openpress.config.mjs +0 -26
  207. package/template/packs/claude-document/document/theme/README.md +0 -15
  208. package/template/packs/claude-document/document/theme/base/page-contract.css +0 -525
  209. package/template/packs/claude-document/document/theme/base/print.css +0 -93
  210. package/template/packs/claude-document/document/theme/base/typography.css +0 -612
  211. package/template/packs/claude-document/document/theme/fonts.css +0 -4
  212. package/template/packs/claude-document/document/theme/page-surfaces/back-cover.css +0 -72
  213. package/template/packs/claude-document/document/theme/page-surfaces/chapter-opener.css +0 -236
  214. package/template/packs/claude-document/document/theme/page-surfaces/cover.css +0 -309
  215. package/template/packs/claude-document/document/theme/page-surfaces/toc.css +0 -225
  216. package/template/packs/claude-document/document/theme/patterns/_chart-frame.css +0 -53
  217. package/template/packs/claude-document/document/theme/patterns/figure-grid.css +0 -68
  218. package/template/packs/claude-document/document/theme/patterns/table-utilities.css +0 -66
  219. package/template/packs/claude-document/document/theme/shell/reader-controls.css +0 -789
  220. package/template/packs/claude-document/document/theme/tokens.css +0 -89
  221. package/template/packs/claude-document/openpress.config.mjs +0 -5
  222. package/template/packs/editorial-monograph/document/chapters/01-product-and-use-cases/content/01-product-and-use-cases.mdx +0 -31
  223. package/template/packs/editorial-monograph/document/chapters/02-workflow/content/01-workflow.mdx +0 -89
  224. package/template/packs/editorial-monograph/document/chapters/03-agent-skills-contributors/content/01-agent-skills-contributors.mdx +0 -51
  225. package/template/packs/editorial-monograph/document/chapters/04-validation-deploy/content/01-validation-deploy.mdx +0 -39
  226. package/template/packs/editorial-monograph/document/components/ChapterOpenerVisual/index.tsx +0 -76
  227. package/template/packs/editorial-monograph/document/components/Page.tsx +0 -37
  228. package/template/packs/editorial-monograph/document/components/TokenSwatchGrid/index.tsx +0 -46
  229. package/template/packs/editorial-monograph/document/components/TokenSwatchGrid/style.css +0 -63
  230. package/template/packs/editorial-monograph/document/components/TypeSpecimen/index.tsx +0 -38
  231. package/template/packs/editorial-monograph/document/components/TypeSpecimen/style.css +0 -111
  232. package/template/packs/editorial-monograph/document/design.md +0 -279
  233. package/template/packs/editorial-monograph/document/index.tsx +0 -97
  234. package/template/packs/editorial-monograph/document/media/README.md +0 -13
  235. package/template/packs/editorial-monograph/document/openpress.config.mjs +0 -26
  236. package/template/packs/editorial-monograph/document/theme/README.md +0 -11
  237. package/template/packs/editorial-monograph/document/theme/base/page-contract.css +0 -505
  238. package/template/packs/editorial-monograph/document/theme/base/print.css +0 -93
  239. package/template/packs/editorial-monograph/document/theme/base/typography.css +0 -336
  240. package/template/packs/editorial-monograph/document/theme/fonts.css +0 -3
  241. package/template/packs/editorial-monograph/document/theme/page-surfaces/back-cover.css +0 -43
  242. package/template/packs/editorial-monograph/document/theme/page-surfaces/chapter-opener.css +0 -205
  243. package/template/packs/editorial-monograph/document/theme/page-surfaces/cover.css +0 -147
  244. package/template/packs/editorial-monograph/document/theme/page-surfaces/toc.css +0 -149
  245. package/template/packs/editorial-monograph/document/theme/patterns/_chart-frame.css +0 -49
  246. package/template/packs/editorial-monograph/document/theme/patterns/figure-grid.css +0 -68
  247. package/template/packs/editorial-monograph/document/theme/patterns/table-utilities.css +0 -66
  248. package/template/packs/editorial-monograph/document/theme/shell/reader-controls.css +0 -761
  249. package/template/packs/editorial-monograph/document/theme/tokens.css +0 -80
  250. package/template/packs/editorial-monograph/openpress.config.mjs +0 -5
@@ -1,238 +0,0 @@
1
- // @open-press/core/manuscript — long-form section-flow helpers.
2
- //
3
- // Manuscript helpers cover the "paper / report / book / monograph" pattern:
4
- // a source resolves into a sequence of sections, each section becomes one
5
- // content frame (with overflow auto-cloning across pages), and a TOC frame
6
- // summarizes the outline.
7
- //
8
- // These helpers are conventions only. Core never knows about them. Any
9
- // document type that wants section flow imports from here; documents that
10
- // do not (slides, folios, calendars) skip this module entirely.
11
-
12
- import { Fragment, useContext, type ComponentType, type ReactNode } from "react";
13
- import { Frame, FrameContext, MdxArea, PressContext, useSource } from "../core";
14
- import type { MdxAreaOverflow, ResolvedSource } from "../core";
15
- import { createMdxAreaObjectEntityId } from "../document-model/objectEntityModel";
16
-
17
- // ---------------------------------------------------------------------------
18
- // <Sections>
19
- // ---------------------------------------------------------------------------
20
-
21
- export interface SectionsPageProps {
22
- frameKey: string;
23
- chainId: string;
24
- pageIndex: number;
25
- totalPages: number;
26
- sectionSlug: string;
27
- sectionTitle: string;
28
- sectionTone?: string;
29
- sectionMeta: Record<string, unknown>;
30
- }
31
-
32
- export interface SectionsOpenerProps {
33
- frameKey: string;
34
- sectionSlug: string;
35
- sectionTitle: string;
36
- sectionIndex: number;
37
- sectionMeta: Record<string, unknown>;
38
- }
39
-
40
- export interface SectionsProps {
41
- source: string;
42
- page?: ComponentType<SectionsPageProps>;
43
- opener?: ComponentType<SectionsOpenerProps>;
44
- }
45
-
46
- export function Sections({ source: sourceId, page: Page = DefaultSectionPage, opener: Opener }: SectionsProps) {
47
- const source = useSource(sourceId);
48
- const press = useContext(PressContext);
49
- const hints = press?.hints ?? null;
50
- return (
51
- <Fragment>
52
- {source.tree.map((section, index) => {
53
- const chainId = `${sourceId}:${section.slug}`;
54
- const meta = (section.meta ?? {}) as Record<string, unknown>;
55
- const tone = typeof meta.tone === "string" ? meta.tone : undefined;
56
- const totalPages = Math.max(1, hints?.totalPagesPerChain?.[chainId] ?? 1);
57
- const pages: ReactNode[] = [];
58
- for (let i = 0; i < totalPages; i++) {
59
- pages.push(
60
- <Page
61
- key={i}
62
- frameKey={`${sourceId}:${section.slug}:content:${i}`}
63
- chainId={chainId}
64
- pageIndex={i}
65
- totalPages={totalPages}
66
- sectionSlug={section.slug}
67
- sectionTitle={section.title}
68
- sectionTone={tone}
69
- sectionMeta={meta}
70
- />,
71
- );
72
- }
73
- return (
74
- <Fragment key={section.slug}>
75
- {Opener ? (
76
- <Opener
77
- frameKey={`${sourceId}:${section.slug}:opener`}
78
- sectionSlug={section.slug}
79
- sectionTitle={section.title}
80
- sectionIndex={index}
81
- sectionMeta={meta}
82
- />
83
- ) : null}
84
- {pages}
85
- </Fragment>
86
- );
87
- })}
88
- </Fragment>
89
- );
90
- }
91
-
92
- // Compatibility alias for chapter vocabulary.
93
- export const Chapters = Sections;
94
- export type ChaptersProps = SectionsProps;
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
-
131
- // ---------------------------------------------------------------------------
132
- // <Toc>
133
- // ---------------------------------------------------------------------------
134
-
135
- export interface TocProps {
136
- source: string;
137
- className?: string;
138
- heading?: ReactNode;
139
- frameKey?: string;
140
- maxLevel?: 2 | 3;
141
- overflow?: MdxAreaOverflow;
142
- page?: React.ComponentType<TocPageProps>;
143
- }
144
-
145
- export interface TocPageProps {
146
- frameKey: string;
147
- chainId: string;
148
- pageIndex: number;
149
- totalPages: number;
150
- sourceId: string;
151
- heading?: ReactNode;
152
- className?: string;
153
- maxLevel?: 2 | 3;
154
- overflow?: MdxAreaOverflow;
155
- }
156
-
157
- export interface TocAreaProps {
158
- chainId: string;
159
- maxLevel?: 2 | 3;
160
- overflow?: MdxAreaOverflow;
161
- className?: string;
162
- }
163
-
164
- export function Toc({ source: sourceId, className, heading, frameKey = "toc", maxLevel = 3, overflow = "extend", page: Page = DefaultTocPage }: TocProps) {
165
- useSource(sourceId) as ResolvedSource;
166
- const press = useContext(PressContext);
167
- const chainId = maxLevel <= 2 ? `toc:${sourceId}:h2` : `toc:${sourceId}`;
168
- const totalPages = Math.max(1, press?.hints?.totalPagesPerChain?.[chainId] ?? 1);
169
- const pages: ReactNode[] = [];
170
- for (let i = 0; i < totalPages; i++) {
171
- pages.push(
172
- <Page
173
- key={i}
174
- frameKey={i === 0 ? frameKey : `${frameKey}:page:${i}`}
175
- chainId={chainId}
176
- pageIndex={i}
177
- totalPages={totalPages}
178
- sourceId={sourceId}
179
- heading={heading}
180
- className={className}
181
- maxLevel={maxLevel}
182
- overflow={overflow}
183
- />,
184
- );
185
- }
186
- return <Fragment>{pages}</Fragment>;
187
- }
188
-
189
- function DefaultTocPage({ frameKey, chainId, pageIndex, totalPages, heading, className, maxLevel, overflow }: TocPageProps) {
190
- const isContinuation = pageIndex > 0;
191
- const tocClassName = ["reader-page--toc", isContinuation ? "toc-continuation" : null, className].filter(Boolean).join(" ") || undefined;
192
- return (
193
- <Frame
194
- frameKey={frameKey}
195
- role="manuscript.toc"
196
- chrome={false}
197
- className={tocClassName}
198
- >
199
- <div className="page-frame">
200
- <header className="page-header toc-header">
201
- {heading ?? (
202
- <h2 className={isContinuation ? "toc-heading toc-heading--continuation" : "toc-heading"} id={isContinuation ? `${frameKey}-title` : "toc-title"}>
203
- {isContinuation ? "目錄續" : "目錄"}
204
- </h2>
205
- )}
206
- </header>
207
- <main className="page-body">
208
- <TocArea chainId={chainId} maxLevel={maxLevel} overflow={overflow} />
209
- </main>
210
- </div>
211
- </Frame>
212
- );
213
- }
214
-
215
- export function TocArea({ chainId, maxLevel, overflow = "extend", className }: TocAreaProps) {
216
- const frame = useContext(FrameContext);
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;
222
- return (
223
- <div
224
- className="openpress-mdx-area openpress-toc-area"
225
- data-openpress-mdx-area="true"
226
- data-openpress-mdx-area-chain={chainId}
227
- data-openpress-mdx-area-index={consumed?.indexInFrame}
228
- data-openpress-object-id={objectId}
229
- data-openpress-toc-max-level={maxLevel}
230
- data-openpress-mdx-area-overflow={overflow}
231
- data-openpress-mdx-area-empty={blocks == null ? "true" : "false"}
232
- >
233
- <ol className={["toc-list", className].filter(Boolean).join(" ") || undefined}>
234
- {blocks}
235
- </ol>
236
- </div>
237
- );
238
- }
@@ -1,88 +0,0 @@
1
- // @open-press/core/mdx — pure source descriptor factories.
2
- //
3
- // These factories MUST stay pure: they construct descriptor objects only.
4
- // They must not touch the filesystem, fetch the network, or execute
5
- // workspace logic at module load. Resolution happens in Layer 1 inside the
6
- // engine, where IO is allowed.
7
-
8
- import type {
9
- MdxSourceDescriptor,
10
- MdxSourceDescriptorFileList,
11
- MdxSourceDescriptorSectionFiles,
12
- MdxSourceDescriptorSectionFolders,
13
- } from "../core/types";
14
-
15
- export type {
16
- MdxSourceDescriptor,
17
- MdxSourceDescriptorFileList,
18
- MdxSourceDescriptorSectionFiles,
19
- MdxSourceDescriptorSectionFolders,
20
- } from "../core/types";
21
-
22
- export type {
23
- OutlineItem,
24
- ResolvedSource,
25
- SourceBlock,
26
- SourceFileRecord,
27
- SourceNode,
28
- } from "../core/types";
29
-
30
- type MdxSourceOptions =
31
- | { preset: "section-folders"; root?: string }
32
- | { preset: "section-files"; root?: string }
33
- | { preset: "file-list"; files: string[] };
34
-
35
- const VALID_PRESETS = new Set(["section-folders", "section-files", "file-list"]);
36
-
37
- export function mdxSource(options: MdxSourceOptions): MdxSourceDescriptor {
38
- if (!options || typeof options !== "object") {
39
- throw new Error("mdxSource() requires an options object.");
40
- }
41
- if (!VALID_PRESETS.has(options.preset)) {
42
- throw new Error(
43
- `mdxSource() preset must be one of: section-folders, section-files, file-list. Got "${
44
- (options as { preset?: unknown }).preset
45
- }".`,
46
- );
47
- }
48
-
49
- if (options.preset === "section-folders") {
50
- return normalizeRooted("section-folders", options.root, "chapters") as MdxSourceDescriptorSectionFolders;
51
- }
52
- if (options.preset === "section-files") {
53
- return normalizeRooted("section-files", options.root, "content") as MdxSourceDescriptorSectionFiles;
54
- }
55
-
56
- // file-list
57
- if (!Array.isArray(options.files)) {
58
- throw new Error('mdxSource({ preset: "file-list" }) requires `files: string[]`.');
59
- }
60
- const files: string[] = [];
61
- for (const raw of options.files) {
62
- if (typeof raw !== "string") {
63
- throw new Error('mdxSource({ preset: "file-list" }) `files` entries must be strings.');
64
- }
65
- const trimmed = raw.trim();
66
- if (!trimmed) continue;
67
- files.push(trimmed);
68
- }
69
- if (files.length === 0) {
70
- throw new Error('mdxSource({ preset: "file-list" }) requires at least one file.');
71
- }
72
- return { type: "mdx", preset: "file-list", files };
73
- }
74
-
75
- function normalizeRooted(
76
- preset: "section-folders" | "section-files",
77
- root: string | undefined,
78
- defaultRoot: string,
79
- ): MdxSourceDescriptor {
80
- if (root !== undefined && typeof root !== "string") {
81
- throw new Error(`mdxSource() \`root\` must be a string if provided. Got ${typeof root}.`);
82
- }
83
- return {
84
- type: "mdx",
85
- preset,
86
- root: (root ?? defaultRoot).trim() || defaultRoot,
87
- };
88
- }
@@ -1,294 +0,0 @@
1
- // @open-press/core/numbering — label formatters for AI authoring layer.
2
- //
3
- // Core stays neutral about how chapter / section / topic numbers should look.
4
- // Source resolution exposes raw integers via outline items
5
- // (`chapterNumber`, `sectionIndex`, `topicIndex`). This module is a toolbox
6
- // of pure functions that turn those integers into human-readable labels —
7
- // Chinese numerals, Roman numerals, alphabet letters, padded decimals, etc.
8
- //
9
- // Workspaces import what they need and compose them inside their own
10
- // `<Page>` / `<Toc>` components. The core engine never calls these.
11
-
12
- // ---------------------------------------------------------------------------
13
- // CJK numeral systems
14
- // ---------------------------------------------------------------------------
15
-
16
- const CJK_INFORMAL = ["〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
17
- const CJK_FORMAL = ["零", "壹", "貳", "參", "肆", "伍", "陸", "柒", "捌", "玖"];
18
- const CJK_HEAVENLY_STEMS = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"];
19
- const CJK_EARTHLY_BRANCHES = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"];
20
-
21
- /**
22
- * Informal CJK numerals (一二三...). Handles 0 to 9999.
23
- *
24
- * toCjk(1) → "一"
25
- * toCjk(10) → "十"
26
- * toCjk(15) → "十五"
27
- * toCjk(23) → "二十三"
28
- * toCjk(100) → "一百"
29
- * toCjk(108) → "一百零八"
30
- * toCjk(2024) → "二千零二十四"
31
- */
32
- export function toCjk(n: number): string {
33
- if (!Number.isFinite(n) || n < 0) return String(n);
34
- return formatCjkDigits(Math.floor(n), CJK_INFORMAL);
35
- }
36
-
37
- /**
38
- * Formal CJK numerals (壹貳參...). Used in legal / financial contexts.
39
- *
40
- * toCjkFormal(1) → "壹"
41
- * toCjkFormal(100) → "壹佰"
42
- */
43
- export function toCjkFormal(n: number): string {
44
- if (!Number.isFinite(n) || n < 0) return String(n);
45
- return formatCjkDigits(Math.floor(n), CJK_FORMAL, { formal: true });
46
- }
47
-
48
- /**
49
- * Heavenly Stems cycle (甲乙丙丁戊己庚辛壬癸 — 10 only).
50
- * Cycles for n > 10; n=11 → 甲 again.
51
- *
52
- * toCjkHeavenlyStem(1) → "甲"
53
- * toCjkHeavenlyStem(10) → "癸"
54
- * toCjkHeavenlyStem(11) → "甲"
55
- */
56
- export function toCjkHeavenlyStem(n: number): string {
57
- if (!Number.isFinite(n) || n < 1) return String(n);
58
- return CJK_HEAVENLY_STEMS[(Math.floor(n) - 1) % 10]!;
59
- }
60
-
61
- /**
62
- * Earthly Branches cycle (子丑寅卯辰巳午未申酉戌亥 — 12 only).
63
- * Cycles for n > 12.
64
- */
65
- export function toCjkEarthlyBranch(n: number): string {
66
- if (!Number.isFinite(n) || n < 1) return String(n);
67
- return CJK_EARTHLY_BRANCHES[(Math.floor(n) - 1) % 12]!;
68
- }
69
-
70
- // ---------------------------------------------------------------------------
71
- // Roman numerals
72
- // ---------------------------------------------------------------------------
73
-
74
- const ROMAN_TABLE: Array<[number, string]> = [
75
- [1000, "M"], [900, "CM"], [500, "D"], [400, "CD"],
76
- [100, "C"], [90, "XC"], [50, "L"], [40, "XL"],
77
- [10, "X"], [9, "IX"], [5, "V"], [4, "IV"],
78
- [1, "I"],
79
- ];
80
-
81
- /**
82
- * Roman numerals (I, II, III, …, MMXX). Uppercase by default.
83
- * Pass `{ upper: false }` for lowercase (typical front-matter page numbering).
84
- *
85
- * toRoman(1) → "I"
86
- * toRoman(4) → "IV"
87
- * toRoman(2024) → "MMXXIV"
88
- * toRoman(3, { upper: false }) → "iii"
89
- */
90
- export function toRoman(n: number, opts: { upper?: boolean } = {}): string {
91
- if (!Number.isFinite(n) || n < 1) return String(n);
92
- let value = Math.floor(n);
93
- let out = "";
94
- for (const [num, sym] of ROMAN_TABLE) {
95
- while (value >= num) {
96
- out += sym;
97
- value -= num;
98
- }
99
- }
100
- return opts.upper === false ? out.toLowerCase() : out;
101
- }
102
-
103
- // ---------------------------------------------------------------------------
104
- // Latin alphabet (a, b, c, …, z, aa, ab, …)
105
- // ---------------------------------------------------------------------------
106
-
107
- /**
108
- * Spreadsheet-column-style alphabet labels.
109
- *
110
- * toAlpha(1) → "a"
111
- * toAlpha(26) → "z"
112
- * toAlpha(27) → "aa"
113
- * toAlpha(53) → "ba"
114
- * toAlpha(1, { upper: true }) → "A"
115
- */
116
- export function toAlpha(n: number, opts: { upper?: boolean } = {}): string {
117
- if (!Number.isFinite(n) || n < 1) return String(n);
118
- let value = Math.floor(n);
119
- let out = "";
120
- while (value > 0) {
121
- const rem = (value - 1) % 26;
122
- out = String.fromCharCode(97 + rem) + out;
123
- value = Math.floor((value - 1) / 26);
124
- }
125
- return opts.upper ? out.toUpperCase() : out;
126
- }
127
-
128
- // ---------------------------------------------------------------------------
129
- // Zero-padded decimal
130
- // ---------------------------------------------------------------------------
131
-
132
- /**
133
- * Zero-padded decimal — `width` is the minimum number of digits.
134
- *
135
- * toPadded(1) → "01"
136
- * toPadded(1, { width: 3 }) → "001"
137
- * toPadded(123) → "123"
138
- */
139
- export function toPadded(n: number, opts: { width?: number } = {}): string {
140
- if (!Number.isFinite(n)) return String(n);
141
- const width = Math.max(1, opts.width ?? 2);
142
- return String(Math.floor(n)).padStart(width, "0");
143
- }
144
-
145
- // ---------------------------------------------------------------------------
146
- // Composable label templates
147
- // ---------------------------------------------------------------------------
148
-
149
- export type NumberFormat =
150
- | "decimal"
151
- | "decimal-padded"
152
- | "cjk"
153
- | "cjk-formal"
154
- | "cjk-heavenly-stem"
155
- | "cjk-earthly-branch"
156
- | "roman"
157
- | "roman-lower"
158
- | "alpha"
159
- | "alpha-upper";
160
-
161
- export interface ChapterLabelOptions {
162
- format?: NumberFormat;
163
- prefix?: string;
164
- suffix?: string;
165
- width?: number;
166
- }
167
-
168
- /**
169
- * Compose a chapter label like "第一章" / "Chapter 1" / "01" / "Part IV".
170
- *
171
- * chapterLabel(1)
172
- * → "第一章" (default: cjk informal, prefix 第, suffix 章)
173
- * chapterLabel(1, { format: "decimal-padded", prefix: "Chapter " })
174
- * → "Chapter 01"
175
- * chapterLabel(4, { format: "roman", prefix: "Part " })
176
- * → "Part IV"
177
- * chapterLabel(2, { prefix: "", suffix: "" })
178
- * → "二"
179
- */
180
- export function chapterLabel(n: number, opts: ChapterLabelOptions = {}): string {
181
- const { format = "cjk", prefix = "第", suffix = "章", width } = opts;
182
- return `${prefix}${formatNumber(n, format, width)}${suffix}`;
183
- }
184
-
185
- export interface SectionLabelOptions {
186
- format?: NumberFormat;
187
- separator?: string;
188
- prefix?: string;
189
- suffix?: string;
190
- }
191
-
192
- /**
193
- * Compose a section label like "1.1" / "1.1.2" / "一-1".
194
- *
195
- * Accepts variadic counters for nesting:
196
- * sectionLabel(1, 2)
197
- * → "1.2"
198
- * sectionLabel(1, 2, 3)
199
- * → "1.2.3"
200
- * sectionLabel(1, 2, { format: "cjk", separator: "之" })
201
- * ⚠ note: pass options as last argument when using variadic counters;
202
- * prefer `sectionLabelOf([1, 2], { … })` below for clarity.
203
- */
204
- export function sectionLabel(...counters: number[]): string {
205
- return sectionLabelOf(counters);
206
- }
207
-
208
- /**
209
- * Explicit-array variant of `sectionLabel` so options can be passed cleanly.
210
- *
211
- * sectionLabelOf([1, 2], { separator: "-" }) → "1-2"
212
- * sectionLabelOf([1, 2, 3], { format: "alpha" }) → "a.b.c"
213
- * sectionLabelOf([1, 1], { format: "cjk", separator: "-" }) → "一-一"
214
- */
215
- export function sectionLabelOf(counters: number[], opts: SectionLabelOptions = {}): string {
216
- const { format = "decimal", separator = ".", prefix = "", suffix = "" } = opts;
217
- const parts = counters.map((c) => formatNumber(c, format));
218
- return `${prefix}${parts.join(separator)}${suffix}`;
219
- }
220
-
221
- // ---------------------------------------------------------------------------
222
- // Generic dispatch — `format` -> formatter
223
- // ---------------------------------------------------------------------------
224
-
225
- /**
226
- * Format a single number using one of the named formats. Useful when the
227
- * caller already knows which format string to use (e.g. from config).
228
- *
229
- * formatNumber(7, "cjk") → "七"
230
- * formatNumber(7, "roman-lower") → "vii"
231
- * formatNumber(3, "decimal-padded", 3) → "003"
232
- */
233
- export function formatNumber(n: number, format: NumberFormat, width?: number): string {
234
- switch (format) {
235
- case "decimal": return String(Math.floor(n));
236
- case "decimal-padded": return toPadded(n, { width });
237
- case "cjk": return toCjk(n);
238
- case "cjk-formal": return toCjkFormal(n);
239
- case "cjk-heavenly-stem": return toCjkHeavenlyStem(n);
240
- case "cjk-earthly-branch": return toCjkEarthlyBranch(n);
241
- case "roman": return toRoman(n, { upper: true });
242
- case "roman-lower": return toRoman(n, { upper: false });
243
- case "alpha": return toAlpha(n);
244
- case "alpha-upper": return toAlpha(n, { upper: true });
245
- default: return String(n);
246
- }
247
- }
248
-
249
- // ---------------------------------------------------------------------------
250
- // CJK digit formatter (internal)
251
- // ---------------------------------------------------------------------------
252
-
253
- const CJK_UNITS = ["", "十", "百", "千"];
254
- const CJK_UNITS_FORMAL = ["", "拾", "佰", "仟"];
255
-
256
- // Gap-zero indicator used between non-zero digits when reading aloud
257
- // (e.g. 一百零八). Distinct from 〇/零 as a literal zero digit.
258
- const CJK_GAP_ZERO = "零";
259
-
260
- function formatCjkDigits(n: number, digits: string[], opts: { formal?: boolean } = {}): string {
261
- if (n === 0) return digits[0]!;
262
- if (n < 0) return `負${formatCjkDigits(-n, digits, opts)}`;
263
- if (n >= 10000) {
264
- const wan = Math.floor(n / 10000);
265
- const rest = n % 10000;
266
- if (rest === 0) return `${formatCjkDigits(wan, digits, opts)}萬`;
267
- const restStr = formatCjkDigits(rest, digits, opts);
268
- const padded = rest < 1000 ? `${CJK_GAP_ZERO}${restStr}` : restStr;
269
- return `${formatCjkDigits(wan, digits, opts)}萬${padded}`;
270
- }
271
- const units = opts.formal ? CJK_UNITS_FORMAL : CJK_UNITS;
272
- const str = String(n);
273
- let out = "";
274
- let zeroPending = false;
275
- for (let i = 0; i < str.length; i++) {
276
- const digit = Number(str[i]);
277
- const unit = str.length - 1 - i;
278
- if (digit === 0) {
279
- zeroPending = true;
280
- continue;
281
- }
282
- if (zeroPending && out.length > 0) {
283
- out += CJK_GAP_ZERO;
284
- zeroPending = false;
285
- }
286
- // Special case: leading "一十" usually written as just "十" in informal CJK
287
- if (!opts.formal && digit === 1 && unit === 1 && i === 0) {
288
- out += units[unit];
289
- } else {
290
- out += digits[digit] + units[unit];
291
- }
292
- }
293
- return out;
294
- }