@jasy/pdf 1.0.0-alpha.1 → 1.0.0-alpha.3

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 (139) hide show
  1. package/README.md +3 -3
  2. package/dist/api/args.d.ts +1 -1
  3. package/dist/api/args.js +2 -5
  4. package/dist/api/color.d.ts +4 -4
  5. package/dist/api/color.js +11 -17
  6. package/dist/api/content.d.ts +8 -8
  7. package/dist/api/content.js +23 -24
  8. package/dist/api/descriptor.d.ts +2 -2
  9. package/dist/api/descriptor.js +75 -31
  10. package/dist/api/index.d.ts +8 -8
  11. package/dist/api/index.js +8 -24
  12. package/dist/api/insets.js +4 -8
  13. package/dist/api/layout.d.ts +27 -12
  14. package/dist/api/layout.js +46 -45
  15. package/dist/api/structure.d.ts +60 -13
  16. package/dist/api/structure.js +132 -88
  17. package/dist/api/table.d.ts +5 -5
  18. package/dist/api/table.js +28 -24
  19. package/dist/api/text.d.ts +27 -2
  20. package/dist/api/text.js +45 -27
  21. package/dist/assets/font-data.d.ts +2 -0
  22. package/dist/assets/font-data.js +6 -0
  23. package/dist/assets/font-data.ts +7 -0
  24. package/dist/common/color.js +1 -5
  25. package/dist/constants/page-sizes.js +3 -6
  26. package/dist/constants/pdf-parts.js +1 -4
  27. package/dist/elements/container-element.d.ts +4 -4
  28. package/dist/elements/container-element.js +9 -13
  29. package/dist/elements/image-element.d.ts +18 -2
  30. package/dist/elements/image-element.js +81 -105
  31. package/dist/elements/index.d.ts +12 -10
  32. package/dist/elements/index.js +12 -28
  33. package/dist/elements/layout/default-text-style-element.d.ts +30 -0
  34. package/dist/elements/layout/default-text-style-element.js +47 -0
  35. package/dist/elements/layout/deferred-element.d.ts +3 -3
  36. package/dist/elements/layout/deferred-element.js +4 -8
  37. package/dist/elements/layout/expanded-element.d.ts +3 -3
  38. package/dist/elements/layout/expanded-element.js +10 -14
  39. package/dist/elements/layout/padding-element.d.ts +3 -3
  40. package/dist/elements/layout/padding-element.js +9 -14
  41. package/dist/elements/layout/positioned-element.d.ts +44 -0
  42. package/dist/elements/layout/positioned-element.js +61 -0
  43. package/dist/elements/layout/repeating-header-element.d.ts +3 -3
  44. package/dist/elements/layout/repeating-header-element.js +8 -12
  45. package/dist/elements/layout/sized-container-element.d.ts +2 -2
  46. package/dist/elements/layout/sized-container-element.js +6 -11
  47. package/dist/elements/line-element.d.ts +3 -3
  48. package/dist/elements/line-element.js +5 -10
  49. package/dist/elements/page-element.d.ts +8 -6
  50. package/dist/elements/page-element.js +31 -23
  51. package/dist/elements/pdf-document-element.d.ts +10 -4
  52. package/dist/elements/pdf-document-element.js +11 -10
  53. package/dist/elements/pdf-element.d.ts +28 -3
  54. package/dist/elements/pdf-element.js +10 -19
  55. package/dist/elements/rectangle-element.d.ts +14 -6
  56. package/dist/elements/rectangle-element.js +44 -21
  57. package/dist/elements/row-element.d.ts +3 -3
  58. package/dist/elements/row-element.js +7 -11
  59. package/dist/elements/text-element.d.ts +37 -11
  60. package/dist/elements/text-element.js +64 -39
  61. package/dist/index.d.ts +3 -3
  62. package/dist/index.js +3 -19
  63. package/dist/ir/display-list.d.ts +22 -3
  64. package/dist/ir/display-list.js +1 -2
  65. package/dist/layout/box-constraints.js +2 -6
  66. package/dist/layout/fragmentation.d.ts +8 -1
  67. package/dist/layout/fragmentation.js +22 -10
  68. package/dist/platform/browser-fs.d.ts +2 -0
  69. package/dist/platform/browser-fs.js +9 -0
  70. package/dist/platform/browser-image.d.ts +5 -0
  71. package/dist/platform/browser-image.js +13 -0
  72. package/dist/platform/node-fs.d.ts +2 -0
  73. package/dist/platform/node-fs.js +10 -0
  74. package/dist/platform/node-image.d.ts +5 -0
  75. package/dist/platform/node-image.js +9 -0
  76. package/dist/renderer/container-renderer.d.ts +3 -3
  77. package/dist/renderer/container-renderer.js +12 -27
  78. package/dist/renderer/default-text-style-renderer.d.ts +6 -0
  79. package/dist/renderer/default-text-style-renderer.js +10 -0
  80. package/dist/renderer/deferred-renderer.d.ts +3 -3
  81. package/dist/renderer/deferred-renderer.js +8 -23
  82. package/dist/renderer/expanded-renderer.d.ts +3 -3
  83. package/dist/renderer/expanded-renderer.js +6 -21
  84. package/dist/renderer/image-renderer.d.ts +3 -3
  85. package/dist/renderer/image-renderer.js +77 -75
  86. package/dist/renderer/index.d.ts +10 -10
  87. package/dist/renderer/index.js +10 -26
  88. package/dist/renderer/line-renderer.d.ts +3 -3
  89. package/dist/renderer/line-renderer.js +13 -28
  90. package/dist/renderer/padding-renderer.d.ts +3 -3
  91. package/dist/renderer/padding-renderer.js +6 -21
  92. package/dist/renderer/page-renderer.d.ts +2 -2
  93. package/dist/renderer/page-renderer.js +61 -77
  94. package/dist/renderer/pdf-backend.d.ts +2 -2
  95. package/dist/renderer/pdf-backend.js +34 -17
  96. package/dist/renderer/pdf-config.js +4 -7
  97. package/dist/renderer/pdf-document-class.d.ts +5 -5
  98. package/dist/renderer/pdf-document-class.js +24 -41
  99. package/dist/renderer/pdf-document-renderer.d.ts +3 -3
  100. package/dist/renderer/pdf-document-renderer.js +71 -85
  101. package/dist/renderer/pdf-renderer.d.ts +2 -2
  102. package/dist/renderer/pdf-renderer.js +83 -90
  103. package/dist/renderer/positioned-renderer.d.ts +6 -0
  104. package/dist/renderer/positioned-renderer.js +10 -0
  105. package/dist/renderer/rectangle-renderer.d.ts +3 -3
  106. package/dist/renderer/rectangle-renderer.js +45 -44
  107. package/dist/renderer/repeating-header-renderer.d.ts +3 -3
  108. package/dist/renderer/repeating-header-renderer.js +11 -26
  109. package/dist/renderer/row-renderer.d.ts +3 -3
  110. package/dist/renderer/row-renderer.js +12 -27
  111. package/dist/renderer/text-renderer.d.ts +6 -5
  112. package/dist/renderer/text-renderer.js +33 -42
  113. package/dist/text/line-breaker.d.ts +8 -5
  114. package/dist/text/line-breaker.js +67 -16
  115. package/dist/text/text-style.d.ts +25 -0
  116. package/dist/text/text-style.js +29 -0
  117. package/dist/utils/afm-parser.js +3 -13
  118. package/dist/utils/bytes.d.ts +24 -0
  119. package/dist/utils/bytes.js +76 -0
  120. package/dist/utils/flex-layout.d.ts +2 -2
  121. package/dist/utils/flex-layout.js +15 -20
  122. package/dist/utils/font-metrics.d.ts +1 -1
  123. package/dist/utils/font-metrics.js +1 -2
  124. package/dist/utils/font-path.js +3 -6
  125. package/dist/utils/image-helper.d.ts +6 -5
  126. package/dist/utils/image-helper.js +101 -111
  127. package/dist/utils/md5.d.ts +4 -0
  128. package/dist/utils/md5.js +80 -0
  129. package/dist/utils/pdf-object-manager.d.ts +10 -6
  130. package/dist/utils/pdf-object-manager.js +89 -94
  131. package/dist/utils/renderer-registry.js +1 -5
  132. package/dist/utils/ttf-parser.d.ts +2 -2
  133. package/dist/utils/ttf-parser.js +32 -36
  134. package/dist/utils/ttf-subsetter.d.ts +1 -1
  135. package/dist/utils/ttf-subsetter.js +40 -42
  136. package/dist/utils/utf8-to-windows1252-encoder.js +1 -4
  137. package/dist/validators/element-validator.d.ts +2 -2
  138. package/dist/validators/element-validator.js +17 -23
  139. package/package.json +14 -2
@@ -1,11 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PaddingElement = void 0;
4
- const element_validator_1 = require("../../validators/element-validator");
5
- const pdf_element_1 = require("../pdf-element");
6
- const box_constraints_1 = require("../../layout/box-constraints");
7
- const fragmentation_1 = require("../../layout/fragmentation");
8
- class PaddingElement extends pdf_element_1.SizedPDFElement {
1
+ import { Validator } from "../../validators/element-validator.js";
2
+ import { SizedPDFElement } from "../pdf-element.js";
3
+ import { BoxConstraints } from "../../layout/box-constraints.js";
4
+ import { isFragmentable } from "../../layout/fragmentation.js";
5
+ export class PaddingElement extends SizedPDFElement {
9
6
  constructor({ margin, child }) {
10
7
  super({ x: 0, y: 0 });
11
8
  this.child = child;
@@ -18,7 +15,7 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
18
15
  * child can't be split, the whole padding moves on as the remainder.
19
16
  */
20
17
  fragment(maxHeight, width, ctx) {
21
- if (!(0, fragmentation_1.isFragmentable)(this.child)) {
18
+ if (!isFragmentable(this.child)) {
22
19
  return { fitted: null, remainder: this };
23
20
  }
24
21
  const [marginTop, marginRight, marginBottom, marginLeft] = this.margin;
@@ -34,7 +31,6 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
34
31
  return new PaddingElement({ margin: this.margin, child });
35
32
  }
36
33
  calculateLayout(constraints, offset, ctx) {
37
- var _a;
38
34
  // Padding takes the width it is offered; its height shrink-wraps the child.
39
35
  if (constraints.hasBoundedWidth)
40
36
  this.width = constraints.maxWidth;
@@ -50,7 +46,7 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
50
46
  const childWidth = constraints.hasBoundedWidth
51
47
  ? Math.max(0, constraints.maxWidth - marginLeft - marginRight)
52
48
  : Infinity;
53
- const childConstraints = box_constraints_1.BoxConstraints.loose(childWidth, Infinity);
49
+ const childConstraints = BoxConstraints.loose(childWidth, Infinity);
54
50
  const childSize = this.child.calculateLayout(childConstraints, childOffset, ctx);
55
51
  this.height = childSize.height + marginTop + marginBottom;
56
52
  // Unbounded width (e.g. a fixed child in a Row): shrink-wrap to the child + insets,
@@ -58,9 +54,9 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
58
54
  if (!constraints.hasBoundedWidth) {
59
55
  this.width = childSize.width + marginLeft + marginRight;
60
56
  }
61
- element_validator_1.Validator.validateSizedElement(this);
57
+ Validator.validateSizedElement(this);
62
58
  // Top-left coordinates; the Y-flip now happens once at the IR -> backend seam.
63
- return { width: (_a = this.width) !== null && _a !== void 0 ? _a : 0, height: this.height };
59
+ return { width: this.width ?? 0, height: this.height };
64
60
  }
65
61
  getProps() {
66
62
  return {
@@ -73,4 +69,3 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
73
69
  };
74
70
  }
75
71
  }
76
- exports.PaddingElement = PaddingElement;
@@ -0,0 +1,44 @@
1
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
2
+ import { LayoutContext, PDFElement, WithChild } from "../pdf-element.js";
3
+ /** A position anchor along one axis: `start` (left/top), `center`, or `end` (right/bottom). */
4
+ export type PositionAnchor = "start" | "center" | "end";
5
+ /**
6
+ * How a `Positioned` child sits in its frame. Two ways, pick per axis:
7
+ * - EDGE pinning: `top`/`right`/`bottom`/`left` (points from that edge; negative pokes outside).
8
+ * Pinning BOTH sides of an axis stretches the child to fill between them.
9
+ * - ANCHOR + nudge: `h`/`v` anchor the child (start/center/end) and `x`/`y` nudge it from there
10
+ * (e.g. `{ h: "center", x: -10 }` = centered minus 10pt). The child shrink-wraps to its content.
11
+ * An edge wins over an anchor on the same axis. With nothing set the child sits at the top-left.
12
+ */
13
+ export interface PositionedInsets {
14
+ top?: number;
15
+ right?: number;
16
+ bottom?: number;
17
+ left?: number;
18
+ h?: PositionAnchor;
19
+ v?: PositionAnchor;
20
+ x?: number;
21
+ y?: number;
22
+ }
23
+ interface PositionedElementParams extends WithChild, PositionedInsets {
24
+ }
25
+ /**
26
+ * An out-of-flow child, placed relative to the nearest enclosing positioning frame (a `relative`
27
+ * Box). It takes ZERO space in the normal flow - `calculateLayout` returns `Size(0,0)` and instead
28
+ * registers a placement closure on the frame. The frame runs that closure once it knows its own
29
+ * size, so `right`/`bottom` resolve against the final box and the child can overflow it (a negative
30
+ * `top`/`left` makes it poke into / out of the corner, e.g. a badge or tab).
31
+ *
32
+ * With no frame in scope the element is a no-op (nothing is drawn) - `Positioned` only makes sense
33
+ * inside a `relative` Box.
34
+ */
35
+ export declare class PositionedElement extends PDFElement {
36
+ private child;
37
+ private insets;
38
+ constructor({ child, top, right, bottom, left, h, v, x, y }: PositionedElementParams);
39
+ calculateLayout(_constraints: BoxConstraints, _offset: Offset, ctx: LayoutContext): Size;
40
+ /** Lays the child out at the resolved position inside (or overflowing) the frame box. */
41
+ private placeInFrame;
42
+ getProps(): WithChild;
43
+ }
44
+ export {};
@@ -0,0 +1,61 @@
1
+ import { BoxConstraints } from "../../layout/box-constraints.js";
2
+ import { PDFElement } from "../pdf-element.js";
3
+ /**
4
+ * An out-of-flow child, placed relative to the nearest enclosing positioning frame (a `relative`
5
+ * Box). It takes ZERO space in the normal flow - `calculateLayout` returns `Size(0,0)` and instead
6
+ * registers a placement closure on the frame. The frame runs that closure once it knows its own
7
+ * size, so `right`/`bottom` resolve against the final box and the child can overflow it (a negative
8
+ * `top`/`left` makes it poke into / out of the corner, e.g. a badge or tab).
9
+ *
10
+ * With no frame in scope the element is a no-op (nothing is drawn) - `Positioned` only makes sense
11
+ * inside a `relative` Box.
12
+ */
13
+ export class PositionedElement extends PDFElement {
14
+ constructor({ child, top, right, bottom, left, h, v, x, y }) {
15
+ super();
16
+ this.child = child;
17
+ this.insets = { top, right, bottom, left, h, v, x, y };
18
+ }
19
+ calculateLayout(_constraints, _offset, ctx) {
20
+ // Defer to the frame: it calls back once it has sized itself. Out of flow either way.
21
+ ctx.frame?.place.push((frame, frameCtx) => this.placeInFrame(frame, frameCtx));
22
+ return { width: 0, height: 0 };
23
+ }
24
+ /** Lays the child out at the resolved position inside (or overflowing) the frame box. */
25
+ placeInFrame(frame, ctx) {
26
+ const { top, right, bottom, left, h, v, x: nudgeX, y: nudgeY } = this.insets;
27
+ // An axis is PINNED (stretched) only when BOTH of its EDGES are given; otherwise the child
28
+ // shrink-wraps its content (unbounded), the CSS rule for an absolutely-positioned element. An
29
+ // anchor never stretches - it positions a content-sized child.
30
+ const width = left !== undefined && right !== undefined
31
+ ? Math.max(0, frame.size.width - left - right)
32
+ : Infinity;
33
+ const height = top !== undefined && bottom !== undefined
34
+ ? Math.max(0, frame.size.height - top - bottom)
35
+ : Infinity;
36
+ const constraints = BoxConstraints.loose(width, height);
37
+ // Measure first (so end/center anchors and right/bottom edges resolve against the child's size).
38
+ const measured = this.child.calculateLayout(constraints, { x: 0, y: 0 }, ctx);
39
+ // Resolve one axis: a near-edge pins to origin, a far-edge pins to the far side; otherwise the
40
+ // anchor (default `start`) positions the child and the nudge shifts it from there.
41
+ const place = (origin, frameExtent, childExtent, nearEdge, farEdge, anchor, nudge) => {
42
+ if (nearEdge !== undefined)
43
+ return origin + nearEdge;
44
+ if (farEdge !== undefined)
45
+ return origin + frameExtent - childExtent - farEdge;
46
+ const base = anchor === "center"
47
+ ? (frameExtent - childExtent) / 2
48
+ : anchor === "end"
49
+ ? frameExtent - childExtent
50
+ : 0; // start (default)
51
+ return origin + base + (nudge ?? 0);
52
+ };
53
+ const x = place(frame.origin.x, frame.size.width, measured.width, left, right, h, nudgeX);
54
+ const y = place(frame.origin.y, frame.size.height, measured.height, top, bottom, v, nudgeY);
55
+ // Place it for real at the resolved position.
56
+ this.child.calculateLayout(constraints, { x, y }, ctx);
57
+ }
58
+ getProps() {
59
+ return { child: this.child };
60
+ }
61
+ }
@@ -1,6 +1,6 @@
1
- import { BoxConstraints, Offset, Size } from "../../layout/box-constraints";
2
- import { Fragmentable, FragmentResult } from "../../layout/fragmentation";
3
- import { LayoutContext, PDFElement } from "../pdf-element";
1
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
2
+ import { Fragmentable, FragmentResult } from "../../layout/fragmentation.js";
3
+ import { LayoutContext, PDFElement } from "../pdf-element.js";
4
4
  /**
5
5
  * Stacks a `header` above a `body` and, when it paginates, **repeats the header on every
6
6
  * fragment**. Used by `Table` so column headings reappear at the top of each page. Layout
@@ -1,16 +1,13 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RepeatingHeaderElement = void 0;
4
- const box_constraints_1 = require("../../layout/box-constraints");
5
- const fragmentation_1 = require("../../layout/fragmentation");
6
- const pdf_element_1 = require("../pdf-element");
1
+ import { BoxConstraints } from "../../layout/box-constraints.js";
2
+ import { isFragmentable } from "../../layout/fragmentation.js";
3
+ import { PDFElement } from "../pdf-element.js";
7
4
  /**
8
5
  * Stacks a `header` above a `body` and, when it paginates, **repeats the header on every
9
6
  * fragment**. Used by `Table` so column headings reappear at the top of each page. Layout
10
7
  * is just header-then-body (like a 2-row Column); the magic is in `fragment`: it splits the
11
8
  * body and re-wraps each piece with the same header, so every physical page gets its own.
12
9
  */
13
- class RepeatingHeaderElement extends pdf_element_1.PDFElement {
10
+ export class RepeatingHeaderElement extends PDFElement {
14
11
  constructor(header, body, gap = 0) {
15
12
  super();
16
13
  this.header = header;
@@ -25,16 +22,16 @@ class RepeatingHeaderElement extends pdf_element_1.PDFElement {
25
22
  this.x = offset.x;
26
23
  this.y = offset.y;
27
24
  const width = constraints.hasBoundedWidth ? constraints.maxWidth : 0;
28
- const h = this.header.calculateLayout(box_constraints_1.BoxConstraints.loose(width, Infinity), { x: this.x, y: this.y }, ctx);
29
- const b = this.body.calculateLayout(box_constraints_1.BoxConstraints.loose(width, Infinity), { x: this.x, y: this.y + h.height + this.gap }, ctx);
25
+ const h = this.header.calculateLayout(BoxConstraints.loose(width, Infinity), { x: this.x, y: this.y }, ctx);
26
+ const b = this.body.calculateLayout(BoxConstraints.loose(width, Infinity), { x: this.x, y: this.y + h.height + this.gap }, ctx);
30
27
  this.width = width;
31
28
  this.height = h.height + this.gap + b.height;
32
29
  return { width: this.width, height: this.height };
33
30
  }
34
31
  fragment(maxHeight, width, ctx) {
35
32
  // Reserve the header's height on every page; the body flows in what's left.
36
- const headerHeight = this.header.calculateLayout(box_constraints_1.BoxConstraints.loose(width, Infinity), { x: 0, y: 0 }, ctx).height;
37
- if (!(0, fragmentation_1.isFragmentable)(this.body))
33
+ const headerHeight = this.header.calculateLayout(BoxConstraints.loose(width, Infinity), { x: 0, y: 0 }, ctx).height;
34
+ if (!isFragmentable(this.body))
38
35
  return { fitted: this, remainder: null };
39
36
  const split = this.body.fragment(Math.max(0, maxHeight - headerHeight - this.gap), width, ctx);
40
37
  // Body fits whole → the whole thing fits on this page.
@@ -57,4 +54,3 @@ class RepeatingHeaderElement extends pdf_element_1.PDFElement {
57
54
  };
58
55
  }
59
56
  }
60
- exports.RepeatingHeaderElement = RepeatingHeaderElement;
@@ -1,5 +1,5 @@
1
- import { SizedElement, WithChildren, SizedPDFElement, LayoutContext } from "../pdf-element";
2
- import { BoxConstraints, Offset, Size } from "../../layout/box-constraints";
1
+ import { SizedElement, WithChildren, SizedPDFElement, LayoutContext } from "../pdf-element.js";
2
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
3
3
  interface ContainerElementParams extends SizedElement, WithChildren {
4
4
  color?: [number, number, number];
5
5
  backgroundColor?: [number, number, number];
@@ -1,15 +1,11 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SizedContainerElement = void 0;
4
- const pdf_element_1 = require("../pdf-element");
5
- const box_constraints_1 = require("../../layout/box-constraints");
6
- class SizedContainerElement extends pdf_element_1.SizedPDFElement {
1
+ import { SizedPDFElement, } from "../pdf-element.js";
2
+ import { BoxConstraints } from "../../layout/box-constraints.js";
3
+ export class SizedContainerElement extends SizedPDFElement {
7
4
  constructor({ width, height, children }) {
8
5
  super({ x: 0, y: 0, width, height });
9
6
  this.children = children;
10
7
  }
11
8
  calculateLayout(constraints, offset, ctx) {
12
- var _a, _b;
13
9
  if (constraints.hasBoundedWidth)
14
10
  this.width = constraints.maxWidth;
15
11
  if (constraints.hasBoundedHeight)
@@ -17,10 +13,10 @@ class SizedContainerElement extends pdf_element_1.SizedPDFElement {
17
13
  // Absolute placement from the parent; assignment (not +=) so re-layout is idempotent.
18
14
  this.x = offset.x;
19
15
  this.y = offset.y;
20
- const width = (_a = this.width) !== null && _a !== void 0 ? _a : 0;
21
- const height = (_b = this.height) !== null && _b !== void 0 ? _b : 0;
16
+ const width = this.width ?? 0;
17
+ const height = this.height ?? 0;
22
18
  if (this.children)
23
- this.children.forEach((child) => child.calculateLayout(box_constraints_1.BoxConstraints.loose(width, height), { x: this.x, y: this.y }, ctx));
19
+ this.children.forEach((child) => child.calculateLayout(BoxConstraints.loose(width, height), { x: this.x, y: this.y }, ctx));
24
20
  // Top-left coordinates; the Y-flip now happens once at the IR -> backend seam.
25
21
  return { width, height };
26
22
  }
@@ -34,4 +30,3 @@ class SizedContainerElement extends pdf_element_1.SizedPDFElement {
34
30
  };
35
31
  }
36
32
  }
37
- exports.SizedContainerElement = SizedContainerElement;
@@ -1,6 +1,6 @@
1
- import { Color } from "../common/color";
2
- import { BoxConstraints, Offset, Size } from "../layout/box-constraints";
3
- import { LayoutContext, SizedElement, SizedPDFElement } from "./pdf-element";
1
+ import { Color } from "../common/color.js";
2
+ import { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
3
+ import { LayoutContext, SizedElement, SizedPDFElement } from "./pdf-element.js";
4
4
  interface LineElementParams extends SizedElement {
5
5
  color?: Color;
6
6
  strokeWidth?: number;
@@ -1,10 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LineElement = void 0;
4
- const color_1 = require("../common/color");
5
- const pdf_element_1 = require("./pdf-element");
6
- class LineElement extends pdf_element_1.SizedPDFElement {
7
- constructor({ color = new color_1.Color(0, 0, 0), strokeWidth, x, y, xEnd, yEnd }) {
1
+ import { Color } from "../common/color.js";
2
+ import { SizedPDFElement } from "./pdf-element.js";
3
+ export class LineElement extends SizedPDFElement {
4
+ constructor({ color = new Color(0, 0, 0), strokeWidth, x, y, xEnd, yEnd }) {
8
5
  super({ x: x, y: y, width: xEnd, height: y + yEnd });
9
6
  this.color = color;
10
7
  this.strokeWidth = strokeWidth ? strokeWidth : 1;
@@ -15,7 +12,6 @@ class LineElement extends pdf_element_1.SizedPDFElement {
15
12
  this.sizeMemory = { x, y, width: xEnd, height: yEnd };
16
13
  }
17
14
  calculateLayout(constraints, offset, _ctx) {
18
- var _a, _b;
19
15
  // Set relative to parent
20
16
  this.x = this.sizeMemory.x + offset.x;
21
17
  this.y = this.sizeMemory.y + offset.y;
@@ -26,7 +22,7 @@ class LineElement extends pdf_element_1.SizedPDFElement {
26
22
  this.xEnd = offset.x + constraints.maxWidth - this.sizeMemory.width;
27
23
  this.yEnd = offset.y + this.sizeMemory.height;
28
24
  // Top-left coordinates; the Y-flip happens once at the IR -> backend seam.
29
- return { width: (_a = this.width) !== null && _a !== void 0 ? _a : 0, height: (_b = this.height) !== null && _b !== void 0 ? _b : 0 };
25
+ return { width: this.width ?? 0, height: this.height ?? 0 };
30
26
  }
31
27
  getProps() {
32
28
  return {
@@ -41,4 +37,3 @@ class LineElement extends pdf_element_1.SizedPDFElement {
41
37
  };
42
38
  }
43
39
  }
44
- exports.LineElement = LineElement;
@@ -1,11 +1,13 @@
1
- import { PageSize } from "../constants/page-sizes";
2
- import { Orientation } from "../renderer/pdf-config";
3
- import type { ColorMode, DefaultFont, Margin } from "../renderer";
4
- import { BoxConstraints, Offset, Size } from "../layout/box-constraints";
5
- import { LayoutContext, PDFElement, WithChildren } from "./pdf-element";
6
- import { TextElement } from "./text-element";
1
+ import { PageSize } from "../constants/page-sizes.js";
2
+ import { Orientation } from "../renderer/pdf-config.js";
3
+ import type { ColorMode, DefaultFont, Margin } from "../renderer/index.js";
4
+ import { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
5
+ import { LayoutContext, PDFElement, WithChildren } from "./pdf-element.js";
6
+ import { TextElement } from "./text-element.js";
7
7
  export interface PDFPageConfig {
8
8
  pageSize?: PageSize;
9
+ /** Explicit [width, height] in points; overrides `pageSize` (e.g. a custom label format). */
10
+ customSize?: [number, number];
9
11
  orientation?: Orientation;
10
12
  margin?: Margin;
11
13
  colorMode?: ColorMode;
@@ -1,22 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PageElement = void 0;
4
- exports.resolvePageContentBox = resolvePageContentBox;
5
- exports.layoutPageBands = layoutPageBands;
6
- const page_sizes_1 = require("../constants/page-sizes");
7
- const pdf_config_1 = require("../renderer/pdf-config");
8
- const box_constraints_1 = require("../layout/box-constraints");
9
- const pdf_element_1 = require("./pdf-element");
1
+ import { pageFormats } from "../constants/page-sizes.js";
2
+ import { Orientation } from "../renderer/pdf-config.js";
3
+ import { BoxConstraints } from "../layout/box-constraints.js";
4
+ import { PDFElement } from "./pdf-element.js";
10
5
  /**
11
6
  * The content box of a page (inside the margins, orientation applied) for a fully
12
7
  * resolved config. Single source of truth, shared by `PageElement` layout and the page
13
8
  * driver so they can never drift.
14
9
  */
15
- function resolvePageContentBox(config) {
10
+ export function resolvePageContentBox(config) {
16
11
  const margin = config.margin;
17
- let width = page_sizes_1.pageFormats[config.pageSize][0] - margin.left - margin.right;
18
- let height = page_sizes_1.pageFormats[config.pageSize][1] - margin.top - margin.bottom;
19
- if (config.orientation === pdf_config_1.Orientation.landscape) {
12
+ const [pageW, pageH] = config.customSize ?? pageFormats[config.pageSize];
13
+ let width = pageW - margin.left - margin.right;
14
+ let height = pageH - margin.top - margin.bottom;
15
+ if (config.orientation === Orientation.landscape) {
20
16
  [width, height] = [height, width];
21
17
  }
22
18
  return { origin: { x: margin.left, y: margin.top }, width, height };
@@ -29,17 +25,17 @@ function resolvePageContentBox(config) {
29
25
  * no header/footer the bands are zero and the body equals the full content box - identical
30
26
  * to a page without them.
31
27
  */
32
- function layoutPageBands(config, header, footer, ctx) {
28
+ export function layoutPageBands(config, header, footer, ctx) {
33
29
  const { origin, width, height } = resolvePageContentBox(config);
34
30
  let headerHeight = 0;
35
31
  if (header) {
36
- headerHeight = header.calculateLayout(box_constraints_1.BoxConstraints.loose(width, Infinity), origin, ctx).height;
32
+ headerHeight = header.calculateLayout(BoxConstraints.loose(width, Infinity), origin, ctx).height;
37
33
  }
38
34
  let footerHeight = 0;
39
35
  if (footer) {
40
36
  // Measure first to learn its height, then place it flush against the bottom edge.
41
- footerHeight = footer.calculateLayout(box_constraints_1.BoxConstraints.loose(width, Infinity), origin, ctx).height;
42
- footer.calculateLayout(box_constraints_1.BoxConstraints.loose(width, Infinity), { x: origin.x, y: origin.y + height - footerHeight }, ctx);
37
+ footerHeight = footer.calculateLayout(BoxConstraints.loose(width, Infinity), origin, ctx).height;
38
+ footer.calculateLayout(BoxConstraints.loose(width, Infinity), { x: origin.x, y: origin.y + height - footerHeight }, ctx);
43
39
  }
44
40
  return {
45
41
  bodyOrigin: { x: origin.x, y: origin.y + headerHeight },
@@ -49,11 +45,11 @@ function layoutPageBands(config, header, footer, ctx) {
49
45
  footerHeight,
50
46
  };
51
47
  }
52
- class PageElement extends pdf_element_1.PDFElement {
48
+ export class PageElement extends PDFElement {
53
49
  constructor({ children, config, header, footer }) {
54
50
  super();
55
51
  this.children = children;
56
- this.config = config !== null && config !== void 0 ? config : {};
52
+ this.config = config ?? {};
57
53
  this.header = header;
58
54
  this.footer = footer;
59
55
  }
@@ -61,16 +57,29 @@ class PageElement extends pdf_element_1.PDFElement {
61
57
  // Merge the document defaults (carried in the context) with this page's overrides,
62
58
  // then hand descendants a context bound to THIS page's geometry. This is what
63
59
  // fixes the old last-page-wins global page-config bug.
64
- this.config = Object.assign(Object.assign({}, ctx.pageConfig), this.config);
60
+ this.config = { ...ctx.pageConfig, ...this.config };
65
61
  const pageCtx = {
66
62
  metrics: ctx.metrics,
67
63
  pageConfig: this.config,
64
+ textStyle: ctx.textStyle,
65
+ onOverflow: ctx.onOverflow,
68
66
  };
69
67
  // Place the header/footer bands; the body gets the region left in between (the whole
70
68
  // content box when there is neither - byte-identical to a plain page).
71
69
  const bands = layoutPageBands(this.config, this.header, this.footer, pageCtx);
72
- const childConstraints = box_constraints_1.BoxConstraints.loose(bands.bodyWidth, bands.bodyHeight);
73
- this.children.forEach((child) => child.calculateLayout(childConstraints, bands.bodyOrigin, pageCtx));
70
+ const childConstraints = BoxConstraints.loose(bands.bodyWidth, bands.bodyHeight);
71
+ // The page body is itself a positioning frame: a `Positioned` with no `relative` ancestor
72
+ // resolves against the content box (a `relative` Box overrides it for its own subtree). Drained
73
+ // after the body is laid out, so a page-level Positioned isn't a silent no-op.
74
+ const frame = {
75
+ origin: bands.bodyOrigin,
76
+ size: { width: bands.bodyWidth, height: bands.bodyHeight },
77
+ place: [],
78
+ };
79
+ const bodyCtx = { ...pageCtx, frame };
80
+ this.children.forEach((child) => child.calculateLayout(childConstraints, bands.bodyOrigin, bodyCtx));
81
+ for (const place of frame.place)
82
+ place(frame, pageCtx);
74
83
  const { width, height } = resolvePageContentBox(this.config);
75
84
  return { width, height };
76
85
  }
@@ -87,4 +96,3 @@ class PageElement extends pdf_element_1.PDFElement {
87
96
  return this;
88
97
  }
89
98
  }
90
- exports.PageElement = PageElement;
@@ -1,12 +1,18 @@
1
- import { PageElement } from "./page-element";
2
- import { BoxConstraints, Offset, Size } from "../layout/box-constraints";
3
- import { LayoutContext, PDFElement, WithChildren } from "./pdf-element";
1
+ import { PageElement } from "./page-element.js";
2
+ import { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
3
+ import { LayoutContext, PDFElement, WithChildren } from "./pdf-element.js";
4
+ import type { ResolvedTextStyle } from "../text/text-style.js";
4
5
  interface PDFDocumentParams extends WithChildren {
5
6
  children: PageElement[];
7
+ /** Document-level text defaults descendants inherit (seeded into the layout-context root). */
8
+ defaultTextStyle?: Partial<ResolvedTextStyle>;
6
9
  }
7
10
  export declare class PDFDocumentElement extends PDFElement {
8
11
  private children;
9
- constructor({ children }: PDFDocumentParams);
12
+ private defaultTextStyle?;
13
+ constructor({ children, defaultTextStyle }: PDFDocumentParams);
14
+ /** The document-level text defaults; the renderer merges them into the cascade root. */
15
+ getDefaultTextStyle(): Partial<ResolvedTextStyle> | undefined;
10
16
  calculateLayout(_constraints: BoxConstraints, _offset: Offset, ctx: LayoutContext): Size;
11
17
  getProps(): PDFDocumentParams;
12
18
  }
@@ -1,22 +1,23 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PDFDocumentElement = void 0;
4
- const box_constraints_1 = require("../layout/box-constraints");
5
- const pdf_element_1 = require("./pdf-element");
6
- class PDFDocumentElement extends pdf_element_1.PDFElement {
7
- constructor({ children }) {
1
+ import { BoxConstraints } from "../layout/box-constraints.js";
2
+ import { PDFElement } from "./pdf-element.js";
3
+ export class PDFDocumentElement extends PDFElement {
4
+ constructor({ children, defaultTextStyle }) {
8
5
  super();
9
6
  this.children = children;
7
+ this.defaultTextStyle = defaultTextStyle;
8
+ }
9
+ /** The document-level text defaults; the renderer merges them into the cascade root. */
10
+ getDefaultTextStyle() {
11
+ return this.defaultTextStyle;
10
12
  }
11
13
  calculateLayout(_constraints, _offset, ctx) {
12
14
  // The document is the root: each page derives its own geometry, so it ignores the
13
15
  // incoming constraints/offset. It has no size of its own.
14
16
  const origin = { x: 0, y: 0 };
15
- this.children.forEach((child) => child.calculateLayout(new box_constraints_1.BoxConstraints(), origin, ctx));
17
+ this.children.forEach((child) => child.calculateLayout(new BoxConstraints(), origin, ctx));
16
18
  return { width: 0, height: 0 };
17
19
  }
18
20
  getProps() {
19
- return { children: this.children };
21
+ return { children: this.children, defaultTextStyle: this.defaultTextStyle };
20
22
  }
21
23
  }
22
- exports.PDFDocumentElement = PDFDocumentElement;
@@ -1,15 +1,40 @@
1
- import type { FontMetrics } from "../utils/font-metrics";
2
- import type { PDFPageConfig } from "./page-element";
3
- import type { BoxConstraints, Offset, Size } from "../layout/box-constraints";
1
+ import type { FontMetrics } from "../utils/font-metrics.js";
2
+ import type { PDFPageConfig } from "./page-element.js";
3
+ import type { ResolvedTextStyle } from "../text/text-style.js";
4
+ import type { OverflowPolicy } from "../layout/fragmentation.js";
5
+ import type { BoxConstraints, Offset, Size } from "../layout/box-constraints.js";
4
6
  /**
5
7
  * Everything the layout pass needs, threaded explicitly (no global singleton):
6
8
  * font metrics for measuring, and the geometry of the page currently being laid out.
7
9
  * `PageElement` sets `pageConfig` for its subtree, so each page flips against its own
8
10
  * height. The PDF byte writer is deliberately absent - layout must not touch it.
9
11
  */
12
+ /**
13
+ * A positioning frame - the CSS "containing block" that `Positioned` children resolve their
14
+ * offsets against. A `relative` Box (later the page) creates one and threads it to its subtree;
15
+ * `Positioned` descendants register a placement closure in `place`, which the frame drains once it
16
+ * has finished sizing itself (so `right`/`bottom` can resolve against the final box).
17
+ */
18
+ export interface PositioningFrame {
19
+ origin: Offset;
20
+ size: Size;
21
+ place: Array<(frame: {
22
+ origin: Offset;
23
+ size: Size;
24
+ }, ctx: LayoutContext) => void>;
25
+ }
10
26
  export interface LayoutContext {
11
27
  metrics: FontMetrics;
12
28
  pageConfig: PDFPageConfig;
29
+ /** The nearest enclosing positioning frame, if any (set by a `relative` Box). */
30
+ frame?: PositioningFrame;
31
+ /** The cascaded text style descendants inherit (CSS/Flutter-style). Seeded at the document root
32
+ * from the built-in defaults + the `Document` defaults, and carried through page contexts; a
33
+ * `Text` resolves its own unset properties against it. Absent falls back to the built-in defaults. */
34
+ textStyle?: ResolvedTextStyle;
35
+ /** What to do when an element overflows a page region and cannot break (set from the render option;
36
+ * absent = clip silently). Evaluated in `packChildren` where the forced placement happens. */
37
+ onOverflow?: OverflowPolicy;
13
38
  }
14
39
  export declare abstract class PDFElement {
15
40
  abstract getProps(): unknown;
@@ -1,13 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VerticalAlignment = exports.HorizontalAlignment = exports.FlexiblePDFElement = exports.SizedPDFElement = exports.PDFElement = void 0;
4
- exports.isSizedElement = isSizedElement;
5
- exports.hasChildrenProp = hasChildrenProp;
6
- exports.hasChildProp = hasChildProp;
7
- class PDFElement {
1
+ export class PDFElement {
8
2
  }
9
- exports.PDFElement = PDFElement;
10
- class SizedPDFElement extends PDFElement {
3
+ export class SizedPDFElement extends PDFElement {
11
4
  constructor(data) {
12
5
  super();
13
6
  this.x = data.x;
@@ -19,8 +12,7 @@ class SizedPDFElement extends PDFElement {
19
12
  return { x: this.x, y: this.y, width: this.width, height: this.height };
20
13
  }
21
14
  }
22
- exports.SizedPDFElement = SizedPDFElement;
23
- class FlexiblePDFElement extends PDFElement {
15
+ export class FlexiblePDFElement extends PDFElement {
24
16
  constructor(data) {
25
17
  super();
26
18
  this.flex = data.flex;
@@ -30,26 +22,25 @@ class FlexiblePDFElement extends PDFElement {
30
22
  return this.flex;
31
23
  }
32
24
  }
33
- exports.FlexiblePDFElement = FlexiblePDFElement;
34
- var HorizontalAlignment;
25
+ export var HorizontalAlignment;
35
26
  (function (HorizontalAlignment) {
36
27
  HorizontalAlignment["left"] = "LEFT";
37
28
  HorizontalAlignment["right"] = "RIGHT";
38
29
  HorizontalAlignment["center"] = "CENTER";
39
30
  HorizontalAlignment["block"] = "BLOCK";
40
- })(HorizontalAlignment || (exports.HorizontalAlignment = HorizontalAlignment = {}));
41
- var VerticalAlignment;
31
+ })(HorizontalAlignment || (HorizontalAlignment = {}));
32
+ export var VerticalAlignment;
42
33
  (function (VerticalAlignment) {
43
34
  VerticalAlignment["top"] = "TOP";
44
35
  VerticalAlignment["middle"] = "MIDDLE";
45
36
  VerticalAlignment["bottom"] = "BOTTOM";
46
- })(VerticalAlignment || (exports.VerticalAlignment = VerticalAlignment = {}));
47
- function isSizedElement(obj) {
37
+ })(VerticalAlignment || (VerticalAlignment = {}));
38
+ export function isSizedElement(obj) {
48
39
  return typeof obj === "object" && obj !== null && "x" in obj && "y" in obj;
49
40
  }
50
- function hasChildrenProp(obj) {
41
+ export function hasChildrenProp(obj) {
51
42
  return "children" in obj;
52
43
  }
53
- function hasChildProp(obj) {
44
+ export function hasChildProp(obj) {
54
45
  return "child" in obj;
55
46
  }