OpenPress

@open-press/core

Press

単一のドキュメント。<Press> はそのタイトル、ページのジオメトリ、ソース、ソースのルートディレクトリ、および配下の Frames + 補助ツールの React ツリー構造を宣言します。フォルダの規約に従うプロジェクトでは、press/<slug>/press.tsx から単一の Press をエクスポートします。

<Press> コンポーネントは、単一のドキュメントのコア設定、コンテンツソース、およびコンポーネント構造を定義します。エンジンはこの宣言を通じて、Workspace 内に分離されたドキュメントの境界を確立します。

1.0 契約: システムは出版物を発見するために press/*/press.tsx フォルダ規約に依存しています。各エントリファイルはデフォルトエクスポートとして単一の <Press> インスタンスを返す必要があり、slug はフォルダ名と一致している必要があります。

Component Impl

# <Press>

単一のドキュメントのコンテキスト、レイアウト、およびデータソースを設定・カプセル化します。レンダリング時には `Frame` および補助コンポーネントのホストとして機能します。

import { Press } from "@open-press/core";
<Press
  title="..."
  page="a4" | "social-square" | "slide-16-9" | PageGeometry
  sources={[ mdxSource({ id, preset, root }) ]}
  slug?
  theme?
  componentsDir?
  mediaDir?
>
  {/* Frames + 原稿補助ツール */}
</Press>

ドキュメント設定 (Metadata & Routing)

Name Type Default Description
title required string ドキュメントの完全な名前。HTML の ``、OG タグ、PDF メタデータ、および UI インターフェースに自動的にバインドされます。このプロパティはコンテンツキャンバスに直接出力されることはありません。</td> </tr><tr> <td class="whitespace-nowrap px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="bg-transparent p-0 text-ink-strong font-mono text-[0.85rem] font-semibold">slug</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="px-[0.32em] py-[0.06em] bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] rounded-[3px] font-mono text-[0.85rem] text-subdued-strong">string</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <span aria-hidden="true">—</span> </td> <td class="text-ink px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top [&_code]:px-[0.3em] [&_code]:py-[0.06em] [&_code]:rounded-[3px] [&_code]:bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] [&_code]:font-mono [&_code]:text-[0.85rem]">URL ルーティングおよび出力ディレクトリの識別子。デフォルトでは親ディレクトリ名から自動的に推論されます(例: `press/report` は `report` に対応します)。</td> </tr> </tbody> </table> </div> </div><div class="min-w-0 max-w-full my-4 mb-6"> <p class="m-0 mb-2 text-subdued font-mono text-xs font-semibold tracking-[0.06em] uppercase">リソース登録 (Resource Registration)</p> <div class="max-w-full overflow-x-auto border border-hairline rounded-[6px]"> <table class="w-full min-w-[38rem] m-0 border-collapse text-sm leading-[1.55]"> <thead> <tr> <th class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top bg-paper-soft text-subdued-strong font-mono text-[0.72rem] font-semibold tracking-[0.06em] uppercase">Name</th> <th class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top bg-paper-soft text-subdued-strong font-mono text-[0.72rem] font-semibold tracking-[0.06em] uppercase">Type</th> <th class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top bg-paper-soft text-subdued-strong font-mono text-[0.72rem] font-semibold tracking-[0.06em] uppercase">Default</th> <th class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top bg-paper-soft text-subdued-strong font-mono text-[0.72rem] font-semibold tracking-[0.06em] uppercase">Description</th> </tr> </thead> <tbody class="[&_tr:last-child_td]:border-b-0"> <tr> <td class="whitespace-nowrap px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="bg-transparent p-0 text-ink-strong font-mono text-[0.85rem] font-semibold">page</code> <span class="inline-block ml-[0.4rem] px-[0.45em] py-[0.05em] rounded-full bg-[color-mix(in_srgb,var(--op-accent)_12%,transparent)] text-accent font-mono text-[0.65rem] font-semibold tracking-[0.04em] uppercase">required</span> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="px-[0.32em] py-[0.06em] bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] rounded-[3px] font-mono text-[0.85rem] text-subdued-strong">"a4" | "social-square" | "slide-16-9" | PageGeometry</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <span aria-hidden="true">—</span> </td> <td class="text-ink px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top [&_code]:px-[0.3em] [&_code]:py-[0.06em] [&_code]:rounded-[3px] [&_code]:bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] [&_code]:font-mono [&_code]:text-[0.85rem]">この Press の page geometry。一般的な形式には preset を使い、プロジェクト固有のサイズには `{ id, label, width, height }` custom object を渡します。Exporter は resolved geometry を `--openpress-page-*` CSS variables に変換します。</td> </tr><tr> <td class="whitespace-nowrap px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="bg-transparent p-0 text-ink-strong font-mono text-[0.85rem] font-semibold">sources</code> <span class="inline-block ml-[0.4rem] px-[0.45em] py-[0.05em] rounded-full bg-[color-mix(in_srgb,var(--op-accent)_12%,transparent)] text-accent font-mono text-[0.65rem] font-semibold tracking-[0.04em] uppercase">required</span> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="px-[0.32em] py-[0.06em] bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] rounded-[3px] font-mono text-[0.85rem] text-subdued-strong">SourceRegistration[]</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <span aria-hidden="true">—</span> </td> <td class="text-ink px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top [&_code]:px-[0.3em] [&_code]:py-[0.06em] [&_code]:rounded-[3px] [&_code]:bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] [&_code]:font-mono [&_code]:text-[0.85rem]">`mdxSource()` によって初期化されたデータソースのリスト。内部で定義された `id` は `<MdxArea>` および `<Sections>` によって消費されます。</td> </tr><tr> <td class="whitespace-nowrap px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="bg-transparent p-0 text-ink-strong font-mono text-[0.85rem] font-semibold">theme</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="px-[0.32em] py-[0.06em] bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] rounded-[3px] font-mono text-[0.85rem] text-subdued-strong">string</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <span aria-hidden="true">—</span> </td> <td class="text-ink px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top [&_code]:px-[0.3em] [&_code]:py-[0.06em] [&_code]:rounded-[3px] [&_code]:bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] [&_code]:font-mono [&_code]:text-[0.85rem]">この Press の theme path override。新しい work では tokens と font loading を `press/<slug>/theme/` に置き、shared theme path は意図的な multi-Press shared source に限定します。</td> </tr><tr> <td class="whitespace-nowrap px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="bg-transparent p-0 text-ink-strong font-mono text-[0.85rem] font-semibold">componentsDir</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="px-[0.32em] py-[0.06em] bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] rounded-[3px] font-mono text-[0.85rem] text-subdued-strong">string | string[]</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <span aria-hidden="true">—</span> </td> <td class="text-ink px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top [&_code]:px-[0.3em] [&_code]:py-[0.06em] [&_code]:rounded-[3px] [&_code]:bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] [&_code]:font-mono [&_code]:text-[0.85rem]">MDX のオートロードコンポーネントの物理ディレクトリ。デフォルトで `./components` が含まれます。ディレクトリ内のコンポーネントは `import` なしで MDX で使用できます。</td> </tr><tr> <td class="whitespace-nowrap px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="bg-transparent p-0 text-ink-strong font-mono text-[0.85rem] font-semibold">mediaDir</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="px-[0.32em] py-[0.06em] bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] rounded-[3px] font-mono text-[0.85rem] text-subdued-strong">string | string[]</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <span aria-hidden="true">—</span> </td> <td class="text-ink px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top [&_code]:px-[0.3em] [&_code]:py-[0.06em] [&_code]:rounded-[3px] [&_code]:bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] [&_code]:font-mono [&_code]:text-[0.85rem]">ローカルメディアファイルのディレクトリ。デフォルトで `./media` が含まれます。</td> </tr><tr> <td class="whitespace-nowrap px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="bg-transparent p-0 text-ink-strong font-mono text-[0.85rem] font-semibold">children</code> <span class="inline-block ml-[0.4rem] px-[0.45em] py-[0.05em] rounded-full bg-[color-mix(in_srgb,var(--op-accent)_12%,transparent)] text-accent font-mono text-[0.65rem] font-semibold tracking-[0.04em] uppercase">required</span> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <code class="px-[0.32em] py-[0.06em] bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] rounded-[3px] font-mono text-[0.85rem] text-subdued-strong">ReactNode</code> </td> <td class="px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top"> <span aria-hidden="true">—</span> </td> <td class="text-ink px-[0.85rem] py-[0.6rem] border-b border-hairline text-left align-top [&_code]:px-[0.3em] [&_code]:py-[0.06em] [&_code]:rounded-[3px] [&_code]:bg-[color-mix(in_srgb,var(--op-ink)_6%,transparent)] [&_code]:font-mono [&_code]:text-[0.85rem]">ドキュメント本体を構成する `<Frame>` および補助コンポーネント(`<Toc>`、`<Sections>` など)のツリー構造。</td> </tr> </tbody> </table> </div> </div><h3 id="例単一ドキュメントの宣言">例:単一ドキュメントの宣言</h3><pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> { Press, Frame } </span><span style="color:#F97583">from</span><span style="color:#9ECBFF"> "@open-press/core"</span><span style="color:#E1E4E8">;</span></span> <span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> { mdxSource } </span><span style="color:#F97583">from</span><span style="color:#9ECBFF"> "@open-press/core/mdx"</span><span style="color:#E1E4E8">;</span></span> <span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> { Sections, Toc } </span><span style="color:#F97583">from</span><span style="color:#9ECBFF"> "@open-press/core/manuscript"</span><span style="color:#E1E4E8">;</span></span> <span class="line"></span> <span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> default</span><span style="color:#F97583"> function</span><span style="color:#B392F0"> ReportPress</span><span style="color:#E1E4E8">() {</span></span> <span class="line"><span style="color:#F97583"> return</span><span style="color:#E1E4E8"> (</span></span> <span class="line"><span style="color:#E1E4E8"> <</span><span style="color:#79B8FF">Press</span></span> <span class="line"><span style="color:#B392F0"> title</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"Transport models in dense networks"</span></span> <span class="line"><span style="color:#B392F0"> page</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"a4"</span></span> <span class="line"><span style="color:#B392F0"> sources</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">{[</span></span> <span class="line"><span style="color:#B392F0"> mdxSource</span><span style="color:#E1E4E8">({ id: </span><span style="color:#9ECBFF">"story"</span><span style="color:#E1E4E8">, preset: </span><span style="color:#9ECBFF">"section-folders"</span><span style="color:#E1E4E8">, root: </span><span style="color:#9ECBFF">"report/chapters"</span><span style="color:#E1E4E8"> }),</span></span> <span class="line"><span style="color:#E1E4E8"> ]}</span></span> <span class="line"><span style="color:#E1E4E8"> ></span></span> <span class="line"><span style="color:#E1E4E8"> <</span><span style="color:#79B8FF">Frame</span><span style="color:#B392F0"> frameKey</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"cover"</span><span style="color:#B392F0"> role</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"document.cover"</span><span style="color:#E1E4E8">></span></span> <span class="line"><span style="color:#E1E4E8"> <</span><span style="color:#79B8FF">Cover</span><span style="color:#E1E4E8"> /></span></span> <span class="line"><span style="color:#E1E4E8"> </</span><span style="color:#79B8FF">Frame</span><span style="color:#E1E4E8">></span></span> <span class="line"><span style="color:#E1E4E8"> <</span><span style="color:#79B8FF">Toc</span><span style="color:#B392F0"> source</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"story"</span><span style="color:#B392F0"> maxLevel</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">{</span><span style="color:#79B8FF">2</span><span style="color:#E1E4E8">} /></span></span> <span class="line"><span style="color:#E1E4E8"> <</span><span style="color:#79B8FF">Sections</span><span style="color:#B392F0"> source</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"story"</span><span style="color:#E1E4E8"> /></span></span> <span class="line"><span style="color:#E1E4E8"> </</span><span style="color:#79B8FF">Press</span><span style="color:#E1E4E8">></span></span> <span class="line"><span style="color:#E1E4E8"> );</span></span> <span class="line"><span style="color:#E1E4E8">}</span></span></code></pre><h3 id="例プロジェクト固有の-geometry">例:プロジェクト固有の geometry</h3><pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8;overflow-x:auto" tabindex="0" data-language="tsx"><code><span class="line"><span style="color:#E1E4E8"><</span><span style="color:#79B8FF">Press</span></span> <span class="line"><span style="color:#B392F0"> slug</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"campaign"</span></span> <span class="line"><span style="color:#B392F0"> title</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"Campaign Card"</span></span> <span class="line"><span style="color:#B392F0"> page</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">{{ id: </span><span style="color:#9ECBFF">"campaign-card"</span><span style="color:#E1E4E8">, label: </span><span style="color:#9ECBFF">"Campaign Card"</span><span style="color:#E1E4E8">, width: </span><span style="color:#9ECBFF">"1080px"</span><span style="color:#E1E4E8">, height: </span><span style="color:#9ECBFF">"1350px"</span><span style="color:#E1E4E8"> }}</span></span> <span class="line"><span style="color:#E1E4E8">></span></span> <span class="line"><span style="color:#E1E4E8"> <</span><span style="color:#79B8FF">Frame</span><span style="color:#B392F0"> frameKey</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"cover"</span><span style="color:#B392F0"> role</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"social.card"</span><span style="color:#E1E4E8">></span></span> <span class="line"><span style="color:#E1E4E8"> <</span><span style="color:#79B8FF">CampaignCard</span><span style="color:#E1E4E8"> /></span></span> <span class="line"><span style="color:#E1E4E8"> </</span><span style="color:#79B8FF">Frame</span><span style="color:#E1E4E8">></span></span> <span class="line"><span style="color:#E1E4E8"></</span><span style="color:#79B8FF">Press</span><span style="color:#E1E4E8">></span></span></code></pre> </div> </section> <h2 id="実行時契約と制約">実行時契約と制約</h2> <p>エンジンが <code><Press></code> を処理する際、以下の不変法則に従います:</p> <ul> <li><strong>単一ルートノードの法則</strong>: ドキュメントのすべての可視コンテンツおよび構造コンテンツは、単一の <code><Press></code> の子である必要があります。</li> <li><strong>設定の一貫性</strong>: ドキュメント設定はすべて props にカプセル化され、並行するフロントエンド設定ファイルは存在しません。</li> <li><strong>順序の制約</strong>: ツリー構造のトップレベルコンポーネントの順序(例: カバー、目次、本文の段落)は、出力されるページネーションの順序に直接対応します。</li> <li><strong>ステートレスレンダリング (Stateless Rendering)</strong>: レンダリングフェーズでは複数のパス(スペースの計算、ブロックの配置など)が行われます。開発者はコンポーネントツリーの内部で副作用(ネットワークの読み書き、乱数生成、キャッシュ操作など)を引き起こしてはなりません。</li> </ul> </div> </article> </main> <footer class="border-t border-hairline-strong bg-[linear-gradient(90deg,rgba(15,13,10,0.035)_1px,transparent_1px),var(--op-paper-soft)] bg-[size:3rem_3rem] py-10"> <div class="op-page grid grid-cols-[1fr_2fr_1fr] gap-8 items-center max-[720px]:grid-cols-1 max-[720px]:text-center"> <div> <p class="font-display text-xl text-ink-strong">OpenPress</p> <p class="op-meta">Agent-first document package · v1.0</p> </div> <ul class="flex flex-wrap justify-center gap-5 p-0 m-0 list-none text-sm [&>li>a]:text-ink [&>li>a]:no-underline hover:[&>li>a]:text-accent"> <li><a href="https://open-press-story.pages.dev">Document</a></li> <li><a href="/showcase">Showcase</a></li> <li><a href="https://github.com/quan0715/open-press">GitHub</a></li> <li><a href="https://www.npmjs.com/package/@open-press/cli">@open-press/cli</a></li> <li><a href="https://github.com/quan0715/open-press/issues">Issues</a></li> </ul> <p class="text-right max-[720px]:text-center op-meta">MIT License · 2026</p> </div> </footer> </body></html>