@open-press/core

Press

One document. <Press> declares its title, page geometry, sources, and the React tree of Frames + helpers underneath. Always sits inside a <Workspace> root — even single-document projects.

1.0 contract. Every project's root is <Workspace>, and every document is one <Press> child under it (1 child for single-doc projects, N for multi-doc). The v0.x shape — openpress.config.mjs + named config / sources exports — is removed in v1.0; downstream workspaces should migrate via the v0.10 codemod before upgrading.
Component Plan · v1.0

# <Press>

One document. Declares title / page geometry / sources via props and the page tree via children. Lives as a child of <Workspace>. Display copy (subtitle, organization, author, etc.) lives in your own Cover JSX — Press does not carry rendering text beyond title.

import { Press } from "@open-press/core";
<Press
  title="..."
  page="a4" | "social-square" | "slide-16-9" | PageGeometry
  sources={[ mdxSource({ id, preset, root }) ]}
  slug?           // optional in single-Press workspaces; required for multi-doc
  theme?          // default "./theme" (relative to the document file)
  componentsDir?  // default "./components"
>
  {/* Frames + manuscript helpers */}
</Press>

Document metadata

Name Type Default Description
title required string Document title. Used for PDF metadata, HTML <title>, OG tags, and the workbench / tab-bar label. The only rendering text Press carries — subtitle / author / etc. belong in your Cover JSX.

Page geometry

Name Type Default Description
page "a4" | "social-square" | "slide-16-9" | PageGeometry Document-wide page size. Accepts a preset name or a custom geometry object ({ id, label, width, height }). Engine injects this as --openpress-page-* CSS variables. Individual <Frame> can override via its own page prop.

Content sources

Name Type Default Description
sources SourceRegistration[] Array of source registrations. Each entry is the return value of mdxSource({ id, preset, root }) from @open-press/core/mdx. id is what <MdxArea chainId>, <Sections source>, <Toc source> reference.

Routing & paths

Name Type Default Description
slug string URL segment and per-doc artifact directory (public/openpress/<slug>/document.json, reader route /<slug>). Required when the Workspace has more than one Press child. Optional for single-doc workspaces — defaults to /.
theme string Path to the theme directory, default "./theme" (relative to the document file). Inherits from workspace-level <Workspace theme> if not set.
componentsDir string Path to the React components directory, default "./components".

Tree

Name Type Default Description
children required ReactNode Your document body — typically <Frame> instances and / or manuscript helpers like <Sections>, <Toc>.
Single-document project (most common)
// press/index.tsx
import { Workspace, Press, Frame, mdxSource } from "@open-press/core";
import { Sections, Toc } from "@open-press/core/manuscript";

export default function Project() {
  return (
    <Workspace>
      <Press
        title="Transport models in dense networks"
        page="a4"
        sources={[
          mdxSource({ id: "story", preset: "section-folders", root: "chapters" }),
        ]}
      >
        <Frame frameKey="cover" role="document.cover">
          <Cover />          {/* subtitle / organization / author all live here */}
        </Frame>
        <Toc source="story" maxLevel={2} />
        <Sections source="story" />
        <Frame frameKey="back-cover" role="document.back-cover">
          <BackCover />
        </Frame>
      </Press>
    </Workspace>
  );
}
Multi-geometry project — one Press per page size
// Need an A4 body AND a 16:9 cover in the same project?
// Use a multi-doc Workspace with one Press per geometry.
// (Per-Frame page override is not supported in 1.0 — one page
//  size per Press.)
<Workspace name="Launch kit">
  <Press slug="report"  title="Launch report" page="a4"           sources={[...]}>
    {/* A4 cover + A4 body */}
  </Press>
  <Press slug="opener"  title="Launch opener" page="slide-16-9"   sources={[...]}>
    {/* one 16:9 hero slide */}
  </Press>
</Workspace>
Component Deprecated

# <Press> (v0.x shape)

The legacy v0.x shape — <Press> took no metadata props; document/index.tsx exported config and sources alongside the component, with an openpress.config.mjs pointer at root. Removed in v1.0; the v0.10 codemod migrates automatically.

import { Press } from "@open-press/core";
<Press>
  {/* tree only — metadata read from openpress.config.mjs */}
</Press>
v0.x shape (removed in v1.0)
// document/index.tsx (v0.x — folder name and shape both removed)
import { Press, Frame } from "@open-press/core";
import { mdxSource } from "@open-press/core/mdx";
import { Sections } from "@open-press/core/manuscript";

export const config = { title: "Hello", page: "a4" };

export const sources = {
  story: mdxSource({ preset: "section-folders", root: "chapters" }),
};

export default function Document() {
  return (
    <Press>
      <Frame frameKey="cover">{/* ... */}</Frame>
      <Sections source="story" />
    </Press>
  );
}

The v0.10 codemod produces the v1.0 shape in one step: rename document/press/ (per-Press chapters move under press/<slug>/chapters/), wrap in <Workspace>, move config fields onto <Press> props, move deploy to package.json "openpress", and delete the .mjs.

Runtime contract

You do not pass pagination state into <Press>. During export, OpenPress renders the tree more than once: first to discover frames and content slots, then again after it knows where each source block belongs. That runtime state is internal to the renderer.

What Press guarantees

Name Type Default Description
Tree boundary contract Everything that should become part of the document must be rendered under the single <Press> root.
Single source of truth for metadata contract Title / page / sources live in <Press> props — there is no parallel config file in the v1.0 contract.
Page order contract Top-level frames and helpers render in document order. A cover before <Sections> appears before the generated content pages.
Renderer-owned pagination contract OpenPress may render the tree repeatedly to calculate page counts and content placement. Authors should describe pages declaratively and avoid render-time side effects.

Authoring rules

  • Every project's root is <Workspace>. <Press> is always a child — never the top-level component.
  • One Workspace can hold 1 or N Press children. Single-doc projects have one; multi-doc projects (proposal + pitch + social) have several.
  • Metadata lives on the <Press> props — there is no parallel config file in the 1.0 contract.
  • Display copy beyond title (subtitle, organization, author bylines, version strings) goes into your own Cover JSX, not into Press props.
  • Covers and back covers are ordinary <Frame> components placed before / after the content helpers — no special API.
  • Do not fetch files, mutate globals, or depend on random values while rendering. The renderer may run the tree multiple times.

Related

  • Workspace — multi-document projects.
  • MDX sources — what mdxSource() returns.
  • Frame — page surfaces inside the Press tree.
  • Workspace config — package.json "openpress" field (operational settings) + Press props (document settings).