@sobree/core 0.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 (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/dist/__vite-browser-external-DYxpcVy9.js +5 -0
  4. package/dist/__vite-browser-external-DYxpcVy9.js.map +1 -0
  5. package/dist/blob/cache.d.ts +69 -0
  6. package/dist/blob/fetch.d.ts +18 -0
  7. package/dist/blob/hash.d.ts +13 -0
  8. package/dist/blob/index.d.ts +33 -0
  9. package/dist/blob/memory.d.ts +2 -0
  10. package/dist/blob/types.d.ts +80 -0
  11. package/dist/createSobree.d.ts +132 -0
  12. package/dist/doc/api.d.ts +132 -0
  13. package/dist/doc/builders.d.ts +42 -0
  14. package/dist/doc/pageSetupBridge.d.ts +26 -0
  15. package/dist/doc/parts.d.ts +18 -0
  16. package/dist/doc/runs.d.ts +47 -0
  17. package/dist/doc/styles.d.ts +19 -0
  18. package/dist/doc/types.d.ts +800 -0
  19. package/dist/doc/walk.d.ts +30 -0
  20. package/dist/docx/export/contentTypes.d.ts +35 -0
  21. package/dist/docx/export/context.d.ts +59 -0
  22. package/dist/docx/export/document.d.ts +19 -0
  23. package/dist/docx/export/drawings.d.ts +10 -0
  24. package/dist/docx/export/headers.d.ts +19 -0
  25. package/dist/docx/export/index.d.ts +14 -0
  26. package/dist/docx/export/runs.d.ts +8 -0
  27. package/dist/docx/export/styles.d.ts +8 -0
  28. package/dist/docx/export/zip.d.ts +13 -0
  29. package/dist/docx/import/anchoredFrames.d.ts +34 -0
  30. package/dist/docx/import/comments.d.ts +3 -0
  31. package/dist/docx/import/document.d.ts +57 -0
  32. package/dist/docx/import/flowFrames.d.ts +11 -0
  33. package/dist/docx/import/footnotes.d.ts +3 -0
  34. package/dist/docx/import/headers.d.ts +50 -0
  35. package/dist/docx/import/index.d.ts +12 -0
  36. package/dist/docx/import/inlineFrames.d.ts +62 -0
  37. package/dist/docx/import/numbering.d.ts +2 -0
  38. package/dist/docx/import/paragraph.d.ts +24 -0
  39. package/dist/docx/import/paragraphs.d.ts +27 -0
  40. package/dist/docx/import/rels.d.ts +5 -0
  41. package/dist/docx/import/runs.d.ts +64 -0
  42. package/dist/docx/import/settings.d.ts +48 -0
  43. package/dist/docx/import/styles.d.ts +3 -0
  44. package/dist/docx/import/tables.d.ts +12 -0
  45. package/dist/docx/import/unzip.d.ts +13 -0
  46. package/dist/docx/shared/namespaces.d.ts +31 -0
  47. package/dist/docx/shared/pageSize.d.ts +27 -0
  48. package/dist/docx/shared/shading.d.ts +2 -0
  49. package/dist/docx/shared/units.d.ts +35 -0
  50. package/dist/docx/shared/xml.d.ts +29 -0
  51. package/dist/docx/types.d.ts +98 -0
  52. package/dist/editor/index.d.ts +1078 -0
  53. package/dist/editor/internal/blockRegistry.d.ts +91 -0
  54. package/dist/editor/internal/mutations.d.ts +63 -0
  55. package/dist/editor/internal/positionMap.d.ts +35 -0
  56. package/dist/editor/table.d.ts +96 -0
  57. package/dist/editor/view/docRenderer/anchorLayer.d.ts +26 -0
  58. package/dist/editor/view/docRenderer/block.d.ts +13 -0
  59. package/dist/editor/view/docRenderer/fontFallback.d.ts +28 -0
  60. package/dist/editor/view/docRenderer/index.d.ts +18 -0
  61. package/dist/editor/view/docRenderer/inline.d.ts +15 -0
  62. package/dist/editor/view/docRenderer/inlineFrame.d.ts +4 -0
  63. package/dist/editor/view/docRenderer/lists.d.ts +28 -0
  64. package/dist/editor/view/docRenderer/paragraph.d.ts +2 -0
  65. package/dist/editor/view/docRenderer/properties.d.ts +2 -0
  66. package/dist/editor/view/docRenderer/table.d.ts +15 -0
  67. package/dist/editor/view/docRenderer/units.d.ts +48 -0
  68. package/dist/editor/view/docSerialize/block.d.ts +14 -0
  69. package/dist/editor/view/docSerialize/index.d.ts +8 -0
  70. package/dist/editor/view/docSerialize/inline.d.ts +11 -0
  71. package/dist/editor/view/docSerialize/table.d.ts +12 -0
  72. package/dist/editor/view/imageResize.d.ts +16 -0
  73. package/dist/embed/floatingCorner.d.ts +44 -0
  74. package/dist/embed/viewport.d.ts +133 -0
  75. package/dist/fonts/embedAPI.d.ts +33 -0
  76. package/dist/fonts/emit.d.ts +24 -0
  77. package/dist/fonts/fontFaceRegistry.d.ts +20 -0
  78. package/dist/fonts/fsType.d.ts +36 -0
  79. package/dist/fonts/index.d.ts +19 -0
  80. package/dist/fonts/liveness.d.ts +2 -0
  81. package/dist/fonts/odttf.d.ts +33 -0
  82. package/dist/fonts/parse.d.ts +29 -0
  83. package/dist/fonts/types.d.ts +52 -0
  84. package/dist/headless.d.ts +168 -0
  85. package/dist/history/history.d.ts +100 -0
  86. package/dist/history/index.d.ts +4 -0
  87. package/dist/history/types.d.ts +54 -0
  88. package/dist/index.css +1 -0
  89. package/dist/index.d.ts +52 -0
  90. package/dist/index.js +10561 -0
  91. package/dist/index.js.map +1 -0
  92. package/dist/markdown/parse.d.ts +6 -0
  93. package/dist/pagination/cost.d.ts +32 -0
  94. package/dist/pagination/index.d.ts +2 -0
  95. package/dist/pagination/paginate.d.ts +10 -0
  96. package/dist/pagination/postConditions.d.ts +10 -0
  97. package/dist/pagination/types.d.ts +94 -0
  98. package/dist/paperStack/pageSetup.d.ts +42 -0
  99. package/dist/paperStack/paginationAdapter/buildItems.d.ts +19 -0
  100. package/dist/paperStack/paginationAdapter/distribute.d.ts +23 -0
  101. package/dist/paperStack/paginationAdapter/index.d.ts +18 -0
  102. package/dist/paperStack/paginationAdapter/paragraphLines.d.ts +23 -0
  103. package/dist/paperStack/paginationAdapter/splitList.d.ts +19 -0
  104. package/dist/paperStack/paginationAdapter/splitParagraph.d.ts +21 -0
  105. package/dist/paperStack/paginationAdapter/types.d.ts +30 -0
  106. package/dist/paperStack/paper.d.ts +107 -0
  107. package/dist/paperStack/paperStack.d.ts +245 -0
  108. package/dist/plugin.d.ts +24 -0
  109. package/dist/plugins/marks.d.ts +49 -0
  110. package/dist/plugins/sections.d.ts +15 -0
  111. package/dist/presence/attach.d.ts +48 -0
  112. package/dist/presence/awareness.d.ts +28 -0
  113. package/dist/presence/index.d.ts +19 -0
  114. package/dist/presence/overlay.d.ts +28 -0
  115. package/dist/presence/state.d.ts +36 -0
  116. package/dist/sobree.d.ts +211 -0
  117. package/dist/tokens.css +144 -0
  118. package/dist/util/selection.d.ts +13 -0
  119. package/dist/ydoc/apply.d.ts +68 -0
  120. package/dist/ydoc/index.d.ts +18 -0
  121. package/dist/ydoc/project.d.ts +41 -0
  122. package/dist/ydoc/runs.d.ts +51 -0
  123. package/dist/ydoc/schema.d.ts +123 -0
  124. package/dist/ydoc/seed.d.ts +45 -0
  125. package/dist/ydoc/textDiff.d.ts +59 -0
  126. package/dist/zoneEdit/index.d.ts +22 -0
  127. package/package.json +61 -0
@@ -0,0 +1,6 @@
1
+ import { SobreeDocument } from '../doc/types';
2
+ /**
3
+ * Parse a Markdown string into a `SobreeDocument`. Always returns a
4
+ * valid document; unsupported syntax falls through as plain text.
5
+ */
6
+ export declare function parseMarkdown(md: string): SobreeDocument;
@@ -0,0 +1,32 @@
1
+ import { Box, Candidate, Item, ResolvedConfig } from './types';
2
+ /**
3
+ * Score a candidate break. Lower is better.
4
+ *
5
+ * totalCost = underfullWeight * leftover²
6
+ * + own penalty cost
7
+ * + widow/orphan penalty
8
+ * + keep-with-next penalty
9
+ * + keep-together penalty
10
+ *
11
+ * `start` is the index of the first item on the current page — needed so we
12
+ * only count paragraph lines that live on this page (not on earlier ones).
13
+ */
14
+ export declare function scoreBreak(items: Item[], start: number, c: Candidate, cfg: ResolvedConfig): number;
15
+ /** Penalty for breaking inside a paragraph and leaving a widow or orphan. */
16
+ export declare function widowOrphanPenalty(items: Item[], start: number, c: Candidate, cfg: ResolvedConfig): number;
17
+ /**
18
+ * +Infinity if the break is between a keepWithNext paragraph and whatever
19
+ * follows. The only case we *don't* forbid is when the break is between two
20
+ * lines of the same paragraph (widow/orphan's concern, not keep-with-next's).
21
+ */
22
+ export declare function keepWithNextPenalty(items: Item[], c: Candidate): number;
23
+ /** Penalty for breaking inside a keepTogether paragraph. */
24
+ export declare function keepTogetherPenalty(items: Item[], c: Candidate, cfg: ResolvedConfig): number;
25
+ export declare function nearestBoxBefore(items: Item[], idxExclusive: number): Box | null;
26
+ export declare function nearestBoxAfter(items: Item[], idxInclusive: number): Box | null;
27
+ export declare function countParagraphLinesOnPageBefore(items: Item[], start: number, pageEnd: number, pid: string): number;
28
+ export declare function countParagraphLinesOnNextPage(items: Item[], nextStart: number, pid: string): number;
29
+ /** Sum of box + inter-line glue heights for the paragraph beginning at startIdx. */
30
+ export declare function sumParagraphHeight(items: Item[], startIdx: number): number;
31
+ export declare function isGlueBetweenBoxes(items: Item[], idx: number): boolean;
32
+ export declare function isGlueInsideKeepTogether(items: Item[], idx: number): boolean;
@@ -0,0 +1,2 @@
1
+ export { paginate } from './paginate';
2
+ export type { Box, Config, Glue, Item, Page, Penalty, ResolvedConfig, } from './types';
@@ -0,0 +1,10 @@
1
+ import { Config, Item, Page } from './types';
2
+ /**
3
+ * Greedy one-pass paginator. See README.md for the full cost model.
4
+ *
5
+ * Walk the item stream, accumulating page height and a list of candidate
6
+ * break positions. When the next item overflows — or a forced penalty
7
+ * appears — pick the candidate that minimises totalCost (see scoreBreak),
8
+ * emit the page, and continue from the chosen break.
9
+ */
10
+ export declare function paginate(items: Item[], config: Config): Page[];
@@ -0,0 +1,10 @@
1
+ import { Candidate, Item, ResolvedConfig } from './types';
2
+ /**
3
+ * If the chosen break still violates widow/orphan (despite the penalty in
4
+ * scoring), walk the candidate list backward and pick the nearest earlier
5
+ * candidate that doesn't violate — "back off the break by one line" in the
6
+ * spec — effectively one paragraph line moves to the next page.
7
+ *
8
+ * Returns the original `best` if no earlier candidate avoids the violation.
9
+ */
10
+ export declare function backOffIfViolates(items: Item[], start: number, best: Candidate, candidates: Candidate[], cfg: ResolvedConfig): Candidate;
@@ -0,0 +1,94 @@
1
+ /** A single line or image-like unit. Contributes height. */
2
+ export interface Box {
3
+ type: "box";
4
+ height: number;
5
+ /** Identifier shared by all lines of the same paragraph. */
6
+ paragraphId?: string;
7
+ isFirstLineOfParagraph?: boolean;
8
+ isLastLineOfParagraph?: boolean;
9
+ /** If true, the box is never split across a page break. */
10
+ monolithic?: boolean;
11
+ /** Paragraph-level: this paragraph must stay adjacent to the next. */
12
+ keepWithNext?: boolean;
13
+ /** Paragraph-level: all lines of this paragraph must fit on one page. */
14
+ keepTogether?: boolean;
15
+ }
16
+ /** Whitespace. Discarded at page edges when it ends up there. */
17
+ export interface Glue {
18
+ type: "glue";
19
+ height: number;
20
+ }
21
+ /**
22
+ * A break point annotation with a finite cost, or a forced break
23
+ * (-Infinity), or a forbidden break (+Infinity).
24
+ */
25
+ export interface Penalty {
26
+ type: "penalty";
27
+ cost: number;
28
+ }
29
+ export type Item = Box | Glue | Penalty;
30
+ export interface Config {
31
+ /** Default page height in px. Used for any page index not covered
32
+ * by `pageHeights`. */
33
+ pageHeight: number;
34
+ /**
35
+ * Per-page height overrides. Entry `i` is the budget for page index
36
+ * `i`; missing/undefined entries fall back to `pageHeight`. Lets
37
+ * callers shrink the body budget on specific pages (e.g. pages with
38
+ * footnote zones eating space at the bottom) without penalising
39
+ * pages that don't need it.
40
+ */
41
+ pageHeights?: readonly number[];
42
+ /** Minimum lines of a paragraph on the new page. Default 2. */
43
+ widows?: number;
44
+ /** Minimum lines of a paragraph on the current page. Default 2. */
45
+ orphans?: number;
46
+ /** Multiplier for underfull penalty (leftover²). Default 1.0. */
47
+ underfullWeight?: number;
48
+ /** Added when a candidate break would leave a widow or orphan. Default 10000. */
49
+ widowOrphanPenalty?: number;
50
+ /** Added to breaks inside keepTogether ranges; used for keep-with-next. Default 10000. */
51
+ keepPenalty?: number;
52
+ }
53
+ export interface ResolvedConfig {
54
+ pageHeight: number;
55
+ pageHeights?: readonly number[];
56
+ widows: number;
57
+ orphans: number;
58
+ underfullWeight: number;
59
+ widowOrphanPenalty: number;
60
+ keepPenalty: number;
61
+ }
62
+ export interface Page {
63
+ items: Item[];
64
+ /** Total box + glue height, excluding trailing glue. */
65
+ usedHeight: number;
66
+ /** Cost of the chosen break ending this page; 0 for forced / end-of-stream. */
67
+ cost: number;
68
+ }
69
+ /**
70
+ * Candidate break position.
71
+ *
72
+ * `pageEnd` is the exclusive upper bound of the current page's items — on a
73
+ * glue break the glue is INCLUDED (trailing glue stays on the current page
74
+ * for round-tripping), so pageEnd = glueIdx + 1. On a penalty break the
75
+ * penalty is EXCLUDED (consumed), so pageEnd = penaltyIdx.
76
+ *
77
+ * `nextStart` is the first item of the next page. On a penalty break it is
78
+ * penaltyIdx + 1 (the penalty is consumed). On a glue break it equals
79
+ * pageEnd.
80
+ *
81
+ * `heightAt` is the accumulated page height just *before* the candidate item
82
+ * — glue is not counted against the page's useful height.
83
+ */
84
+ export interface Candidate {
85
+ pageEnd: number;
86
+ nextStart: number;
87
+ heightAt: number;
88
+ ownCost: number;
89
+ }
90
+ export declare const DEFAULTS: Omit<ResolvedConfig, "pageHeight">;
91
+ export declare function resolveConfig(cfg: Config): ResolvedConfig;
92
+ /** Effective page budget for `pageIdx` — per-page override if present,
93
+ * global `pageHeight` otherwise. */
94
+ export declare function pageHeightAt(cfg: ResolvedConfig, pageIdx: number): number;
@@ -0,0 +1,42 @@
1
+ export type PageSizeKey = "A3" | "A4" | "A5" | "B5" | "Letter" | "Legal" | "Tabloid";
2
+ export interface PageSizeMM {
3
+ width: number;
4
+ height: number;
5
+ }
6
+ export declare const PAGE_SIZES: Record<PageSizeKey, PageSizeMM>;
7
+ export type Orientation = "portrait" | "landscape";
8
+ export interface Margins {
9
+ top: number;
10
+ right: number;
11
+ bottom: number;
12
+ left: number;
13
+ }
14
+ export interface PageZoneText {
15
+ default: string;
16
+ first: string;
17
+ last: string;
18
+ differentFirst: boolean;
19
+ differentLast: boolean;
20
+ }
21
+ /** Vertical alignment of body content on every page — OOXML `<w:vAlign>`. */
22
+ export type VerticalAlign = "top" | "center" | "bottom" | "both";
23
+ export interface PageSetup {
24
+ size: PageSizeKey;
25
+ orientation: Orientation;
26
+ margins: Margins;
27
+ header: PageZoneText;
28
+ footer: PageZoneText;
29
+ /** Section-level vertical alignment. Default `"top"`. */
30
+ verticalAlign: VerticalAlign;
31
+ }
32
+ export declare const DEFAULT_PAGE_SETUP: PageSetup;
33
+ export declare function resolvedDimensions(setup: PageSetup): {
34
+ widthMM: number;
35
+ heightMM: number;
36
+ };
37
+ export declare function substituteVariables(template: string, ctx: {
38
+ page: number;
39
+ pages: number;
40
+ }): string;
41
+ /** Pick the raw zone template for a given page, honouring first/last overrides. */
42
+ export declare function zoneTemplateFor(zone: PageZoneText, page: number, pages: number): string;
@@ -0,0 +1,19 @@
1
+ import { DomItem } from './types';
2
+ /**
3
+ * Convert a flat list of top-level block elements into an Item stream for
4
+ * the pagination engine.
5
+ *
6
+ * Per-block handling:
7
+ * - `.page-break` / `[data-page-break]` → Penalty(-Infinity) + zero-height Box
8
+ * (element still lands at the top of the next page for round-tripping).
9
+ * - `<figure>` / `.keep-together` / `[data-keep-together]` → monolithic Box
10
+ * (whole block moves together; doesn't split).
11
+ * - `<table>`, `<pre>` → monolithic Box.
12
+ * - h1–h6 → Box with `keepWithNext: true`.
13
+ * - `<p>` with ≥2 line boxes → one Box per line (shared paragraphId,
14
+ * first/last flags set) so widow/orphan can act per line.
15
+ * - Otherwise → one Box with the element's measured height.
16
+ *
17
+ * Inter-block glue(0) makes every inter-block position a candidate break.
18
+ */
19
+ export declare function buildItems(blocks: HTMLElement[]): DomItem[];
@@ -0,0 +1,23 @@
1
+ import { Page } from '../../pagination/types';
2
+ /**
3
+ * Turn the paginator's `Page[]` into a per-page array of DOM elements.
4
+ *
5
+ * Two flavours of split:
6
+ *
7
+ * - **Multi-line `<p>` straddling a page boundary**: split the `<p>`
8
+ * at the character offset of the first line on the later page.
9
+ * Original keeps the head fragment; a clone (same tag, attributes
10
+ * preserved, data-pag-continuation stamped) holds the tail.
11
+ * - **Multi-line `<li>` straddling a page boundary**: same machinery
12
+ * — `<li>` is treated like `<p>` by `buildItems`, so the per-line
13
+ * boxes route through `splitParagraphAcrossPages` too. Continuation
14
+ * `<li>` fragments are tagged so CSS can hide their list marker.
15
+ *
16
+ * On top of per-element splits, `<li>` elements need re-wrapping into
17
+ * per-page `<ol>` / `<ul>` clones (you can't have a bare `<li>` at
18
+ * paper-content level — its marker won't render). The third pass
19
+ * groups consecutive same-source LIs into per-page list-container
20
+ * clones with the right `start` attribute so numbering continues
21
+ * across page breaks.
22
+ */
23
+ export declare function distributePages(pages: Page[]): HTMLElement[][];
@@ -0,0 +1,18 @@
1
+ /**
2
+ * DOM → pagination-engine adapter for PaperStack.
3
+ *
4
+ * 1. `buildItems` walks the blocks and emits the Item stream — one Box
5
+ * per block (or one per paragraph line), plus penalties for page-break
6
+ * markers and monolithic flags for figures / keep-together groups.
7
+ * 2. `paginate` (the pure engine in `src/pagination`) produces Pages.
8
+ * 3. `distributePages` turns Pages into a per-page list of DOM elements,
9
+ * physically splitting paragraphs that straddle page boundaries.
10
+ *
11
+ * Features honoured:
12
+ * - Widow/orphan at the line level for `<p>` elements.
13
+ * - Keep-with-next for headings (h1–h6).
14
+ * - Keep-together for `<figure>`, `.keep-together`, `[data-keep-together]`.
15
+ * - Forced page breaks for `.page-break` / `[data-page-break]` markers.
16
+ * - Tables and code blocks remain monolithic.
17
+ */
18
+ export declare function paginateBlocks(blocks: HTMLElement[], pageContentHeightPx: number, pageHeightsPx?: readonly number[]): HTMLElement[][];
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Measure the individual line boxes of a paragraph-like element using
3
+ * `Range.getClientRects()`. The returned metrics let the paginator treat
4
+ * each line as its own `Box` so widow/orphan rules can act per line.
5
+ *
6
+ * Fast path uses binary search — O(L · log N) per paragraph for L lines
7
+ * and N characters (versus O(N) for a per-character linear walk).
8
+ */
9
+ export interface LineMetric {
10
+ lineIndex: number;
11
+ /** Natural height of the line box in CSS px. */
12
+ height: number;
13
+ /** Character offset within the element where the line starts. */
14
+ startCharOffset: number;
15
+ /** Character offset (exclusive) where the line ends. */
16
+ endCharOffset: number;
17
+ }
18
+ export declare function measureParagraphLines(el: HTMLElement): LineMetric[];
19
+ /** Resolve a character offset (0-based, counting only text chars) to (textNode, nodeOffset). */
20
+ export declare function nodeAtCharOffset(el: HTMLElement, charOffset: number): {
21
+ node: Text;
22
+ offset: number;
23
+ } | null;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Split an `<ol>` / `<ul>` into two sibling list elements at the given
3
+ * child index. The original keeps `<li>`s `[0, liIndex)`; a new sibling
4
+ * (same tag + cloned attributes) is inserted immediately after and
5
+ * receives `<li>`s `[liIndex, end)`. Returns the new (tail) element.
6
+ *
7
+ * Why this exists: paragraphs can split mid-character via
8
+ * `splitElementAtCharOffset`, but lists need to split at `<li>`
9
+ * boundaries — both because the LI is the smallest paginable unit AND
10
+ * because mid-LI splits would require duplicating the marker (number /
11
+ * bullet) which is browser-rendered.
12
+ *
13
+ * For ordered lists, the tail clone gets a `start` attribute so the
14
+ * second fragment continues numbering from where the first left off.
15
+ * `start` is computed from the head's surviving `<li>` count plus the
16
+ * head's own `start` attribute (defaults to 1) — handles already-split
17
+ * fragments correctly.
18
+ */
19
+ export declare function splitListAtChild(el: HTMLElement, liIndex: number): HTMLElement;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Split `el` into two sibling elements at the given character offset. The
3
+ * original keeps [0, charOffset); a new element (same tag + attributes) is
4
+ * inserted immediately after and receives [charOffset, end). Returns the
5
+ * new (bottom) element.
6
+ *
7
+ * Uses `Range.extractContents()` to move the tail into a fragment; preserves
8
+ * element boundaries within the `<p>` (e.g. `<strong>`, `<code>` are cloned
9
+ * if the split falls mid-element).
10
+ */
11
+ export declare function splitElementAtCharOffset(el: HTMLElement, charOffset: number): HTMLElement;
12
+ /**
13
+ * Move a split offset backward to the nearest word boundary (whitespace) so
14
+ * words are never cut in half. We don't have a proper line-breaking engine,
15
+ * so keeping words intact is the rule.
16
+ *
17
+ * Returns 0 if no whitespace is found before `offset` (rare — long single
18
+ * word); callers should skip splitting in that case and let the paragraph
19
+ * overflow rather than break mid-word.
20
+ */
21
+ export declare function snapToWordBoundary(el: HTMLElement, offset: number): number;
@@ -0,0 +1,30 @@
1
+ import { Box, Glue, Penalty } from '../../pagination/types';
2
+ /**
3
+ * Box that carries the DOM element it came from. For multi-line paragraphs,
4
+ * a single `<p>` contributes multiple DomBoxes — each with the same `el` and
5
+ * a distinct `lineIndex`. For lists, a single `<ol>` / `<ul>` contributes
6
+ * one DomBox per `<li>` child, each with the same `el` and a distinct
7
+ * `liIndex` — the distribution step uses these to clone the parent list
8
+ * and move tail `<li>`s into per-page fragments, mirroring how multi-line
9
+ * paragraphs are split.
10
+ */
11
+ export interface DomBox extends Box {
12
+ el: HTMLElement;
13
+ /** 0-based line within the paragraph, when `el` is a split paragraph. */
14
+ lineIndex?: number;
15
+ /** Total lines of the paragraph. */
16
+ totalLines?: number;
17
+ /** 0-based li index within an `<ol>` / `<ul>` parent, when `el` is the list. */
18
+ liIndex?: number;
19
+ /** Total `<li>` children in the parent list. */
20
+ totalLis?: number;
21
+ /** Source `<tr>` when this box represents a paragraph emitted by
22
+ * per-paragraph row-content splitting (tall rows). `el` points at the
23
+ * cell-level paragraph; `cellTr` lets `distributePages` clone the TR
24
+ * per page and route the paragraph into the matching cell clone. */
25
+ cellTr?: HTMLElement;
26
+ /** Marks the FIRST box of a tall row's per-paragraph stream so distribute
27
+ * can move non-dominant-cell content (labels, …) onto that fragment. */
28
+ isFirstParaOfRow?: boolean;
29
+ }
30
+ export type DomItem = DomBox | Glue | Penalty;
@@ -0,0 +1,107 @@
1
+ import { PageSetup } from './pageSetup';
2
+ import { AnchorLayerContext } from '../editor/view/docRenderer/anchorLayer';
3
+ import { AnchoredFrame, Block, NamedStyle, NumberingDefinition, SectionProperties } from '../doc/types';
4
+ export interface ZoneRenderContext {
5
+ blocks: readonly Block[];
6
+ numbering: readonly NumberingDefinition[];
7
+ styles: readonly NamedStyle[];
8
+ rawParts: Record<string, Uint8Array>;
9
+ pageNumber: number;
10
+ totalPages: number;
11
+ }
12
+ /**
13
+ * A single paper — exactly one page. Fixed width and height from the page
14
+ * setup. Has a header zone, a content area, and a footer zone. The content
15
+ * area is where editable blocks live (the PaperStack assigns them here).
16
+ *
17
+ * Header/footer elements are contentEditable=false; the content area inherits
18
+ * editability from the PaperStack root.
19
+ */
20
+ export declare class Paper {
21
+ /**
22
+ * Outer row container — holds the paper card + the right-side
23
+ * comments sidebar. `PaperStack` appends this to its root; CSS uses
24
+ * flex layout so comments sit beside (not inside) the paper.
25
+ */
26
+ readonly outer: HTMLElement;
27
+ /** The paper card itself — sized to the page dimensions. */
28
+ readonly root: HTMLElement;
29
+ readonly content: HTMLElement;
30
+ /**
31
+ * Per-page footnote zone. Sits between body content and the footer
32
+ * INSIDE the paper card. Populated by `PaperStack` after pagination
33
+ * distributes footnote bodies to the page where their referencing
34
+ * `<sup>` landed. Empty zones get `is-empty` for CSS hiding.
35
+ */
36
+ readonly footnotes: HTMLElement;
37
+ /**
38
+ * Per-page floating-object overlay. Absolute-positioned children
39
+ * (anchored textboxes, decorative shapes, anchored pictures) live
40
+ * here, painted on top of `content` by the renderer's anchor-layer
41
+ * module. The paginator never sees these — flow content and
42
+ * floating content are fully decoupled.
43
+ */
44
+ readonly anchors: HTMLElement;
45
+ /**
46
+ * Per-page side gutter — sits to the RIGHT of the paper card
47
+ * (sibling of `root`, child of `outer`). Core leaves it empty (and
48
+ * `is-empty`, so it collapses); the `@sobree/review` plugin fills it
49
+ * with comment cards. Kept in core as a stable mount point so the
50
+ * `.paper-row` flex layout — which the viewport's fit-to-width
51
+ * depends on — doesn't shift when a plugin attaches or detaches.
52
+ */
53
+ readonly comments: HTMLElement;
54
+ private readonly header;
55
+ private readonly footer;
56
+ constructor(container: HTMLElement, setup: PageSetup);
57
+ applySetup(setup: PageSetup): void;
58
+ /**
59
+ * Apply per-section settings on top of the base PageSetup. Currently
60
+ * just `vAlign` — extends naturally to per-section page size, margins,
61
+ * column counts, etc. when those land. Idempotent; called by
62
+ * PaperStack after pagination distributes content.
63
+ */
64
+ applySectionOverride(section: SectionProperties): void;
65
+ /**
66
+ * Render the header zone from the rich AST. Uses the same `renderBlocks`
67
+ * walker as body content so drawings, formatting, hyperlinks and
68
+ * tables all carry through. `PAGE` / `NUMPAGES` field nodes are
69
+ * substituted with this paper's page number / the total count.
70
+ */
71
+ setHeaderBlocks(ctx: ZoneRenderContext): void;
72
+ setFooterBlocks(ctx: ZoneRenderContext): void;
73
+ /**
74
+ * When a rich header (or footer) renders taller than the page's
75
+ * reserved margin, push body content out of the overlap.
76
+ *
77
+ * Word's behaviour: if header content exceeds `pgMar.top`, the body
78
+ * yields downward. Same for footer + `pgMar.bottom`. Our paper
79
+ * normally sets `padding-top: var(--margin-top)`; we override here to
80
+ * `max(--margin-top, headerOffsetHeight)` (resp. for footer) so the
81
+ * body's first paragraph never sits underneath the rendered header.
82
+ *
83
+ * The override is purely visual — the paginator still uses
84
+ * `setup.margins.top/bottom` for its budget, so pages with very tall
85
+ * headers may end up packing fewer body lines than expected. That's
86
+ * a follow-up: feed the observed zone heights back into
87
+ * `pageContentHeightPx` so pagination matches Word's effective body
88
+ * area.
89
+ */
90
+ private applyZoneOverflowPadding;
91
+ /**
92
+ * Plain-text fallback for callers that don't have rich blocks (legacy
93
+ * page-setup modal templates that render to a single line of text).
94
+ * Mirrors what `setHeaderBlocks` would do for an "x of y"-style
95
+ * paragraph; kept as a separate method to keep the call sites obvious.
96
+ */
97
+ setHeaderText(text: string): void;
98
+ setFooterText(text: string): void;
99
+ /**
100
+ * Replace the anchor layer with frames whose anchor resolves to this
101
+ * page. Idempotent — the old layer is wiped before painting the new
102
+ * one. Pass `frames=[]` to clear the layer (sets `is-empty` so the
103
+ * pointer-events-blocking overlay collapses out of the way).
104
+ */
105
+ setAnchoredFrames(frames: readonly AnchoredFrame[], ctx: AnchorLayerContext): void;
106
+ destroy(): void;
107
+ }