API 参考

Core API

来自 @imposia/core 的框架无关页面文档与 Publication 控制器。

@imposia/core 是权威的页面文档运行时:分页、生命周期、解析器边界、扩展、打印和导出,全部不依赖 React。这里的一切都只在浏览器中运行。

Core 页面文档

mountPageDocument

mountPageDocument(
  container: HTMLElement,
  source: PageSource,
  options?: PageDocumentOptions,
): PageDocumentController;

该函数立即追加一个 canonical iframe,启动一个暂存世代,并同步返回。读取第一份文档前,请先等待 ready。

app/mount-page-document.ts
const controller = mountPageDocument(host, { html: "<article><h1>你好</h1></article>" });
const pageDocument = await controller.ready;

PageSource 为 { html: string; baseUrl?: string } 或 { lightDom: Element | DocumentFragment; baseUrl?: string }。

PageDocumentOptions 字段类型 / 用途
cssreadonly string[];附加的作者 CSS。
assetResolver处理字体、图片、媒体和样式表请求的异步解析器。
page{ size?, orientation?, margin? };size 接受 A3、A4、A5、B4、B5、Letter、Legal、Ledger 或自定义宽高。
limits可选的输入、节点、资源、期限、页数、布局轮次和生成产物上限。
headerTemplate、footerTemplate页面装饰标记。
decorateBlankPages空白页是否接受装饰。
experimental{ footnotes?: boolean; pageFloats?: boolean };两者都是实验性特性,超出各自限制时分别以 FOOTNOTE_DEFERRED 或 PAGE_FLOAT_FALLBACK 警告回退。
extensions有序的 PageExtension 或 PublicationExtension 值。
compose{ yieldBudgetMs?: number; scheduler?: () => Promise<void> };主线程协作式分页,默认预算 8 ms。传 Infinity 可关闭向调度器让出。
signal取消初始世代。
onProgressstaging 每分配一页就收到轮次内的 { completedPages, pass, provisional: true }。之后的收敛轮次会重置计数。

调度器、字体和图片的等待都计入按实际时间计算的 limits.resourceDeadlineMs。进度描述的是暂存中的临时工作;最新已提交的世代只从 controller.current 读取。

AssetResolver 接收 { url, kind, baseUrl, signal },解析为 { status: "resolved", bytes, mimeType, resolvedUrl? } 或 { status: "blocked", reason? }。实现方法见加载图片与字体。

扩展

PageExtension 和 PublicationExtension 还可以实现同步的 finalizePage(page, context)。它在 Core 解析完装饰和 margin box 之后、提交之前,对每个被接受的页面运行一次,因此 page.element 是可实际测量的页面元素。page.tableFragments 列出续排的表格片段,带原始表格与从 1 开始的续排索引。修改会保留进已提交的 iframe。无论 decorateBlankPages 如何设置,它都会在每个已分配页面上运行,包括有意插入的空白页。

finalizePage 必须返回 undefined

finalizePage 返回任何非 undefined 的值都会让整个世代被拒绝。该钩子通过修改活动页面元素来传达结果,绝不通过返回替代值。

拆分表格需要在续排片段中冻结实测像素列宽时,将 createTableColgroupExtension() 作为可选扩展启用。Core 始终携带作者的 <colgroup> 元素,但默认从不合成列宽。

PageDocumentController

成员返回值就绪与错误
readyPromise<PageDocument>首次提交;无法提交时拒绝。
currentPageDocument | undefined更新失败期间和之后保留上一次提交;销毁后清空。
update(source, options?)Promise<PageDocument>启动一个世代;更新的 update 会中止进行中的那个。支持 options.signal。
print()Promise<void>等待最新工作完成,然后通过顶层文档中的隔离快照打印最近一次成功提交。无提交或销毁后拒绝。
destroy()Promise<void>中止生成与导出工作,移除 iframe,释放资源,并等待被跟踪的工作。幂等。

PageDocument

成员类型 / 返回值含义
iframeHTMLIFrameElementCore 拥有的 canonical 框架。
generation、pageCountnumber提交的世代号与页数。
pagesreadonly PageMetadata[]页码、左右页、命名、空白状态、几何、尺寸和正文文本。
warningsreadonly PageWarning[]当前世代的诊断。
timings{ totalMs; resourceMs; paginationMs }该世代的耗时,单位毫秒。
exportEpub(options)Promise<Blob>等待最新活动工作完成,把最近一次提交的源内容导出为可重排 EPUB 3.3 Blob。

EPUB 选项要求 metadata: { title, language, identifier, modified? },并可选接受 signal 与 { maxEntries?, maxBytes? } 上限。导出是语义性的:页面包装、页边装饰、生成的计数器和只存在于页面上的实验性产物都被排除。

警告

每个已提交的 PageWarning 携带 code、message 和冻结的 location(含 generation、entryId 与 page,未知时各自为 undefined)。扩展诊断使用带命名空间的 EXTENSION_${string} 代码,并注明其 extension。

Core 辅助函数

prepareDocument(html: string, options?: PrepareDocumentOptions): PreparedDocument;
pageWarningTargetBounds(document: PageDocument, warning: PageWarning): PageWarningTargetBounds | undefined;
hasPageDocumentFrameSandbox(iframe: HTMLIFrameElement): boolean;
committedFrameGeneration(frameDocument: Document): number | undefined;
selectBlankMarkers(markers: PageSideConstraint[], pages: Map<number, number>): number[];
  • prepareDocument 同步规范化并清理 HTML,返回 { html, headerTemplate?, footerTemplate?, warnings }。其选项为 headerTemplate、footerTemplate 和 allowRemoteResources。API 装饰选项会覆盖内嵌模板。它使用浏览器原生 HTML 解析器,因此与其他所有 Core API 一样仅限浏览器运行,警告按错误恢复后的文档顺序排列。
  • pageWarningTargetBounds 返回 iframe 视口坐标下的实时 { left, top, width, height }。对来自其他文档或无法定位的警告返回 undefined。
  • hasPageDocumentFrameSandbox 仅在 sandbox 令牌恰好是公开集合(allow-same-origin 与 allow-modals)时为 true。
  • committedFrameGeneration 返回 Core 在提交时刻印在 canonical frame 上的世代;若该帧尚未提交带标记的世代,则为 undefined。用于区分尚未送达的较新提交与真正的损坏。它不读取也不校验页面 marker。
  • selectBlankMarkers 返回为满足左右页奇偶而需要空白页的 marker ID,并考虑之前的选择。marker 没有页面映射时抛出。

Core Publication

mountPublication

mountPublication(
  container: HTMLElement,
  snapshot: PublicationSnapshot,
  options?: PublicationOptions,
): PublicationController;

它把有序条目组合成一个页面序列,并同步返回。无效的快照或 Publication 扩展可能在挂载期间抛出。

app/mount-publication.ts
const controller = mountPublication(host, {
  metadata: { title: "手册", language: "zh-CN" },
  entries: [
    { id: "cover", title: "封面", html: "<h1>手册</h1>" },
    { id: "start", title: "开始", html: "<h1>开始</h1><p>第一步。</p>" },
  ],
});
const publication = await controller.ready;

PublicationSnapshot 包含 metadata: { title, language?, identifier? } 和有序条目。每个条目要求一个唯一且不含空白或控制字符的 id、一个 title、可选的 baseUrl,以及 html 或 lightDom 中恰好一个。PublicationOptions 与 PageDocumentOptions 相同,只是 extensions 只接受 PublicationExtension[],并增加 pageNumbering。设为 pageNumbering: "entry" 时,每个条目从新页开始,counter(page)、counter(pages) 和 pageNumber/totalPages 模板令牌在条目内计数,因此批量打印发票时每张发票都显示“Page 1 of 2”。页面元数据、导航、搜索、条目页码范围、扩展的 decoratePage 输入和 target 引用仍按全局计数。默认值 "publication" 对整个 Publication 编号。

PublicationController

成员返回值就绪与错误
readyPromise<PublicationDocument>首个已提交的 Publication。
currentPublicationDocument | undefined当前提交。
resolveDestination(id)PublicationDestination | undefined在当前世代中解析大纲或搜索 ID。
search(query)readonly PublicationSearchResult[]提交前为空;之后搜索当前索引。
navigate(destination)void除非完整的导航目标匹配且存在于当前世代,否则抛出。
update(snapshot, options?)Promise<PublicationDocument>校验并暂存一份完整快照;支持 options.signal。
print()Promise<void>使用页面控制器打印最近一次成功提交的行为。
destroy()Promise<void>销毁底层的页面与 Publication 资源。

PublicationDocument 在 PageDocument 基础上增加已提交的 metadata、entries 和嵌套的 outline。每个条目有一段闭区间的全局 pageRange。PublicationDestination 为 { id, entryId, page, generation };它绑定到世代,对过期值 navigate 抛出类型化 ImposiaError(STALE_PUBLICATION_DESTINATION)。搜索结果为 { entry, page, excerpt, destination }。

On this page