reamkit 1.16.0 → 1.17.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 (65) hide show
  1. package/dist/esm/core/bidi/segments.js +1 -2
  2. package/dist/esm/core/converter/project.js +5 -1
  3. package/dist/esm/core/document-model/index.d.ts +1 -1
  4. package/dist/esm/core/document-model/types.d.ts +473 -7
  5. package/dist/esm/core/drawingml/chart-geometry.d.ts +8 -12
  6. package/dist/esm/core/drawingml/chart-geometry.js +58 -9
  7. package/dist/esm/core/drawingml/chart-parser.js +44 -5
  8. package/dist/esm/core/drawingml/colors.d.ts +1 -1
  9. package/dist/esm/core/drawingml/colors.js +27 -1
  10. package/dist/esm/core/drawingml/preset-geometry.js +233 -0
  11. package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
  12. package/dist/esm/core/drawingml/shape-render.js +116 -3
  13. package/dist/esm/core/drawingml/theme-parser.d.ts +10 -0
  14. package/dist/esm/core/drawingml/theme-parser.js +19 -1
  15. package/dist/esm/core/font/measure.d.ts +5 -0
  16. package/dist/esm/core/font/measure.js +21 -1
  17. package/dist/esm/core/images.d.ts +2 -2
  18. package/dist/esm/core/images.js +181 -0
  19. package/dist/esm/core/ir/flow.d.ts +23 -1
  20. package/dist/esm/core/numbering/apply.d.ts +5 -3
  21. package/dist/esm/core/numbering/apply.js +42 -11
  22. package/dist/esm/core/numbering/index.js +2 -0
  23. package/dist/esm/core/numbering/state.d.ts +13 -1
  24. package/dist/esm/core/numbering/state.js +256 -15
  25. package/dist/esm/core/po-helpers.js +16 -1
  26. package/dist/esm/core/style-cascade/resolver.js +66 -11
  27. package/dist/esm/core/style-cascade/table.js +35 -11
  28. package/dist/esm/core/style-cascade/types.d.ts +42 -1
  29. package/dist/esm/core/style-cascade/types.js +4 -0
  30. package/dist/esm/core/vector.d.ts +17 -0
  31. package/dist/esm/excel/print-model.js +1 -1
  32. package/dist/esm/excel/sheet-to-flow.js +10 -8
  33. package/dist/esm/excel/worksheet-parser.js +1 -1
  34. package/dist/esm/html/html-writer.js +18 -4
  35. package/dist/esm/layout/page-doc.d.ts +62 -2
  36. package/dist/esm/layout/styled-layout.d.ts +44 -2
  37. package/dist/esm/layout/styled-layout.js +1870 -228
  38. package/dist/esm/pdf/shading.js +76 -6
  39. package/dist/esm/pdf/styled-page-emitter.js +217 -43
  40. package/dist/esm/pdf/vector-graphics.d.ts +28 -1
  41. package/dist/esm/pdf/vector-graphics.js +94 -11
  42. package/dist/esm/pptx/pptx-reader.js +1 -0
  43. package/dist/esm/pptx/slide-parser.d.ts +21 -4
  44. package/dist/esm/pptx/slide-parser.js +86 -23
  45. package/dist/esm/svg/svg-writer.js +1 -1
  46. package/dist/esm/word/document-parser.d.ts +96 -7
  47. package/dist/esm/word/document-parser.js +537 -116
  48. package/dist/esm/word/docx-reader.js +135 -43
  49. package/dist/esm/word/docx-writer.js +6 -1
  50. package/dist/esm/word/drawing-parser.d.ts +53 -5
  51. package/dist/esm/word/drawing-parser.js +1540 -54
  52. package/dist/esm/word/index.d.ts +4 -4
  53. package/dist/esm/word/numbering-parser.d.ts +2 -1
  54. package/dist/esm/word/numbering-parser.js +107 -21
  55. package/dist/esm/word/paragraph-properties.d.ts +11 -1
  56. package/dist/esm/word/paragraph-properties.js +219 -10
  57. package/dist/esm/word/run-properties.js +45 -1
  58. package/dist/esm/word/settings-parser.d.ts +24 -0
  59. package/dist/esm/word/settings-parser.js +31 -5
  60. package/dist/esm/word/shading.d.ts +11 -0
  61. package/dist/esm/word/shading.js +64 -0
  62. package/dist/esm/word/styles-parser.js +8 -2
  63. package/dist/esm/word/table-parser.d.ts +9 -1
  64. package/dist/esm/word/table-parser.js +182 -30
  65. package/package.json +1 -1
@@ -60,6 +60,23 @@ export interface ShapeGradient {
60
60
  readonly kind: 'linear' | 'radial';
61
61
  /** Linear only: gradient direction in degrees clockwise (0 = left→right). */
62
62
  readonly angle?: number;
63
+ /**
64
+ * Radial only: where the first stop sits inside the box, as fractions of it
65
+ * (`{x: 0, y: 0}` is the top-left corner). Absent means the middle, which is
66
+ * where DrawingML's own `a:path` puts it; VML aims it at a corner instead
67
+ * (`@focus` with an `@angle`), and fill.docx's page sweep starts in one.
68
+ */
69
+ readonly center?: {
70
+ readonly x: number;
71
+ readonly y: number;
72
+ };
73
+ /**
74
+ * Radial only: the shape of the sweep's contours. Circles by default, which
75
+ * is what DrawingML's `a:path path="circle"` draws; VML's `gradientRadial`
76
+ * grows RECTANGLES out to the box instead, and so does the page background
77
+ * of fill.docx.
78
+ */
79
+ readonly sweep?: 'circle' | 'rect';
63
80
  readonly stops: ReadonlyArray<GradientStop>;
64
81
  }
65
82
  /**
@@ -1237,7 +1237,7 @@ function mapBorderStyle(style) {
1237
1237
  sizeEighthPt: 18
1238
1238
  };
1239
1239
  case "dashed": return {
1240
- style: "dashed",
1240
+ style: "dashSmallGap",
1241
1241
  sizeEighthPt: 6
1242
1242
  };
1243
1243
  case "dashDot": return {
@@ -6,6 +6,14 @@ import { buildHeaderFooterContent } from "./header-footer.js";
6
6
  //#region src/excel/sheet-to-flow.ts
7
7
  var HEADER_REL = "_xlsxHeaderDefault";
8
8
  var FOOTER_REL = "_xlsxFooterDefault";
9
+ var PAGE_BREAK_PARAGRAPH = {
10
+ properties: {
11
+ pageBreakBefore: true,
12
+ spacingLine: pt(0),
13
+ spacingLineRule: "exact"
14
+ },
15
+ runs: []
16
+ };
9
17
  /**
10
18
  * Project a {@link SheetDoc} into a {@link FlowDoc} (E-SHEET SA2): each grid sheet
11
19
  * becomes flow blocks (a table + chart/picture/shape/slicer frames, then comment
@@ -61,10 +69,7 @@ function projectSheetDoc(sheet, options = {}) {
61
69
  sheetSections.push(sheetSection);
62
70
  if (printed > 0) body.push({
63
71
  kind: "paragraph",
64
- paragraph: {
65
- properties: { pageBreakBefore: true },
66
- runs: []
67
- }
72
+ paragraph: PAGE_BREAK_PARAGRAPH
68
73
  });
69
74
  const drawings = [];
70
75
  for (const ref of ws.charts ?? []) drawings.push({
@@ -96,10 +101,7 @@ function projectSheetDoc(sheet, options = {}) {
96
101
  for (let band = 0; band < drawingBands.length; band++) {
97
102
  if (band > 0) drawings.push({
98
103
  kind: "paragraph",
99
- paragraph: {
100
- properties: { pageBreakBefore: true },
101
- runs: []
102
- }
104
+ paragraph: PAGE_BREAK_PARAGRAPH
103
105
  });
104
106
  for (const shape of drawingBands[band]) drawings.push({
105
107
  kind: "shape",
@@ -1,7 +1,7 @@
1
1
  import { INDEXED_COLORS } from "../core/indexed-colors.js";
2
+ import { resolveInternalEntities } from "../core/opc/xml-entities.js";
2
3
  import { parseCellRef } from "./cell-reference.js";
3
4
  import { parseAreaRef } from "./defined-name-ref.js";
4
- import { resolveInternalEntities } from "../core/opc/xml-entities.js";
5
5
  import { decodeXstring } from "./escaped-text.js";
6
6
  import { parseDxf } from "./styles-parser.js";
7
7
  import { XMLParser } from "fast-xml-parser";
@@ -106,7 +106,11 @@ function collectReferencedAnchors(body) {
106
106
  for (const el of els) if (el.kind === "paragraph") {
107
107
  for (const r of el.paragraph.runs) if (r.anchor !== void 0) out.add(r.anchor);
108
108
  } else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
109
- else if (el.kind === "shape" && el.shape.text) visit(el.shape.text.content);
109
+ else if (el.kind === "shape") visitShape(el.shape);
110
+ };
111
+ const visitShape = (shape) => {
112
+ if (shape.text) visit(shape.text.content);
113
+ for (const child of shape.children ?? []) visitShape(child.shape);
110
114
  };
111
115
  visit(body);
112
116
  return out;
@@ -122,7 +126,11 @@ function collectNoteNumbers(flow) {
122
126
  if (r.commentRef !== void 0 && !comments.has(r.commentRef)) comments.set(r.commentRef, comments.size + 1);
123
127
  }
124
128
  else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
125
- else if (el.kind === "shape" && el.shape.text) visit(el.shape.text.content);
129
+ else if (el.kind === "shape") visitShape(el.shape);
130
+ };
131
+ const visitShape = (shape) => {
132
+ if (shape.text) visit(shape.text.content);
133
+ for (const child of shape.children ?? []) visitShape(child.shape);
126
134
  };
127
135
  visit(flow.body);
128
136
  return {
@@ -274,6 +282,11 @@ function hexToRgbCss(hex) {
274
282
  return `${String(n >> 16 & 255)},${String(n >> 8 & 255)},${String(n & 255)}`;
275
283
  }
276
284
  function emitShapeBlock(out, shape, ctx) {
285
+ const children = shape.children ?? [];
286
+ if (!(children.length > 0 && shape.fill.kind === "none" && shape.line === void 0 && (shape.text?.content.length ?? 0) === 0)) emitOneShape(out, shape, ctx);
287
+ for (const child of children) emitShapeBlock(out, child.shape, ctx);
288
+ }
289
+ function emitOneShape(out, shape, ctx) {
277
290
  const w = shape.width;
278
291
  const h = shape.height;
279
292
  const paths = buildShapePaths(shape.geometry, w, h);
@@ -620,7 +633,7 @@ function pieIconSvg(fill, color, empty) {
620
633
  function pushBorder(css, side, border) {
621
634
  if (!border || border.style === "none") return;
622
635
  const width = border.width ?? .5;
623
- const style = border.style === "double" ? "double" : border.style === "dotted" ? "dotted" : border.style === "dashed" ? "dashed" : "solid";
636
+ const style = border.style === "double" ? "double" : border.style === "dotted" ? "dotted" : border.style === "dashed" || border.style === "dashSmallGap" ? "dashed" : "solid";
624
637
  css.push(`border-${side}:${fmt(width)}pt ${style} #${border.colorHex ?? "000000"}`);
625
638
  }
626
639
  function emitImageBlock(out, image, ctx) {
@@ -638,7 +651,8 @@ function emitImageBlock(out, image, ctx) {
638
651
  var MIME_BY_FORMAT = {
639
652
  jpeg: "image/jpeg",
640
653
  png: "image/png",
641
- jpeg2000: "image/jp2"
654
+ jpeg2000: "image/jp2",
655
+ gif: "image/gif"
642
656
  };
643
657
  function dataUri(resource, store) {
644
658
  if (resource === void 0) return void 0;
@@ -1,8 +1,8 @@
1
- import { BorderStyle } from '../core/document-model/index.js';
1
+ import { BorderStyle, ImageCrop, PictureOutline, ShapeShadow } from '../core/document-model/index.js';
2
2
  import { Pt, ResourceId, ResourceStore } from '../core/ir/index.js';
3
3
  import { FontMeasure, ParsedTtf } from '../core/font/index.js';
4
4
  import { ResolvedParagraphProperties, ResolvedRunProperties } from '../core/style-cascade/index.js';
5
- import { PathSegment, VectorShape } from '../core/vector.js';
5
+ import { PathSegment, VectorPath, VectorShape } from '../core/vector.js';
6
6
  import { PreparedImage } from '../core/images.js';
7
7
  /** A font bound into a {@link LaidOutDocument}: the parsed face plus what layout/emit need from it. */
8
8
  export interface FontResource {
@@ -42,6 +42,17 @@ export interface TextToken {
42
42
  * element separate from the item body.
43
43
  */
44
44
  readonly listMarker?: true;
45
+ /**
46
+ * §17.3.3.1 — the token is the break of a `w:br w:type="column"`: what
47
+ * follows it belongs in the next column.
48
+ */
49
+ readonly columnBreak?: true;
50
+ /**
51
+ * §17.3.1.38 — the token IS a tab: its width is the distance to the stop it
52
+ * advances to, resolved once the line is known, and its text is whatever
53
+ * leader fills that gap.
54
+ */
55
+ readonly tab?: true;
45
56
  /**
46
57
  * The token falls inside a comment range (`commentRangeRefs`): the emitter
47
58
  * fills a soft highlight behind it (E-COMMENTS CM2c).
@@ -69,6 +80,28 @@ export interface ImageToken {
69
80
  readonly imageResourceName: string;
70
81
  readonly widthPt: number;
71
82
  readonly heightPt: number;
83
+ /** §20.1.2.2.24 — the frame the picture is drawn with, when it has one. */
84
+ readonly outline?: PictureOutline;
85
+ /** §20.1.8.40 — the drop shadow under the picture, when it casts one. */
86
+ readonly shadow?: ShapeShadow;
87
+ /** §20.1.8.55 `a:srcRect` — the part of the source the frame shows. */
88
+ readonly crop?: ImageCrop;
89
+ /** §20.1.7.6 — degrees clockwise about the box's centre. */
90
+ readonly rotationDeg?: number;
91
+ /** §20.1.7.6 — the picture drawn mirrored in its box. */
92
+ readonly flipH?: boolean;
93
+ readonly flipV?: boolean;
94
+ /**
95
+ * §20.4.2.6 — where the picture itself sits inside the reserved box when the
96
+ * drawing asked for an effect extent: offsets from the box's left edge and
97
+ * from the baseline, plus the drawn size. Absent ⇒ the picture fills the box.
98
+ */
99
+ readonly drawBox?: {
100
+ readonly dxPt: number;
101
+ readonly dyPt: number;
102
+ readonly widthPt: number;
103
+ readonly heightPt: number;
104
+ };
72
105
  /** Constants kept to satisfy {@link Token} consumers — they never read these for images. */
73
106
  readonly isSpace: false;
74
107
  readonly bidiLevel: number;
@@ -121,6 +154,12 @@ export interface Line {
121
154
  readonly firstLine: boolean;
122
155
  readonly resolved: ResolvedParagraphProperties;
123
156
  isLastInParagraph: boolean;
157
+ /**
158
+ * ECMA-376 §17.15.1.35 — the line ends at a soft line break in a document
159
+ * that asked for `w:doNotExpandShiftReturn`, so justification leaves it at
160
+ * its natural width (as the paragraph's own last line is left).
161
+ */
162
+ readonly noJustify?: boolean;
124
163
  /**
125
164
  * Max ascent/descent contributed by math tokens (0 when none) — they straddle
126
165
  * the baseline, so the line height/descent must grow to fit them.
@@ -154,6 +193,11 @@ export interface ImageResource {
154
193
  * numbers — they are not page-frame coordinates.
155
194
  */
156
195
  export interface PageItemBase {
196
+ /**
197
+ * §20.4.2.3 — the float's `relativeHeight`. Items with one are sorted by it
198
+ * inside their layer before the page is written; the rest keep their order.
199
+ */
200
+ readonly z?: number;
157
201
  /**
158
202
  * Tagged PDF (§14.8): the logical structure node this item's content belongs
159
203
  * to. Set only on body content in tagged mode; undefined text in the line pass
@@ -225,6 +269,22 @@ export interface ImageItem extends PageItemBase {
225
269
  readonly width: Pt;
226
270
  readonly height: Pt;
227
271
  readonly imageResourceName: string;
272
+ /** §20.1.8.55 `a:srcRect` — the part of the source the frame shows. */
273
+ readonly crop?: ImageCrop;
274
+ /** §20.1.7.6 — degrees clockwise about the box's centre. */
275
+ readonly rotationDeg?: number;
276
+ /** §20.1.7.6 — the picture drawn mirrored in its box. */
277
+ readonly flipH?: boolean;
278
+ readonly flipV?: boolean;
279
+ /**
280
+ * §20.1.8.14 — a picture FILL is the shape's outline painted with a picture,
281
+ * so it is clipped to that outline: the paths in the shape's local frame and
282
+ * the matrix that maps them onto the page.
283
+ */
284
+ readonly clip?: {
285
+ readonly paths: ReadonlyArray<VectorPath>;
286
+ readonly transform: readonly [number, number, number, number, number, number];
287
+ };
228
288
  }
229
289
  /**
230
290
  * DrawingML vector geometry. `shape.transform` maps the shape's local y-up frame
@@ -1,12 +1,12 @@
1
- import { BodyElement, Chart, Comment, DocumentInfo, Numbering, Section, SectionProperties, StyleSheet } from '../core/document-model/index.js';
1
+ import { BodyElement, Chart, Comment, DocumentInfo, Numbering, Section, SectionProperties, ShapeFill, StyleSheet } from '../core/document-model/index.js';
2
2
  import { FontRegistry } from '../core/font/index.js';
3
3
  import { FamilyKey } from '../core/fonts/index.js';
4
4
  import { Hyphenator } from '../core/hyphenation/index.js';
5
+ import { Pt, ResourceStore } from '../core/ir/index.js';
5
6
  import { LaidOutDocument, PageItem } from './page-doc.js';
6
7
  import { AttachedFile } from '../pdf/embedded-file.js';
7
8
  import { SignaturePlaceholder } from '../pdf/signature.js';
8
9
  import { PdfEncryptOptions } from '../pdf/encryption.js';
9
- import { ResourceStore } from '../core/ir/index.js';
10
10
  import { StructTreeBuilder } from '../pdf/struct-tree.js';
11
11
  /**
12
12
  * PDF/A conformance string: part 1 (ISO 19005-1, PDF 1.4) / 2 (ISO 19005-2) / 3
@@ -75,6 +75,12 @@ export interface StyledRenderOptions {
75
75
  * `body[sections[N-1].endIndex..sections[N].endIndex)`).
76
76
  */
77
77
  readonly sections?: ReadonlyArray<Section>;
78
+ /**
79
+ * §17.6.5 — the pitch of the document grid the text is laid on. Set by the
80
+ * layout itself, per section (see {@link SectionRenderCtx.options}); callers
81
+ * state it on the section, not here.
82
+ */
83
+ readonly gridLinePitchPt?: Pt;
78
84
  /** Header/footer body content keyed by relationship id. */
79
85
  readonly headersFooters?: ReadonlyMap<string, ReadonlyArray<BodyElement>>;
80
86
  /**
@@ -149,6 +155,24 @@ export interface StyledRenderOptions {
149
155
  * converter fills this from the document's default `w:lang`.
150
156
  */
151
157
  readonly language?: string;
158
+ /**
159
+ * ECMA-376 §17.15.1.35 `w:doNotExpandShiftReturn` — when set, a justified
160
+ * line that ends at a soft line break (`w:br`) is drawn at its natural width
161
+ * instead of being stretched out to the measure.
162
+ */
163
+ readonly doNotExpandShiftReturn?: boolean;
164
+ /**
165
+ * ECMA-376 §17.2.1 `w:background` — the colour every page is painted before
166
+ * anything else is drawn on it. Absent ⇒ the paper's own white.
167
+ */
168
+ readonly pageBackgroundColorHex?: string;
169
+ /** §17.2.1 — the background's gradient or picture, when it has one. */
170
+ readonly pageBackgroundFill?: ShapeFill;
171
+ /**
172
+ * ECMA-376 §17.15.1.38 `w:gutterAtTop` — the binding space belongs to the
173
+ * TOP margin, not the left.
174
+ */
175
+ readonly gutterAtTop?: boolean;
152
176
  /**
153
177
  * §7.6 PDF encryption (AES-256, R6). Only honoured on the ASYNC conversion
154
178
  * path (WebCrypto); mutually exclusive with `pdfA` (ISO 19005 forbids
@@ -175,6 +199,12 @@ export type { DocumentInfo } from '../core/document-model/index.js';
175
199
  export declare const A4_WIDTH = 595;
176
200
  /** A4 page height in points (the page-geometry fallback). */
177
201
  export declare const A4_HEIGHT = 842;
202
+ /**
203
+ * How far a space may be squeezed below its natural width — the shrink the
204
+ * line breaker offers when it weighs a line, and therefore the shrink the
205
+ * emitter owes it back when it draws one.
206
+ */
207
+ export declare const GLUE_SHRINK_RATIO = 0.3;
178
208
  /**
179
209
  * §17.13.6.2 — a bookmark's GoTo destination: the page (0-based) and the y-up
180
210
  * top of the anchoring paragraph's first line.
@@ -274,6 +304,18 @@ export interface SectionRenderCtx {
274
304
  readonly footerSet: HeaderFooterSet;
275
305
  readonly titlePg: boolean;
276
306
  readonly evenAndOddHeaders: boolean;
307
+ /**
308
+ * §17.6.22 — the section begins on the page already in hand, at the point the
309
+ * one before it stopped, rather than on a fresh one.
310
+ */
311
+ readonly continuous: boolean;
312
+ /**
313
+ * The render options this section's content is laid out with: `options` plus
314
+ * whatever the section itself decides for its text — today only §17.6.5's
315
+ * document grid, which is a property of the SECTION and is needed by every
316
+ * paragraph in it. Absent on a bare context built outside a layout run.
317
+ */
318
+ readonly options?: StyledRenderOptions;
277
319
  }
278
320
  interface HfBandEntry {
279
321
  readonly commands: Array<PageItem>;