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

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 (275) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -21
  3. package/dist/api/args.d.ts +1 -1
  4. package/dist/api/args.js +2 -5
  5. package/dist/api/color.d.ts +4 -4
  6. package/dist/api/color.js +11 -17
  7. package/dist/api/content.d.ts +20 -13
  8. package/dist/api/content.js +44 -29
  9. package/dist/api/descriptor.d.ts +2 -2
  10. package/dist/api/descriptor.js +121 -31
  11. package/dist/api/dimension.d.ts +76 -0
  12. package/dist/api/dimension.js +43 -0
  13. package/dist/api/font-url.d.ts +28 -0
  14. package/dist/api/font-url.js +134 -0
  15. package/dist/api/forms.d.ts +347 -0
  16. package/dist/api/forms.js +189 -0
  17. package/dist/api/gradient.d.ts +53 -0
  18. package/dist/api/gradient.js +97 -0
  19. package/dist/api/index.d.ts +13 -8
  20. package/dist/api/index.js +13 -24
  21. package/dist/api/insets.d.ts +19 -12
  22. package/dist/api/insets.js +19 -12
  23. package/dist/api/layout.d.ts +149 -25
  24. package/dist/api/layout.js +182 -51
  25. package/dist/api/page-builder.d.ts +40 -0
  26. package/dist/api/page-builder.js +44 -0
  27. package/dist/api/structure.d.ts +100 -13
  28. package/dist/api/structure.js +179 -88
  29. package/dist/api/table.d.ts +5 -5
  30. package/dist/api/table.js +38 -26
  31. package/dist/api/text.d.ts +90 -4
  32. package/dist/api/text.js +116 -31
  33. package/dist/assets/font-data.d.ts +2 -0
  34. package/dist/assets/font-data.js +21 -0
  35. package/dist/assets/font-data.ts +37 -0
  36. package/dist/common/color.js +1 -5
  37. package/dist/constants/page-sizes.js +3 -6
  38. package/dist/constants/pdf-parts.js +1 -4
  39. package/dist/crypto/legacy-handler.d.ts +43 -0
  40. package/dist/crypto/legacy-handler.js +145 -0
  41. package/dist/crypto/security-handler.d.ts +62 -0
  42. package/dist/crypto/security-handler.js +155 -0
  43. package/dist/crypto/webcrypto.d.ts +11 -0
  44. package/dist/crypto/webcrypto.js +62 -0
  45. package/dist/edit/acroform-reader.d.ts +70 -0
  46. package/dist/edit/acroform-reader.js +126 -0
  47. package/dist/edit/appearance.d.ts +47 -0
  48. package/dist/edit/appearance.js +171 -0
  49. package/dist/edit/document.d.ts +145 -0
  50. package/dist/edit/document.js +642 -0
  51. package/dist/edit/fill.d.ts +65 -0
  52. package/dist/edit/fill.js +424 -0
  53. package/dist/edit/flatten.d.ts +54 -0
  54. package/dist/edit/flatten.js +462 -0
  55. package/dist/edit/index.d.ts +20 -0
  56. package/dist/edit/index.js +18 -0
  57. package/dist/edit/lexer.d.ts +30 -0
  58. package/dist/edit/lexer.js +285 -0
  59. package/dist/edit/objects.d.ts +68 -0
  60. package/dist/edit/objects.js +83 -0
  61. package/dist/edit/writer.d.ts +60 -0
  62. package/dist/edit/writer.js +283 -0
  63. package/dist/elements/container-element.d.ts +50 -5
  64. package/dist/elements/container-element.js +100 -39
  65. package/dist/elements/forms/checkbox-element.d.ts +51 -0
  66. package/dist/elements/forms/checkbox-element.js +48 -0
  67. package/dist/elements/forms/choice-element.d.ts +53 -0
  68. package/dist/elements/forms/choice-element.js +59 -0
  69. package/dist/elements/forms/push-button-element.d.ts +56 -0
  70. package/dist/elements/forms/push-button-element.js +49 -0
  71. package/dist/elements/forms/radio-element.d.ts +52 -0
  72. package/dist/elements/forms/radio-element.js +49 -0
  73. package/dist/elements/forms/signature-element.d.ts +54 -0
  74. package/dist/elements/forms/signature-element.js +47 -0
  75. package/dist/elements/forms/text-field-element.d.ts +61 -0
  76. package/dist/elements/forms/text-field-element.js +54 -0
  77. package/dist/elements/image-element.d.ts +58 -6
  78. package/dist/elements/image-element.js +145 -111
  79. package/dist/elements/index.d.ts +26 -10
  80. package/dist/elements/index.js +26 -28
  81. package/dist/elements/layout/anchor-element.d.ts +23 -0
  82. package/dist/elements/layout/anchor-element.js +27 -0
  83. package/dist/elements/layout/bookmark-element.d.ts +27 -0
  84. package/dist/elements/layout/bookmark-element.js +30 -0
  85. package/dist/elements/layout/default-text-style-element.d.ts +30 -0
  86. package/dist/elements/layout/default-text-style-element.js +47 -0
  87. package/dist/elements/layout/deferred-element.d.ts +3 -3
  88. package/dist/elements/layout/deferred-element.js +4 -8
  89. package/dist/elements/layout/expanded-element.d.ts +6 -4
  90. package/dist/elements/layout/expanded-element.js +22 -17
  91. package/dist/elements/layout/keep-together-element.d.ts +42 -0
  92. package/dist/elements/layout/keep-together-element.js +85 -0
  93. package/dist/elements/layout/link-element.d.ts +33 -0
  94. package/dist/elements/layout/link-element.js +39 -0
  95. package/dist/elements/layout/padding-element.d.ts +10 -5
  96. package/dist/elements/layout/padding-element.js +25 -16
  97. package/dist/elements/layout/page-break-element.d.ts +17 -0
  98. package/dist/elements/layout/page-break-element.js +24 -0
  99. package/dist/elements/layout/page-builder-element.d.ts +32 -0
  100. package/dist/elements/layout/page-builder-element.js +45 -0
  101. package/dist/elements/layout/positioned-element.d.ts +47 -0
  102. package/dist/elements/layout/positioned-element.js +73 -0
  103. package/dist/elements/layout/repeating-header-element.d.ts +3 -3
  104. package/dist/elements/layout/repeating-header-element.js +8 -12
  105. package/dist/elements/layout/rotated-box-element.d.ts +35 -0
  106. package/dist/elements/layout/rotated-box-element.js +54 -0
  107. package/dist/elements/layout/rotated-element.d.ts +32 -0
  108. package/dist/elements/layout/rotated-element.js +41 -0
  109. package/dist/elements/layout/sized-container-element.d.ts +2 -2
  110. package/dist/elements/layout/sized-container-element.js +6 -11
  111. package/dist/elements/layout/struct-group.d.ts +28 -0
  112. package/dist/elements/layout/struct-group.js +42 -0
  113. package/dist/elements/line-element.d.ts +3 -3
  114. package/dist/elements/line-element.js +5 -10
  115. package/dist/elements/page-element.d.ts +26 -6
  116. package/dist/elements/page-element.js +72 -27
  117. package/dist/elements/pdf-document-element.d.ts +10 -4
  118. package/dist/elements/pdf-document-element.js +11 -10
  119. package/dist/elements/pdf-element.d.ts +150 -4
  120. package/dist/elements/pdf-element.js +138 -20
  121. package/dist/elements/rectangle-element.d.ts +52 -11
  122. package/dist/elements/rectangle-element.js +129 -36
  123. package/dist/elements/row-element.d.ts +45 -4
  124. package/dist/elements/row-element.js +66 -18
  125. package/dist/elements/text-element.d.ts +132 -11
  126. package/dist/elements/text-element.js +206 -56
  127. package/dist/forms/acroform.d.ts +63 -0
  128. package/dist/forms/acroform.js +427 -0
  129. package/dist/forms/appearance.d.ts +58 -0
  130. package/dist/forms/appearance.js +204 -0
  131. package/dist/forms/field.d.ts +164 -0
  132. package/dist/forms/field.js +1 -0
  133. package/dist/forms/pdf.d.ts +19 -0
  134. package/dist/forms/pdf.js +28 -0
  135. package/dist/index.d.ts +3 -3
  136. package/dist/index.js +3 -19
  137. package/dist/ir/display-list.d.ts +197 -8
  138. package/dist/ir/display-list.js +8 -2
  139. package/dist/layout/alignment.d.ts +10 -0
  140. package/dist/layout/alignment.js +6 -0
  141. package/dist/layout/box-constraints.d.ts +61 -0
  142. package/dist/layout/box-constraints.js +88 -6
  143. package/dist/layout/collect-images.d.ts +9 -0
  144. package/dist/layout/collect-images.js +34 -0
  145. package/dist/layout/fragmentation.d.ts +20 -1
  146. package/dist/layout/fragmentation.js +74 -18
  147. package/dist/layout/insets.d.ts +28 -0
  148. package/dist/layout/insets.js +20 -0
  149. package/dist/platform/browser-fs.d.ts +2 -0
  150. package/dist/platform/browser-fs.js +9 -0
  151. package/dist/platform/browser-image.d.ts +5 -0
  152. package/dist/platform/browser-image.js +13 -0
  153. package/dist/platform/node-fs.d.ts +2 -0
  154. package/dist/platform/node-fs.js +10 -0
  155. package/dist/platform/node-image.d.ts +5 -0
  156. package/dist/platform/node-image.js +9 -0
  157. package/dist/renderer/anchor-renderer.d.ts +6 -0
  158. package/dist/renderer/anchor-renderer.js +11 -0
  159. package/dist/renderer/bookmark-renderer.d.ts +6 -0
  160. package/dist/renderer/bookmark-renderer.js +11 -0
  161. package/dist/renderer/container-renderer.d.ts +3 -3
  162. package/dist/renderer/container-renderer.js +11 -28
  163. package/dist/renderer/default-text-style-renderer.d.ts +6 -0
  164. package/dist/renderer/default-text-style-renderer.js +10 -0
  165. package/dist/renderer/deferred-renderer.d.ts +3 -3
  166. package/dist/renderer/deferred-renderer.js +8 -23
  167. package/dist/renderer/emoji-image.d.ts +9 -0
  168. package/dist/renderer/emoji-image.js +68 -0
  169. package/dist/renderer/expanded-renderer.d.ts +3 -3
  170. package/dist/renderer/expanded-renderer.js +6 -21
  171. package/dist/renderer/form-field-renderer.d.ts +20 -0
  172. package/dist/renderer/form-field-renderer.js +12 -0
  173. package/dist/renderer/image-renderer.d.ts +4 -4
  174. package/dist/renderer/image-renderer.js +86 -75
  175. package/dist/renderer/index.d.ts +10 -10
  176. package/dist/renderer/index.js +10 -26
  177. package/dist/renderer/keep-together-renderer.d.ts +10 -0
  178. package/dist/renderer/keep-together-renderer.js +12 -0
  179. package/dist/renderer/line-renderer.d.ts +3 -3
  180. package/dist/renderer/line-renderer.js +13 -28
  181. package/dist/renderer/link-renderer.d.ts +6 -0
  182. package/dist/renderer/link-renderer.js +11 -0
  183. package/dist/renderer/padding-renderer.d.ts +3 -3
  184. package/dist/renderer/padding-renderer.js +6 -21
  185. package/dist/renderer/page-break-renderer.d.ts +14 -0
  186. package/dist/renderer/page-break-renderer.js +15 -0
  187. package/dist/renderer/page-builder-renderer.d.ts +6 -0
  188. package/dist/renderer/page-builder-renderer.js +11 -0
  189. package/dist/renderer/page-renderer.d.ts +2 -2
  190. package/dist/renderer/page-renderer.js +115 -77
  191. package/dist/renderer/pdf-backend.d.ts +31 -4
  192. package/dist/renderer/pdf-backend.js +287 -49
  193. package/dist/renderer/pdf-config.js +4 -7
  194. package/dist/renderer/pdf-document-class.d.ts +5 -5
  195. package/dist/renderer/pdf-document-class.js +27 -41
  196. package/dist/renderer/pdf-document-renderer.d.ts +19 -10
  197. package/dist/renderer/pdf-document-renderer.js +135 -91
  198. package/dist/renderer/pdf-renderer.d.ts +2 -2
  199. package/dist/renderer/pdf-renderer.js +165 -90
  200. package/dist/renderer/positioned-renderer.d.ts +6 -0
  201. package/dist/renderer/positioned-renderer.js +10 -0
  202. package/dist/renderer/rectangle-renderer.d.ts +3 -3
  203. package/dist/renderer/rectangle-renderer.js +49 -44
  204. package/dist/renderer/repeating-header-renderer.d.ts +3 -3
  205. package/dist/renderer/repeating-header-renderer.js +10 -26
  206. package/dist/renderer/rotated-renderer.d.ts +7 -0
  207. package/dist/renderer/rotated-renderer.js +29 -0
  208. package/dist/renderer/row-renderer.d.ts +3 -3
  209. package/dist/renderer/row-renderer.js +11 -28
  210. package/dist/renderer/struct-group-renderer.d.ts +10 -0
  211. package/dist/renderer/struct-group-renderer.js +24 -0
  212. package/dist/renderer/text-renderer.d.ts +9 -5
  213. package/dist/renderer/text-renderer.js +437 -89
  214. package/dist/text/advance.d.ts +34 -0
  215. package/dist/text/advance.js +45 -0
  216. package/dist/text/arabic.d.ts +20 -0
  217. package/dist/text/arabic.js +101 -0
  218. package/dist/text/bidi.d.ts +33 -0
  219. package/dist/text/bidi.js +94 -0
  220. package/dist/text/emoji-codepoints.d.ts +1 -0
  221. package/dist/text/emoji-codepoints.js +29 -0
  222. package/dist/text/font-fallback.d.ts +25 -0
  223. package/dist/text/font-fallback.js +38 -0
  224. package/dist/text/line-breaker.d.ts +50 -12
  225. package/dist/text/line-breaker.js +158 -37
  226. package/dist/text/line-metrics.d.ts +49 -0
  227. package/dist/text/line-metrics.js +57 -0
  228. package/dist/text/orphans-widows.d.ts +27 -0
  229. package/dist/text/orphans-widows.js +53 -0
  230. package/dist/text/shape.d.ts +29 -0
  231. package/dist/text/shape.js +67 -0
  232. package/dist/text/text-decoration.d.ts +50 -0
  233. package/dist/text/text-decoration.js +62 -0
  234. package/dist/text/text-style.d.ts +60 -0
  235. package/dist/text/text-style.js +79 -0
  236. package/dist/utils/afm-parser.d.ts +34 -0
  237. package/dist/utils/afm-parser.js +76 -17
  238. package/dist/utils/bytes.d.ts +24 -0
  239. package/dist/utils/bytes.js +76 -0
  240. package/dist/utils/dest-registry.d.ts +22 -0
  241. package/dist/utils/dest-registry.js +32 -0
  242. package/dist/utils/flex-layout.d.ts +36 -9
  243. package/dist/utils/flex-layout.js +207 -30
  244. package/dist/utils/font-metrics.d.ts +20 -1
  245. package/dist/utils/font-metrics.js +1 -2
  246. package/dist/utils/font-path.js +3 -6
  247. package/dist/utils/gsub.d.ts +36 -0
  248. package/dist/utils/gsub.js +178 -0
  249. package/dist/utils/image-helper.d.ts +6 -5
  250. package/dist/utils/image-helper.js +101 -111
  251. package/dist/utils/inflate.d.ts +16 -0
  252. package/dist/utils/inflate.js +52 -0
  253. package/dist/utils/md5.d.ts +4 -0
  254. package/dist/utils/md5.js +79 -0
  255. package/dist/utils/outline.d.ts +21 -0
  256. package/dist/utils/outline.js +79 -0
  257. package/dist/utils/pdf-object-manager.d.ts +110 -8
  258. package/dist/utils/pdf-object-manager.js +583 -141
  259. package/dist/utils/renderer-registry.d.ts +13 -1
  260. package/dist/utils/renderer-registry.js +23 -6
  261. package/dist/utils/struct-tree.d.ts +44 -0
  262. package/dist/utils/struct-tree.js +129 -0
  263. package/dist/utils/ttf-parser.d.ts +134 -2
  264. package/dist/utils/ttf-parser.js +873 -50
  265. package/dist/utils/ttf-subsetter.d.ts +1 -1
  266. package/dist/utils/ttf-subsetter.js +40 -42
  267. package/dist/utils/ua-xmp.d.ts +9 -0
  268. package/dist/utils/ua-xmp.js +32 -0
  269. package/dist/utils/utf8-to-windows1252-encoder.d.ts +6 -0
  270. package/dist/utils/utf8-to-windows1252-encoder.js +11 -4
  271. package/dist/utils/woff.d.ts +10 -0
  272. package/dist/utils/woff.js +116 -0
  273. package/dist/validators/element-validator.d.ts +2 -2
  274. package/dist/validators/element-validator.js +31 -26
  275. package/package.json +22 -2
@@ -0,0 +1,73 @@
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, or failing that the page's content box. It takes ZERO space in the normal flow -
6
+ * `calculateLayout` returns `Size(0,0)` and instead registers a placement closure on the frame. The
7
+ * frame runs that closure once it knows its own size, so `right`/`bottom` resolve against the final
8
+ * box and the child can overflow it (a negative `top`/`left` makes it poke into / out of the
9
+ * corner, e.g. a badge or tab).
10
+ *
11
+ * Every page supplies a frame - header, footer and body alike - so within a document there is
12
+ * always one. Outside of one we REFUSE rather than draw: the element used to fall through to its
13
+ * child's default (0, 0), which is how a header watermark landed silently in the page corner
14
+ * (ISSUE-4). Content that lands somewhere unasked is worse than content that does not render.
15
+ */
16
+ export class PositionedElement extends PDFElement {
17
+ constructor({ child, top, right, bottom, left, h, v, x, y }) {
18
+ super();
19
+ this.child = child;
20
+ this.insets = { top, right, bottom, left, h, v, x, y };
21
+ }
22
+ calculateLayout(_constraints, _offset, ctx) {
23
+ if (!ctx.frame) {
24
+ throw new Error("Positioned found no positioning frame. It must sit inside a Page (header, footer or body) " +
25
+ "or inside a Box({ relative: true }).");
26
+ }
27
+ // Defer to the frame: it calls back once it has sized itself. Out of flow either way.
28
+ ctx.frame.place.push((frame, frameCtx) => this.placeInFrame(frame, frameCtx));
29
+ return { width: 0, height: 0 };
30
+ }
31
+ /** Lays the child out at the resolved position inside (or overflowing) the frame box. */
32
+ placeInFrame(frame, ctx) {
33
+ const { top, right, bottom, left, h, v, x: nudgeX, y: nudgeY } = this.insets;
34
+ // An axis is PINNED (stretched) only when BOTH of its EDGES are given; otherwise the child
35
+ // shrink-wraps its content (unbounded), the CSS rule for an absolutely-positioned element. An
36
+ // anchor never stretches - it positions a content-sized child.
37
+ const width = left !== undefined && right !== undefined
38
+ ? Math.max(0, frame.size.width - left - right)
39
+ : Infinity;
40
+ const height = top !== undefined && bottom !== undefined
41
+ ? Math.max(0, frame.size.height - top - bottom)
42
+ : Infinity;
43
+ const constraints = BoxConstraints.loose(width, height);
44
+ // Measure first (so end/center anchors and right/bottom edges resolve against the child's size).
45
+ // The measuring pass gets a throwaway `place` list: this subtree is laid out twice, and a nested
46
+ // out-of-flow child would otherwise register its placement on both passes.
47
+ const measureCtx = ctx.frame
48
+ ? { ...ctx, frame: { ...ctx.frame, place: [] } }
49
+ : ctx;
50
+ const measured = this.child.calculateLayout(constraints, { x: 0, y: 0 }, measureCtx);
51
+ // Resolve one axis: a near-edge pins to origin, a far-edge pins to the far side; otherwise the
52
+ // anchor (default `start`) positions the child and the nudge shifts it from there.
53
+ const place = (origin, frameExtent, childExtent, nearEdge, farEdge, anchor, nudge) => {
54
+ if (nearEdge !== undefined)
55
+ return origin + nearEdge;
56
+ if (farEdge !== undefined)
57
+ return origin + frameExtent - childExtent - farEdge;
58
+ const base = anchor === "center"
59
+ ? (frameExtent - childExtent) / 2
60
+ : anchor === "end"
61
+ ? frameExtent - childExtent
62
+ : 0; // start (default)
63
+ return origin + base + (nudge ?? 0);
64
+ };
65
+ const x = place(frame.origin.x, frame.size.width, measured.width, left, right, h, nudgeX);
66
+ const y = place(frame.origin.y, frame.size.height, measured.height, top, bottom, v, nudgeY);
67
+ // Place it for real at the resolved position.
68
+ this.child.calculateLayout(constraints, { x, y }, ctx);
69
+ }
70
+ getProps() {
71
+ return { child: this.child };
72
+ }
73
+ }
@@ -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;
@@ -0,0 +1,35 @@
1
+ import { PDFElement, LayoutContext } from "../pdf-element.js";
2
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
3
+ /**
4
+ * Rotates its child by whole quarter-turns and, unlike `RotatedElement` (paint-only), makes the
5
+ * rotation LAYOUT-AWARE: for a 90 / 270 turn it SWAPS width and height, so the box reports the rotated
6
+ * footprint UP and siblings reflow around it. A tall text becomes a narrow vertical strip that actually
7
+ * reserves its narrow width and its long height - the "vertical label beside a table" case.
8
+ *
9
+ * `turns` is the number of 90-degree CLOCKWISE quarter-turns (like Flutter's `RotatedBox.quarterTurns`):
10
+ * 0 = none, 1 = 90, 2 = 180, 3 = 270. The child lays out with the box's constraints swapped, then it is
11
+ * placed centered on the box's center so a plain center-rotation (the shared renderer) maps it exactly
12
+ * onto the swapped box.
13
+ */
14
+ export declare class RotatedBoxElement extends PDFElement {
15
+ private turns;
16
+ private child;
17
+ private x;
18
+ private y;
19
+ private width;
20
+ private height;
21
+ constructor({ turns, child }: {
22
+ turns: number;
23
+ child: PDFElement;
24
+ });
25
+ calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
26
+ /** Same shape as `RotatedElement` (angle + box), so both share `RotatedRenderer`. */
27
+ getProps(): {
28
+ angle: number;
29
+ child: PDFElement;
30
+ x: number;
31
+ y: number;
32
+ width: number;
33
+ height: number;
34
+ };
35
+ }
@@ -0,0 +1,54 @@
1
+ import { PDFElement } from "../pdf-element.js";
2
+ import { BoxConstraints } from "../../layout/box-constraints.js";
3
+ /**
4
+ * Rotates its child by whole quarter-turns and, unlike `RotatedElement` (paint-only), makes the
5
+ * rotation LAYOUT-AWARE: for a 90 / 270 turn it SWAPS width and height, so the box reports the rotated
6
+ * footprint UP and siblings reflow around it. A tall text becomes a narrow vertical strip that actually
7
+ * reserves its narrow width and its long height - the "vertical label beside a table" case.
8
+ *
9
+ * `turns` is the number of 90-degree CLOCKWISE quarter-turns (like Flutter's `RotatedBox.quarterTurns`):
10
+ * 0 = none, 1 = 90, 2 = 180, 3 = 270. The child lays out with the box's constraints swapped, then it is
11
+ * placed centered on the box's center so a plain center-rotation (the shared renderer) maps it exactly
12
+ * onto the swapped box.
13
+ */
14
+ export class RotatedBoxElement extends PDFElement {
15
+ constructor({ turns, child }) {
16
+ super();
17
+ this.x = 0;
18
+ this.y = 0;
19
+ this.width = 0;
20
+ this.height = 0;
21
+ this.turns = ((Math.trunc(turns) % 4) + 4) % 4;
22
+ this.child = child;
23
+ }
24
+ calculateLayout(constraints, offset, ctx) {
25
+ const quarter = this.turns % 2 === 1; // 90 or 270: axes swap
26
+ // A quarter-turned child experiences the box's constraints with the axes swapped.
27
+ const childConstraints = quarter
28
+ ? new BoxConstraints(constraints.minHeight, constraints.maxHeight, constraints.minWidth, constraints.maxWidth)
29
+ : constraints;
30
+ // Measure the child to learn its natural size, then take that size swapped as our own box.
31
+ const child = this.child.calculateLayout(childConstraints, offset, ctx);
32
+ this.width = quarter ? child.height : child.width;
33
+ this.height = quarter ? child.width : child.height;
34
+ this.x = offset.x;
35
+ this.y = offset.y;
36
+ // Re-place the child CENTERED on the box center: a rotation around that center then maps the
37
+ // child's (w x h) box exactly onto our (swapped) box - so the shared renderer needs no special case.
38
+ const cx = this.x + this.width / 2;
39
+ const cy = this.y + this.height / 2;
40
+ this.child.calculateLayout(childConstraints, { x: cx - child.width / 2, y: cy - child.height / 2 }, ctx);
41
+ return { width: this.width, height: this.height };
42
+ }
43
+ /** Same shape as `RotatedElement` (angle + box), so both share `RotatedRenderer`. */
44
+ getProps() {
45
+ return {
46
+ angle: this.turns * 90,
47
+ child: this.child,
48
+ x: this.x,
49
+ y: this.y,
50
+ width: this.width,
51
+ height: this.height,
52
+ };
53
+ }
54
+ }
@@ -0,0 +1,32 @@
1
+ import { PDFElement, LayoutContext } from "../pdf-element.js";
2
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
3
+ /**
4
+ * Rotates its single child at PAINT time only (like Flutter's `Transform.rotate`): the child lays out
5
+ * in its normal, axis-aligned box and the element reports that same box UP, so siblings never reflow
6
+ * around the rotated shape. Only the drawing is rotated, around the box's center, by the renderer.
7
+ *
8
+ * Layout-transparent: it delegates `calculateLayout` to the child and just records the resulting box,
9
+ * which the renderer needs as the pivot. Not `Fragmentable` on purpose - a rotated subtree is atomic
10
+ * w.r.t. pagination (it moves whole to the next page rather than splitting mid-rotation).
11
+ */
12
+ export declare class RotatedElement extends PDFElement {
13
+ private angle;
14
+ private child;
15
+ private x;
16
+ private y;
17
+ private width;
18
+ private height;
19
+ constructor({ angle, child }: {
20
+ angle: number;
21
+ child: PDFElement;
22
+ });
23
+ calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
24
+ getProps(): {
25
+ angle: number;
26
+ child: PDFElement;
27
+ x: number;
28
+ y: number;
29
+ width: number;
30
+ height: number;
31
+ };
32
+ }
@@ -0,0 +1,41 @@
1
+ import { PDFElement } from "../pdf-element.js";
2
+ /**
3
+ * Rotates its single child at PAINT time only (like Flutter's `Transform.rotate`): the child lays out
4
+ * in its normal, axis-aligned box and the element reports that same box UP, so siblings never reflow
5
+ * around the rotated shape. Only the drawing is rotated, around the box's center, by the renderer.
6
+ *
7
+ * Layout-transparent: it delegates `calculateLayout` to the child and just records the resulting box,
8
+ * which the renderer needs as the pivot. Not `Fragmentable` on purpose - a rotated subtree is atomic
9
+ * w.r.t. pagination (it moves whole to the next page rather than splitting mid-rotation).
10
+ */
11
+ export class RotatedElement extends PDFElement {
12
+ constructor({ angle, child }) {
13
+ super();
14
+ this.x = 0;
15
+ this.y = 0;
16
+ this.width = 0;
17
+ this.height = 0;
18
+ this.angle = angle;
19
+ this.child = child;
20
+ }
21
+ calculateLayout(constraints, offset, ctx) {
22
+ // Delegate entirely to the child, then record its box (position + size) as our own - the
23
+ // rotation does not change what space we take, only how the child is painted.
24
+ const size = this.child.calculateLayout(constraints, offset, ctx);
25
+ this.x = offset.x;
26
+ this.y = offset.y;
27
+ this.width = size.width;
28
+ this.height = size.height;
29
+ return size;
30
+ }
31
+ getProps() {
32
+ return {
33
+ angle: this.angle,
34
+ child: this.child,
35
+ x: this.x,
36
+ y: this.y,
37
+ width: this.width,
38
+ height: this.height,
39
+ };
40
+ }
41
+ }
@@ -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;
@@ -0,0 +1,28 @@
1
+ import { PDFElement, LayoutContext } from "../pdf-element.js";
2
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
3
+ import { Fragmentable, FragmentResult } from "../../layout/fragmentation.js";
4
+ /**
5
+ * A layout-TRANSPARENT wrapper that assigns an accessibility structure role (Table / TR / TH / TD / …) to
6
+ * its single child. It delegates ALL layout and fragmentation to the child, so the visual result is byte-
7
+ * identical; only its renderer opens a structure element and nests the child's tags underneath.
8
+ *
9
+ * Split across pages, the fitted and remainder halves share this group's `structId`, so it stays ONE
10
+ * logical structure element (a table broken over pages is a single <Table>, exactly as Acrobat produces).
11
+ */
12
+ export declare class StructGroup extends PDFElement implements Fragmentable {
13
+ private role;
14
+ private child;
15
+ constructor({ role, child }: {
16
+ role: string;
17
+ child: PDFElement;
18
+ });
19
+ calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
20
+ /** Only splittable when the wrapped child is - so a StructGroup(Row) is moved whole to the next page,
21
+ * not clipped at the boundary (isFragmentable honours this veto). */
22
+ canFragment(): boolean;
23
+ fragment(maxHeight: number, width: number, ctx: LayoutContext): FragmentResult;
24
+ getProps(): {
25
+ role: string;
26
+ child: PDFElement;
27
+ };
28
+ }
@@ -0,0 +1,42 @@
1
+ import { PDFElement } from "../pdf-element.js";
2
+ import { isFragmentable } from "../../layout/fragmentation.js";
3
+ /**
4
+ * A layout-TRANSPARENT wrapper that assigns an accessibility structure role (Table / TR / TH / TD / …) to
5
+ * its single child. It delegates ALL layout and fragmentation to the child, so the visual result is byte-
6
+ * identical; only its renderer opens a structure element and nests the child's tags underneath.
7
+ *
8
+ * Split across pages, the fitted and remainder halves share this group's `structId`, so it stays ONE
9
+ * logical structure element (a table broken over pages is a single <Table>, exactly as Acrobat produces).
10
+ */
11
+ export class StructGroup extends PDFElement {
12
+ constructor({ role, child }) {
13
+ super();
14
+ this.role = role;
15
+ this.child = child;
16
+ }
17
+ calculateLayout(constraints, offset, ctx) {
18
+ return this.child.calculateLayout(constraints, offset, ctx);
19
+ }
20
+ /** Only splittable when the wrapped child is - so a StructGroup(Row) is moved whole to the next page,
21
+ * not clipped at the boundary (isFragmentable honours this veto). */
22
+ canFragment() {
23
+ return isFragmentable(this.child);
24
+ }
25
+ fragment(maxHeight, width, ctx) {
26
+ if (!isFragmentable(this.child))
27
+ return { fitted: null, remainder: this };
28
+ const { fitted, remainder } = this.child.fragment(maxHeight, width, ctx);
29
+ // Re-wrap each half with the SAME role + identity, so both pages point at one structure element.
30
+ return {
31
+ fitted: fitted
32
+ ? new StructGroup({ role: this.role, child: fitted }).adoptStructId(this)
33
+ : null,
34
+ remainder: remainder
35
+ ? new StructGroup({ role: this.role, child: remainder }).adoptStructId(this)
36
+ : null,
37
+ };
38
+ }
39
+ getProps() {
40
+ return { role: this.role, child: this.child };
41
+ }
42
+ }
@@ -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, PositioningFrame, 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;
@@ -18,6 +20,14 @@ interface PDFPageParams extends WithChildren {
18
20
  /** Laid out at the BOTTOM of the content box, repeated on every physical page. */
19
21
  footer?: PDFElement;
20
22
  }
23
+ /**
24
+ * The full page (media box) size in points, orientation applied. This is what a `PageBuilder` sees as
25
+ * `pageSize`; `resolvePageContentBox` below then subtracts the margins.
26
+ */
27
+ export declare function resolvePageSize(config: PDFPageConfig): {
28
+ width: number;
29
+ height: number;
30
+ };
21
31
  /**
22
32
  * The content box of a page (inside the margins, orientation applied) for a fully
23
33
  * resolved config. Single source of truth, shared by `PageElement` layout and the page
@@ -44,6 +54,16 @@ export interface PageBands {
44
54
  * no header/footer the bands are zero and the body equals the full content box - identical
45
55
  * to a page without them.
46
56
  */
57
+ /**
58
+ * The page's positioning frame: its CONTENT box (paper minus margins). Header, footer and body all
59
+ * resolve a `Positioned` against this same box, so `top`/`bottom` mean the same thing in each.
60
+ *
61
+ * `layoutPageBands` lays the bands out, so its caller must hand it a context carrying this frame -
62
+ * otherwise a `Positioned` in a band has nothing to resolve against (ISSUE-4). A caller that only
63
+ * wants the band HEIGHTS may throw the frame away without draining it: an out-of-flow child
64
+ * contributes no height.
65
+ */
66
+ export declare function pageFrame(config: PDFPageConfig): PositioningFrame;
47
67
  export declare function layoutPageBands(config: PDFPageConfig, header: PDFElement | undefined, footer: PDFElement | undefined, ctx: LayoutContext): PageBands;
48
68
  export declare class PageElement extends PDFElement {
49
69
  private config;