@sobree/core 0.1.28 → 0.1.30

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 (43) hide show
  1. package/dist/doc/mutations/blocks.d.ts +14 -0
  2. package/dist/doc/mutations/index.d.ts +38 -0
  3. package/dist/doc/mutations/numbering.d.ts +8 -0
  4. package/dist/doc/mutations/paragraphs.d.ts +13 -0
  5. package/dist/doc/mutations/sections.d.ts +40 -0
  6. package/dist/doc/mutations/styles.d.ts +14 -0
  7. package/dist/doc/mutations/types.d.ts +57 -0
  8. package/dist/doc/types/block.d.ts +182 -0
  9. package/dist/doc/types/document.d.ts +122 -0
  10. package/dist/doc/types/drawing.d.ts +141 -0
  11. package/dist/doc/types/headersFooters.d.ts +7 -0
  12. package/dist/doc/types/index.d.ts +34 -0
  13. package/dist/doc/types/numbering.d.ts +25 -0
  14. package/dist/doc/types/paragraph.d.ts +82 -0
  15. package/dist/doc/types/parts.d.ts +18 -0
  16. package/dist/doc/types/revisions.d.ts +8 -0
  17. package/dist/doc/types/runs.d.ts +178 -0
  18. package/dist/doc/types/sections.d.ts +67 -0
  19. package/dist/doc/types/styles.d.ts +32 -0
  20. package/dist/doc/types.d.ts +7 -842
  21. package/dist/editor/index.d.ts +7 -2
  22. package/dist/editor/internal/applyMutation.d.ts +9 -0
  23. package/dist/editor/internal/mutations.d.ts +4 -64
  24. package/dist/editor/ops/blocks.d.ts +5 -4
  25. package/dist/editor/renderedDocument/blocks.d.ts +14 -0
  26. package/dist/editor/renderedDocument/comments.d.ts +6 -0
  27. package/dist/editor/renderedDocument/index.d.ts +27 -0
  28. package/dist/editor/renderedDocument/revisions.d.ts +11 -0
  29. package/dist/editor/renderedDocument/selectors.d.ts +51 -0
  30. package/dist/editor/renderedDocument/types.d.ts +59 -0
  31. package/dist/editor/table.d.ts +17 -11
  32. package/dist/headless.d.ts +14 -5
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.js +5154 -4829
  35. package/dist/index.js.map +1 -1
  36. package/dist/ydoc/apply.d.ts +7 -2
  37. package/dist/ydoc/blockCodec.d.ts +55 -0
  38. package/dist/ydoc/frameCodec.d.ts +33 -0
  39. package/dist/ydoc/index.d.ts +3 -2
  40. package/dist/ydoc/project.d.ts +1 -6
  41. package/dist/ydoc/schema.d.ts +66 -8
  42. package/dist/ydoc/seed.d.ts +2 -33
  43. package/package.json +1 -1
@@ -1,845 +1,10 @@
1
- import { BorderSpec, Shading, TableBorders, TableCellBorders, TableCellMargins } from './formatting.types';
2
- import { TableLook, TableStyleDefinition } from './tableStyle.types';
3
- import { FontDeclaration as _FontDeclaration } from '../fonts/types';
4
- export type { BorderSpec, Shading, TableBorders, TableCellBorders, TableCellMargins, } from './formatting.types';
5
- export type { TableConditionalType, TableLook, TableStyleCellFormat, TableStyleDefinition, } from './tableStyle.types';
6
- export interface SobreeDocument {
7
- /** Top-level body content, in document order. */
8
- body: Block[];
9
- /**
10
- * One section per body slice. The simplest doc has exactly one section
11
- * spanning the whole body. Phase N1 supports a single-section model.
12
- */
13
- sections: SectionProperties[];
14
- /**
15
- * Header and footer bodies keyed by `HeaderFooterRef.partId`. The partId
16
- * is the ZIP target name (`header1.xml`, `footer2.xml`, …). Rendering
17
- * emits each body to its own OOXML part at export time.
18
- */
19
- headerFooterBodies: Record<string, Block[]>;
20
- /**
21
- * Floating objects that live inside a header/footer part, keyed by the
22
- * SAME `HeaderFooterRef.partId` as `headerFooterBodies`. A header part
23
- * is a self-contained sub-document: its flow blocks live in
24
- * `headerFooterBodies[partId]`, its anchored frames here. The renderer
25
- * paints these into a per-zone overlay exactly like body `anchoredFrames`.
26
- * Empty/absent for the common header-without-floats case.
27
- */
28
- headerFooterFrames?: Record<string, AnchoredFrame[]>;
29
- /** Named styles (Heading1, Quote, Body Text, …) defined at the doc level. */
30
- styles: NamedStyle[];
31
- /** List/numbering definitions referenced by `Paragraph.properties.numbering`. */
32
- numbering: NumberingDefinition[];
33
- /**
34
- * Embedded binary parts keyed by ZIP path (e.g. `word/media/image1.png`).
35
- * Images, fonts, custom XML — anything not represented in body XML.
36
- */
37
- rawParts: Record<string, Uint8Array>;
38
- /**
39
- * Font declarations from `word/fontTable.xml`. Empty for new docs.
40
- * Embedded faces reference parts inside `rawParts`.
41
- */
42
- fonts: FontDeclaration[];
43
- /**
44
- * Footnote bodies keyed by id. Body inline runs use `FootnoteRefRun`
45
- * with the matching `id` to reference them. Empty for docs without
46
- * footnotes (the common case).
47
- */
48
- footnotes?: Record<number, Block[]>;
49
- /**
50
- * Comments keyed by id. Body inline runs whose properties carry a
51
- * matching `commentIds` mark the range each comment annotates.
52
- * Empty for docs without comments (the common case).
53
- */
54
- comments?: Record<number, Comment>;
55
- /**
56
- * Document-wide layout settings parsed from `word/settings.xml`.
57
- * Currently only `defaultTabStopTwips` — Word's default interval for
58
- * tab advances in paragraphs that don't declare their own `<w:tabs>`
59
- * stops. Word's factory default is 720 twips (0.5"). Without
60
- * respecting this, the browser falls back to the CSS `tab-size`
61
- * default of 8 characters which is much narrower than what Word
62
- * shows, and tab-aligned content (e.g. label/value columns in
63
- * letterheads) ends up cramped.
64
- */
65
- settings?: {
66
- defaultTabStopTwips?: number;
67
- };
68
- /**
69
- * NOTE: inline-drawing frames are emitted as `InlineFrame` BLOCKS
70
- * directly in `body` (the importer splices them in at their source
71
- * paragraph's position via `ConvertOptions.replaceParagraphs`), so
72
- * they paginate in document flow. This optional top-level list is
73
- * a secondary handle kept for tooling/inspection; the renderer
74
- * consumes the body blocks, not this list.
75
- *
76
- * The first-class model replaced the old `liftTextBoxContent`
77
- * machinery that exploded section-heading textboxes into body
78
- * paragraphs with synthetic `framePictures` / `liftedFromTextBox`
79
- * metadata. See `packages/core/docs/INLINE_FRAME_DESIGN.md`.
80
- */
81
- inlineFrames?: InlineFrame[];
82
- /**
83
- * Floating objects (`<w:drawing>/<wp:anchor>`, `<w:pict>` VML) that
84
- * live in their own layer above the body. Each frame carries its
85
- * own coordinates + dimensions in EMU and is independent of
86
- * pagination — the paginator only sees `body` blocks. The renderer
87
- * places each frame on the page its anchor resolves to and paints
88
- * it into a per-page `<div class="paper-anchors">` overlay.
89
- *
90
- * Replaces the pre-AnchoredFrame "lifter" architecture where the
91
- * importer exploded each `<w:txbxContent>` into N body paragraphs
92
- * with synthetic `liftedFromTextBox` metadata. The flat list here
93
- * is simpler, makes selection / resize / move trivial (each frame
94
- * is one DOM element), and frees the paginator from having to
95
- * route around absolute-positioned ghosts.
96
- */
97
- anchoredFrames?: AnchoredFrame[];
98
- }
99
1
  /**
100
- * A floating object pinned to a page or paragraph at an explicit
101
- * coordinate. Sources: `<w:drawing>/<wp:anchor>` shapes,
102
- * `<w:pict>` VML boxes.
2
+ * Compatibility barrel for Sobree's document model.
103
3
  *
104
- * Coordinates use OOXML's EMU (914400 EMU = 1 inch). The renderer
105
- * converts to CSS millimetres at paint time.
4
+ * The model is split into concept-owned modules under `./types/` (one per
5
+ * document concept: blocks, runs, paragraphs, tables, sections, styles,
6
+ * numbering, drawing, …). This file preserves the historical
7
+ * `doc/types` import path so every consumer keeps importing AST types from
8
+ * one place — adding or moving a concept file never touches a caller.
106
9
  */
107
- export interface AnchoredFrame {
108
- /** Stable id, deterministic from document import order. */
109
- id: string;
110
- /** What the offsets are measured from. */
111
- anchor: AnchorOrigin;
112
- offsetXEmu: number;
113
- offsetYEmu: number;
114
- widthEmu: number;
115
- heightEmu: number;
116
- /** Stacking order. Higher = on top. Default 0. */
117
- zIndex?: number;
118
- /** When true the frame paints BEHIND body text (z-index negative).
119
- * Maps to OOXML `<wp:anchor behindDoc="1">`. */
120
- behindText?: boolean;
121
- /** Text-wrap mode from the `<wp:wrap*>` child of `<wp:anchor>`.
122
- * Decides whether the frame DISPLACES body flow: `square` /
123
- * `topAndBottom` / `tight` / `through` reserve vertical space (the
124
- * paginator treats the anchor paragraph as that tall), while `none`
125
- * floats over text and reserves nothing. Absent ⇒ unknown (treated
126
- * as non-displacing). */
127
- wrap?: "square" | "topAndBottom" | "tight" | "through" | "none";
128
- /** `wrapText` side from `<wp:wrapSquare|Tight|Through wrapText="…">` —
129
- * which sides of the frame body text flows on. Default `bothSides`.
130
- * Only meaningful for the displacing wrap modes; drives whether a
131
- * floated image goes `float: left` (text on the right) or `right`. */
132
- wrapText?: "bothSides" | "left" | "right" | "largest";
133
- /** Text-distance insets — `distT/B/L/R` on `<wp:anchor>`, in EMU. The
134
- * gap Word keeps between the frame and the text wrapping around it;
135
- * rendered as margins on the floated frame. */
136
- textDistancesEmu?: {
137
- topEmu: number;
138
- rightEmu: number;
139
- bottomEmu: number;
140
- leftEmu: number;
141
- };
142
- /** What this frame contains. */
143
- content: AnchoredContent;
144
- }
145
- /**
146
- * Where an anchored frame is positioned and which page receives it.
147
- *
148
- * - `sectionIndex` decides which section's pages are candidates.
149
- * - `paragraphIndex` (optional) ties the frame to a specific body
150
- * paragraph — useful when `verticalFrom: "paragraph"` so the
151
- * frame floats to whichever page the paragraph paginates onto.
152
- * When absent, the frame is page-relative (lands on the first
153
- * page of its section).
154
- * - `horizontalFrom` / `verticalFrom` mirror OOXML's
155
- * `relativeFromH` / `relativeFromV` enums.
156
- */
157
- export interface AnchorOrigin {
158
- sectionIndex: number;
159
- paragraphIndex?: number;
160
- horizontalFrom: "page" | "margin" | "column";
161
- verticalFrom: "page" | "margin" | "paragraph";
162
- }
163
- /**
164
- * What an AnchoredFrame contains. Closed union — adding a new variant
165
- * requires both importer and renderer support.
166
- *
167
- * - "picture" — a single image from `rawParts`. The frame's
168
- * widthEmu / heightEmu give the display size; the picture
169
- * stretches to fill (matches Word's default sizing behaviour).
170
- *
171
- * - "textbox" — rich body content. Renders recursively via
172
- * `renderBlocks` inside the frame, with `overflow: hidden` so
173
- * text that exceeds the frame's height clips (Word behaviour).
174
- * Optional fill / border / padding paint the textbox chrome.
175
- *
176
- * - "shape" — a vector primitive (filled rectangle, ellipse,
177
- * rounded-rect). No text. Used for decorative backgrounds and
178
- * dividers (dotted lines, banner rectangles).
179
- *
180
- * - "group" — wraps other frames at NESTED coordinates. The
181
- * children's offsets are interpreted in the group's local
182
- * coordinate system, scaled to fill `widthEmu × heightEmu`.
183
- * Maps to OOXML `<wpg:wgp>`. This is how a single project
184
- * heading carries its rounded-rect frame + atom icon + arrow
185
- * stripe as ONE selectable unit.
186
- */
187
- export type AnchoredContent = {
188
- kind: "picture";
189
- partPath: string;
190
- altText?: string;
191
- } | {
192
- kind: "textbox";
193
- body: Block[];
194
- fill?: string;
195
- border?: {
196
- color: string;
197
- widthEmu: number;
198
- style: "solid" | "dashed" | "dotted" | "double";
199
- };
200
- padding?: {
201
- topEmu: number;
202
- rightEmu: number;
203
- bottomEmu: number;
204
- leftEmu: number;
205
- };
206
- } | {
207
- kind: "shape";
208
- geometry: "rect" | "ellipse" | "roundedRect" | "line" | "custom";
209
- fill?: string;
210
- border?: {
211
- color: string;
212
- widthEmu: number;
213
- style: "solid" | "dashed" | "dotted" | "double";
214
- };
215
- /** Present when `geometry === "custom"`: a DrawingML `<a:custGeom>`
216
- * outline as an SVG path in its own `widthEmu × heightEmu` box,
217
- * rendered as a scaled `<svg><path>`. Absent for preset geometry. */
218
- path?: {
219
- widthEmu: number;
220
- heightEmu: number;
221
- d: string;
222
- };
223
- } | {
224
- kind: "group";
225
- children: AnchoredFrame[];
226
- /** Local coordinate system extent (`<a:chExt>`). A child at offset
227
- * `P` maps into the group's rendered box as
228
- * `(P − childCoordOffset) × (size / childCoordSystem)` — the
229
- * extent gives the scale. */
230
- childCoordSystemCx: number;
231
- childCoordSystemCy: number;
232
- /** Local coordinate system ORIGIN (`<a:chOff>`). Child offsets are
233
- * measured from this point, not from 0 — so it must be subtracted
234
- * before scaling, or the children shift by `chOff × scale`.
235
- * Absent ⇒ origin is `(0, 0)` (the common case). */
236
- childCoordOffsetX?: number;
237
- childCoordOffsetY?: number;
238
- };
239
- export interface Comment {
240
- id: number;
241
- author?: string;
242
- /** Author initials as recorded in the docx — Word uses them in the
243
- * comment sidebar header. */
244
- initials?: string;
245
- /** ISO-8601 date string. */
246
- date?: string;
247
- /** Comment body — typically one or more paragraphs. */
248
- body: Block[];
249
- /**
250
- * Resolved / "Done" flag from `word/commentsExtended.xml`
251
- * (`<w15:commentEx w15:done="1">`). Absent or false → open.
252
- */
253
- done?: boolean;
254
- /**
255
- * Id of the parent comment when this is a reply in a thread.
256
- * Resolved from `<w15:commentEx w15:paraIdParent="…">` by matching
257
- * the parent's body-paragraph paraId back to its comment id.
258
- * Absent → top-level comment.
259
- */
260
- replyToId?: number;
261
- }
262
- export type { FontDeclaration, FontEmbedRef } from '../fonts/types';
263
- type FontDeclaration = _FontDeclaration;
264
- export type Block = Paragraph | Table | SectionBreak | InlineFrame;
265
- export interface Paragraph {
266
- kind: "paragraph";
267
- properties: ParagraphProperties;
268
- /** Inline runs in document order. May be empty (a blank paragraph). */
269
- runs: InlineRun[];
270
- }
271
- /** Explicit page-break or section-break marker emitted between paragraphs. */
272
- export interface SectionBreak {
273
- kind: "section_break";
274
- /** Which section in `SobreeDocument.sections` continues after this point. */
275
- toSectionIndex: number;
276
- }
277
- /**
278
- * A rectangular drawing region that flows inline with body blocks
279
- * (NOT absolutely positioned — that's `AnchoredFrame`). Owns its own
280
- * picture decoration(s), its own textbox body (recursive `Block[]`),
281
- * and its own break / keep-with-next directives. Maps 1:1 to
282
- * `<w:drawing><wp:inline>` with a `<wpg:wgp>` payload that wraps a
283
- * `<wps:txbx>` textbox shape + decorative `<pic:pic>` / `<wps:wsp>`
284
- * siblings.
285
- *
286
- * Replaces the legacy lifter's "split into N body paragraphs with
287
- * `liftedFromTextBox` + `framePictures` + `textboxShape` glued on"
288
- * approach. One frame = one block. The page-break directive that
289
- * belonged to the containing paragraph in the source OOXML moves
290
- * here (`pageBreakBefore`), where the paginator's top-level-child
291
- * inspection actually finds it.
292
- *
293
- * See `packages/core/docs/INLINE_FRAME_DESIGN.md` for the full
294
- * design and migration plan.
295
- *
296
- * **Status**: type declared (Phase 1.0). Importer does not yet emit
297
- * this; renderer treats it as a no-op. Wiring lands in Phase 1.1-1.2.
298
- */
299
- /** One textbox shape inside an inline-frame group: its intra-group
300
- * position + size and recursive body, plus optional chrome (fill /
301
- * border / text insets) and vertical text anchor. */
302
- export interface InlineFrameTextbox {
303
- offsetEmu: {
304
- xEmu: number;
305
- yEmu: number;
306
- };
307
- sizeEmu: {
308
- wEmu: number;
309
- hEmu: number;
310
- };
311
- body: Block[];
312
- fill?: string;
313
- border?: FrameBorder;
314
- /** `<wps:bodyPr>` text insets (lIns/tIns/rIns/bIns) → CSS padding. */
315
- padding?: {
316
- topEmu: number;
317
- rightEmu: number;
318
- bottomEmu: number;
319
- leftEmu: number;
320
- };
321
- /** Vertical text anchor from `<wps:bodyPr anchor>`; defaults to "top". */
322
- vAlign?: "top" | "center" | "bottom";
323
- }
324
- export interface InlineFrame {
325
- kind: "inline_frame";
326
- /** From the containing `<w:p>`'s `<w:pPr>`. The paginator emits a
327
- * `Penalty(-Infinity)` before the frame when set. */
328
- pageBreakBefore?: boolean;
329
- /** From the containing `<w:p>`'s `<w:pPr>`. Keep with the next
330
- * block to avoid widowing a section heading from its body. */
331
- keepNext?: boolean;
332
- /** The containing `<w:p>`'s resolved paragraph properties. An inline
333
- * drawing lives inside a host paragraph; that paragraph carries
334
- * spacing (before/after), alignment, etc. from its style cascade
335
- * (commonly `Normal`'s `<w:spacing w:after>`). The renderer applies
336
- * these to the frame wrapper so the band reserves the SAME vertical
337
- * box (drawing height + paragraph spacing) Word does — without it
338
- * the band is short by the spacing-after, which compounds down the
339
- * page and shifts pagination. Absent → wrapper uses bare defaults. */
340
- hostProps?: ParagraphProperties;
341
- /** The drawing group's intrinsic coordinate-system extent. Every
342
- * child's `offsetEmu` / `sizeEmu` below is expressed in this
343
- * space; the renderer scales them by `sizeEmu / groupExtentEmu`
344
- * when painting at the final rendered size. */
345
- groupExtentEmu: {
346
- wEmu: number;
347
- hEmu: number;
348
- };
349
- /** The frame's rendered display dimensions. Usually equal to
350
- * `groupExtentEmu` for inline drawings (no scaling) but kept
351
- * separate so a future "render at half-size" / scaling case
352
- * doesn't require touching every child. */
353
- sizeEmu: {
354
- wEmu: number;
355
- hEmu: number;
356
- };
357
- /** The group's textbox SHAPES, in document (child) order. Most groups
358
- * have one (a section "pill" heading: a centred line over a background
359
- * picture), but a "Project: X" entry has two — a title textbox and a
360
- * details textbox — and the renderer must show BOTH. Empty when the
361
- * group carries only pictures / shapes (no textbox content). */
362
- textboxes: InlineFrameTextbox[];
363
- /** Decorative pictures inside the group. Each carries its own
364
- * intra-group position. The renderer paints them as
365
- * absolute-positioned `<img>` children of the frame wrapper,
366
- * scaled by the same `sizeEmu / groupExtentEmu` ratio. */
367
- pictures: ReadonlyArray<{
368
- partPath: string;
369
- offsetEmu: {
370
- xEmu: number;
371
- yEmu: number;
372
- };
373
- sizeEmu: {
374
- wEmu: number;
375
- hEmu: number;
376
- };
377
- altText?: string;
378
- }>;
379
- /** Non-picture decorative shapes (rect / ellipse / line) inside
380
- * the group. Same positioning model as `pictures`. */
381
- shapes: ReadonlyArray<{
382
- geometry: "rect" | "ellipse" | "roundedRect" | "line";
383
- offsetEmu: {
384
- xEmu: number;
385
- yEmu: number;
386
- };
387
- sizeEmu: {
388
- wEmu: number;
389
- hEmu: number;
390
- };
391
- fill?: string;
392
- border?: FrameBorder;
393
- }>;
394
- }
395
- /** Shared border descriptor for inline / anchored frame chrome.
396
- * Distinct from `BorderSpec` (used for paragraph / table borders
397
- * whose OOXML `w:val` covers a different vocabulary). */
398
- export interface FrameBorder {
399
- color: string;
400
- widthEmu: number;
401
- style: "solid" | "dashed" | "dotted" | "double";
402
- }
403
- export type InlineRun = TextRun | BreakRun | TabRun | FieldRun | DrawingRun | HyperlinkRun | FootnoteRefRun | CommentRefRun;
404
- export interface TextRun {
405
- kind: "text";
406
- text: string;
407
- properties: RunProperties;
408
- }
409
- export interface BreakRun {
410
- kind: "break";
411
- /**
412
- * `line` — soft line break inside a paragraph (Shift-Enter).
413
- * `page` — explicit page break.
414
- * `column` — column break in a multi-column section.
415
- */
416
- type: "line" | "page" | "column";
417
- properties?: RunProperties;
418
- }
419
- export interface TabRun {
420
- kind: "tab";
421
- properties?: RunProperties;
422
- }
423
- export interface FieldRun {
424
- kind: "field";
425
- /** Field instruction text — `PAGE`, `NUMPAGES`, `DATE`, `AUTHOR`, … */
426
- instruction: string;
427
- /**
428
- * Cached value displayed if a viewer doesn't recalculate. Used as the
429
- * preview text by Sobree's renderer.
430
- */
431
- cached?: string;
432
- properties?: RunProperties;
433
- }
434
- /**
435
- * Inline reference to a comment (`<w:commentReference w:id="N"/>`).
436
- * Word renders a small balloon icon at the position; we mirror with
437
- * a clickable inline span linking to the comment card in the aside.
438
- */
439
- export interface CommentRefRun {
440
- kind: "commentRef";
441
- /** ID matching a key in `SobreeDocument.comments`. */
442
- id: number;
443
- properties?: RunProperties;
444
- }
445
- /**
446
- * Inline reference to a footnote (`<w:footnoteReference w:id="N"/>`).
447
- * Renders as a clickable superscript number; the referenced footnote's
448
- * body lives in `SobreeDocument.footnotes[id]` and is rendered at the
449
- * end of the document. (True per-page pinning is a paginator feature
450
- * deferred for now.)
451
- */
452
- export interface FootnoteRefRun {
453
- kind: "footnoteRef";
454
- /** ID matching a key in `SobreeDocument.footnotes`. */
455
- id: number;
456
- properties?: RunProperties;
457
- }
458
- export interface DrawingRun {
459
- kind: "drawing";
460
- /** Path of the embedded media part in `rawParts` (e.g. `word/media/image1.png`). */
461
- partPath: string;
462
- /** Rendered size. */
463
- widthEmu: number;
464
- heightEmu: number;
465
- /** Accessibility text. */
466
- altText?: string;
467
- /**
468
- * Where the image lays out:
469
- * - "inline" — flows in the paragraph like a tall character.
470
- * - "anchor" — positioned absolutely (`<wp:anchor>`); `anchor`
471
- * carries the offset + frame-of-reference.
472
- * - "floatLeft" / "floatRight" — a `<wp:anchor>` image with a
473
- * displacing wrap (square/tight/through), converted to a
474
- * CSS float at the head of its anchor paragraph so body
475
- * text flows around it. `floatMarginsEmu` carries the
476
- * `distT/B/L/R` clearance.
477
- */
478
- placement: "inline" | "anchor" | "floatLeft" | "floatRight";
479
- /** Set when `placement === "anchor"`. */
480
- anchor?: DrawingAnchor;
481
- /** Set for `floatLeft` / `floatRight` — the text-clearance margins
482
- * (from the frame's `distT/B/L/R`), applied as CSS margins. */
483
- floatMarginsEmu?: {
484
- topEmu: number;
485
- rightEmu: number;
486
- bottomEmu: number;
487
- leftEmu: number;
488
- };
489
- /**
490
- * Vertical alignment for an `inline` image relative to the text on
491
- * its line. Defaults to the browser baseline (image bottom on the
492
- * text baseline). `"middle"` centres the image on the text — used
493
- * for a heading decoration (the flowed ► project arrow) that is
494
- * taller than its label, so the label centres beside it as Word
495
- * renders it. Omitted for ordinary inline images.
496
- */
497
- verticalAlign?: "baseline" | "middle";
498
- }
499
- export interface DrawingAnchor {
500
- /** Horizontal offset in EMU (English Metric Units; 914400 EMU = 1 inch). */
501
- offsetXEmu: number;
502
- /** Vertical offset in EMU. */
503
- offsetYEmu: number;
504
- /** What `offsetXEmu` is measured from. */
505
- relativeFromH: "page" | "margin" | "column" | "character";
506
- /** What `offsetYEmu` is measured from. */
507
- relativeFromV: "page" | "margin" | "paragraph" | "line";
508
- /** True when the image renders *behind* text (z-index negative). */
509
- behindDoc?: boolean;
510
- }
511
- export interface HyperlinkRun {
512
- kind: "hyperlink";
513
- /** Either an external URL or an internal anchor id. */
514
- href: string;
515
- /** Display text — itself a list of runs to allow nested formatting. */
516
- children: InlineRun[];
517
- properties?: RunProperties;
518
- }
519
- export interface RunProperties {
520
- /** Reference to a `NamedStyle.id` of type "character". */
521
- styleId?: string;
522
- bold?: boolean;
523
- italic?: boolean;
524
- /** Underline style — most callers want `"single"`. */
525
- underline?: "single" | "double" | "dotted" | "dashed" | "wave" | "none";
526
- strike?: boolean;
527
- doubleStrike?: boolean;
528
- /** `#rrggbb`. */
529
- color?: string;
530
- /** Word highlight name (`yellow`, `green`, …) or `#rrggbb`. */
531
- highlight?: string;
532
- /** Cell-style shading (`<w:shd w:fill="…">`). */
533
- shading?: Shading;
534
- /** Font family name (Calibri, Georgia, …). */
535
- fontFamily?: string;
536
- /** Size in points (Word stores half-points; we expose pt for ergonomics). */
537
- fontSizePt?: number;
538
- verticalAlign?: "subscript" | "superscript";
539
- /** Whether the text is uppercase / small caps. */
540
- caps?: boolean;
541
- smallCaps?: boolean;
542
- /** Hidden text (`<w:vanish/>`). */
543
- hidden?: boolean;
544
- /**
545
- * Tracked-change marker — set when the run is inside a `<w:ins>`
546
- * (insertion) or `<w:del>` (deletion) wrapper. The renderer
547
- * applies a visual revision style; the underlying text is preserved
548
- * either way so the document round-trips faithfully.
549
- */
550
- revision?: RevisionMark;
551
- /**
552
- * Comment ids whose `<w:commentRangeStart>` … `<w:commentRangeEnd>`
553
- * span includes this run. The renderer highlights ranges with any
554
- * active comment. Multiple ids let nested/overlapping comments
555
- * coexist on the same run.
556
- */
557
- commentIds?: readonly number[];
558
- /**
559
- * Tracked **format change** — a snapshot of this run's properties
560
- * *before* the most recent tracked formatting edit. Word stores this
561
- * as `<w:rPrChange>` (ECMA-376 §17.13.5.32).
562
- *
563
- * Accepting the format revision drops `revisionFormat` (the current
564
- * `properties` stays). Rejecting it restores `properties` *to* the
565
- * `before` snapshot. Repeated tracked format edits don't overwrite
566
- * the snapshot — the *original* properties stay captured, so a
567
- * reject always returns the run to its pre-tracking state.
568
- *
569
- * `before` is itself a `RunProperties` but `revisionFormat` doesn't
570
- * recurse (the snapshot is "what the run looked like before we
571
- * started tracking format changes").
572
- */
573
- revisionFormat?: {
574
- before: RunProperties;
575
- author?: string;
576
- date?: string;
577
- };
578
- }
579
- export interface RevisionMark {
580
- /** `ins` = insertion, `del` = deletion. */
581
- type: "ins" | "del";
582
- /** Author name as recorded in the docx (`<w:ins w:author="...">`). */
583
- author?: string;
584
- /** ISO-8601 timestamp string from the docx. */
585
- date?: string;
586
- }
587
- export interface ParagraphProperties {
588
- /** Reference to a `NamedStyle.id` of type "paragraph". */
589
- styleId?: string;
590
- alignment?: ParagraphAlignment;
591
- /** Numbered/bulleted list reference. */
592
- numbering?: {
593
- numId: number;
594
- level: number;
595
- };
596
- spacing?: ParagraphSpacing;
597
- indent?: ParagraphIndent;
598
- borders?: ParagraphBorders;
599
- shading?: Shading;
600
- /** Keep this paragraph on the same page as the next one. */
601
- keepNext?: boolean;
602
- /** Don't allow this paragraph to break across pages. */
603
- keepLines?: boolean;
604
- /** Insert a page break before this paragraph. */
605
- pageBreakBefore?: boolean;
606
- /** Custom tab stops from `<w:pPr><w:tabs>`, positions in twips. The
607
- * renderer uses the smallest stop's position to compute a CSS
608
- * `tab-size` on the paragraph so `\t` characters in the text honour
609
- * the document's tab geometry instead of the browser's 8-char
610
- * default. Mixed alignments (right / decimal / leader) collapse to
611
- * "left" for now — covering the common case (label-value columns
612
- * in headers + form fields). */
613
- tabStops?: readonly {
614
- positionTwips: number;
615
- alignment: string;
616
- leader?: string;
617
- }[];
618
- /** Default run properties applied to runs that don't override. */
619
- runDefaults?: RunProperties;
620
- /**
621
- * Tracked-change marker on the paragraph mark itself. Semantically:
622
- * the *paragraph break that precedes this paragraph* is a tracked
623
- * change. Word stores this as `<w:rPr><w:ins/></w:rPr>` inside
624
- * `<w:pPr>` — see ECMA-376 §17.13.5.7.
625
- *
626
- * `ins` — pressing Enter created this paragraph (split the prior
627
- * paragraph). Accepting keeps the split; rejecting merges
628
- * the paragraph back into the previous one.
629
- * `del` — the user has marked this paragraph break for deletion
630
- * (e.g. Backspace at the start of this paragraph in
631
- * tracked mode). Accepting merges into the previous;
632
- * rejecting keeps the split.
633
- *
634
- * Accept/reject of this paragraph-level marker is tracked under
635
- * follow-up task 26 (block-level revisions); v1 only adds the
636
- * authoring path (via `Editor.splitBlock` in track-changes mode).
637
- */
638
- revision?: RevisionMark;
639
- }
640
- export type ParagraphAlignment = "left" | "center" | "right" | "both" | "distribute";
641
- export interface ParagraphSpacing {
642
- /** Twips before the paragraph. */
643
- beforeTwips?: number;
644
- /** Twips after the paragraph. */
645
- afterTwips?: number;
646
- /** Twips between lines (when `lineRule === "exact" | "atLeast"`) or
647
- * 240ths of a multiplier (when `lineRule === "auto"`). */
648
- line?: number;
649
- lineRule?: "auto" | "exact" | "atLeast";
650
- }
651
- export interface ParagraphIndent {
652
- leftTwips?: number;
653
- rightTwips?: number;
654
- /** Indent of the first line of the paragraph (positive = indent in). */
655
- firstLineTwips?: number;
656
- /** Hanging indent (offsets first line OUT of the rest of the para). */
657
- hangingTwips?: number;
658
- }
659
- export interface ParagraphBorders {
660
- top?: BorderSpec;
661
- right?: BorderSpec;
662
- bottom?: BorderSpec;
663
- left?: BorderSpec;
664
- between?: BorderSpec;
665
- }
666
- export interface Table {
667
- kind: "table";
668
- /** Column widths in twips. Length = number of columns. */
669
- grid: number[];
670
- rows: TableRow[];
671
- properties: TableProperties;
672
- }
673
- export interface TableProperties {
674
- /** Total table width in twips, or "auto" for content-driven. */
675
- widthTwips?: number;
676
- alignment?: ParagraphAlignment;
677
- borders?: TableBorders;
678
- /** Style reference (e.g. "TableGrid"). */
679
- styleId?: string;
680
- /** `<w:tblLook>` — which of the table style's conditional formats are
681
- * active (first row / column, last row / column, row / column
682
- * banding). Gates {@link TableStyleDefinition} resolution. */
683
- look?: TableLook;
684
- /** `<w:tblCellMar>` — default inner padding for every cell (the table's
685
- * own value wins over the style's). Word's stock default is ~108 twips
686
- * left / right and 0 top / bottom when omitted. */
687
- cellMargins?: TableCellMargins;
688
- }
689
- export interface TableRow {
690
- cells: TableCell[];
691
- /** True if this row is a header row repeated on each page. */
692
- isHeader?: boolean;
693
- }
694
- export interface TableCell {
695
- /** Number of grid columns this cell spans horizontally. */
696
- gridSpan?: number;
697
- /** Vertical merge state — `restart` begins a merge, `continue` continues. */
698
- vMerge?: "restart" | "continue";
699
- verticalAlign?: "top" | "center" | "bottom";
700
- shading?: Shading;
701
- borders?: TableCellBorders;
702
- /** Cell content — paragraphs and (rare) nested tables. */
703
- content: Block[];
704
- }
705
- export interface SectionProperties {
706
- pageSize: PageSize;
707
- pageMargins: PageMargins;
708
- /** Header references. Most docs have one or two. */
709
- headerRefs: HeaderFooterRef[];
710
- footerRefs: HeaderFooterRef[];
711
- /** Show the first-page header/footer slot if true. */
712
- titlePage?: boolean;
713
- /** Continuous, nextPage, etc. */
714
- type?: "continuous" | "nextPage" | "evenPage" | "oddPage";
715
- /**
716
- * Vertical alignment of the body content on each page in this section.
717
- * OOXML `<w:vAlign>` (ECMA-376 §17.6.21). Only visible on partial pages
718
- * — full pages have no slack to redistribute. Default is `"top"` (the
719
- * field is omitted in that case).
720
- *
721
- * - `top` — content anchored to top margin (default).
722
- * - `center` — content centred between top and bottom margin.
723
- * - `bottom` — content anchored to bottom margin.
724
- * - `both` — paragraph spacing stretched to fill the page.
725
- */
726
- vAlign?: "top" | "center" | "bottom" | "both";
727
- /**
728
- * Multi-column layout for the section's content (`<w:cols>`).
729
- * Absent or `count <= 1` → single column (the default; the renderer
730
- * does not wrap in a column container in that case).
731
- */
732
- columns?: SectionColumns;
733
- }
734
- export interface SectionColumns {
735
- /** Number of columns. */
736
- count: number;
737
- /** Default inter-column gap in twips (Word's `<w:cols w:space>`). Used
738
- * for equal columns and as the fallback gap when a per-column space
739
- * is absent. */
740
- spaceTwips?: number;
741
- /** `false` when the section declares explicit per-column widths
742
- * (Word's `<w:cols w:equalWidth="0">`). Absent/`true` → equal columns,
743
- * which the renderer flows with CSS multi-column. */
744
- equalWidth?: boolean;
745
- /** Per-column geometry from `<w:col w:w w:space>`, present only for the
746
- * unequal case. `length === count`. Each entry's `spaceTwips` is the
747
- * gap AFTER that column (the last column's is usually absent). The
748
- * renderer flows blocks across these tracks at their true widths. */
749
- columns?: SectionColumn[];
750
- }
751
- export interface SectionColumn {
752
- /** Column width in twips (`<w:col w:w>`). */
753
- widthTwips: number;
754
- /** Trailing gap after this column in twips (`<w:col w:space>`). */
755
- spaceTwips?: number;
756
- }
757
- export interface PageSize {
758
- wTwips: number;
759
- hTwips: number;
760
- orientation: "portrait" | "landscape";
761
- }
762
- export interface PageMargins {
763
- topTwips: number;
764
- rightTwips: number;
765
- bottomTwips: number;
766
- leftTwips: number;
767
- headerTwips: number;
768
- footerTwips: number;
769
- gutterTwips: number;
770
- }
771
- export interface HeaderFooterRef {
772
- type: "default" | "first" | "even";
773
- /** Internal id pointing into `SobreeDocument.rawParts` /
774
- * `relationships`. We store the header/footer body itself as a
775
- * `Block[]` keyed in a side table at the SobreeDocument level. */
776
- partId: string;
777
- }
778
- export interface NamedStyle {
779
- id: string;
780
- type: "paragraph" | "character" | "table" | "numbering";
781
- /** Display name shown in Word's style picker. */
782
- displayName: string;
783
- /** Inherits from another style id. */
784
- basedOn?: string;
785
- /** The style applied to the next paragraph after this one (for headings). */
786
- nextStyleId?: string;
787
- /** Default run properties. */
788
- runDefaults?: RunProperties;
789
- /** Default paragraph properties. */
790
- paragraphDefaults?: ParagraphProperties;
791
- /** Numbering linked via the style's `<w:numPr>` — the source of heading
792
- * outline numbers ("1", "1.1", "1.2"). `numId` references a
793
- * `NumberingDefinition`; `level` is the outline level this style sits at.
794
- * Distinct from `ParagraphProperties.numbering` (a paragraph's OWN list
795
- * membership); a style's numbering applies to every paragraph using it. */
796
- numbering?: {
797
- numId: number;
798
- level: number;
799
- };
800
- /** Default table properties (only for table styles). */
801
- tableDefaults?: TableProperties;
802
- /** Table-style borders + conditional formatting (only for table
803
- * styles). Resolved per cell at render time. */
804
- tableStyle?: TableStyleDefinition;
805
- }
806
- export interface NumberingDefinition {
807
- /** `numId` referenced from `ParagraphProperties.numbering`. */
808
- numId: number;
809
- /** The abstract format definition. */
810
- abstractFormat: AbstractNumberingFormat;
811
- }
812
- export interface AbstractNumberingFormat {
813
- /** One per indent level (0..8 typically). */
814
- levels: NumberingLevel[];
815
- }
816
- export interface NumberingLevel {
817
- level: number;
818
- /** Format: `bullet`, `decimal`, `lowerRoman`, `upperLetter`, … */
819
- format: string;
820
- /** Text template, e.g. `%1.` or a literal bullet character. */
821
- text: string;
822
- /** Restart numbering after this level. */
823
- restart?: number;
824
- /** Indentation of the numbered text. */
825
- paragraphIndent?: ParagraphIndent;
826
- /** Run properties for the bullet/number marker itself. */
827
- runDefaults?: RunProperties;
828
- }
829
- /**
830
- * Mirror of the `_rels/document.xml.rels` table — Sobree tracks
831
- * relationships as data so headers, footers, images, hyperlinks all share
832
- * one allocation strategy at export time.
833
- */
834
- export interface RelationshipManifest {
835
- /** Map of `rId…` → relationship descriptor. */
836
- byId: Record<string, Relationship>;
837
- }
838
- export interface Relationship {
839
- id: string;
840
- type: RelationshipType;
841
- target: string;
842
- /** External (true) means `target` is a URL; otherwise a part path. */
843
- external?: boolean;
844
- }
845
- export type RelationshipType = "header" | "footer" | "image" | "hyperlink" | "styles" | "numbering" | "settings" | "fontTable" | "theme" | "comments" | "footnotes" | "endnotes";
10
+ export type * from './types/index';