@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
@@ -1,6 +1,6 @@
1
- import { PDFElement, LayoutContext, FlexiblePDFElement, WithChild, FlexibleElement } from "../pdf-element";
2
- import { BoxConstraints, Offset, Size } from "../../layout/box-constraints";
3
- import { Fragmentable, FragmentResult } from "../../layout/fragmentation";
1
+ import { PDFElement, LayoutContext, FlexiblePDFElement, WithChild, FlexibleElement } from "../pdf-element.js";
2
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
3
+ import { Fragmentable, FragmentResult } from "../../layout/fragmentation.js";
4
4
  interface ExpandedElementParams extends FlexibleElement, WithChild {
5
5
  }
6
6
  export declare class ExpandedElement extends FlexiblePDFElement implements Fragmentable {
@@ -9,7 +9,7 @@ export declare class ExpandedElement extends FlexiblePDFElement implements Fragm
9
9
  private y;
10
10
  private width;
11
11
  private height;
12
- constructor({ flex, child }: ExpandedElementParams);
12
+ constructor({ flex, basis, basisFactor, child }: ExpandedElementParams);
13
13
  calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
14
14
  /**
15
15
  * When the column paginates, a flex region can't "fill" across pages, so it delegates to
@@ -24,6 +24,8 @@ export declare class ExpandedElement extends FlexiblePDFElement implements Fragm
24
24
  y: number;
25
25
  width: number;
26
26
  height: number;
27
+ basis: number;
28
+ basisFactor: number | undefined;
27
29
  child: PDFElement;
28
30
  };
29
31
  }
@@ -1,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ExpandedElement = 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 ExpandedElement extends pdf_element_1.FlexiblePDFElement {
9
- constructor({ flex, child }) {
10
- super({ flex });
1
+ import { Validator } from "../../validators/element-validator.js";
2
+ import { FlexiblePDFElement, } from "../pdf-element.js";
3
+ import { BoxConstraints } from "../../layout/box-constraints.js";
4
+ import { isFragmentable } from "../../layout/fragmentation.js";
5
+ export class ExpandedElement extends FlexiblePDFElement {
6
+ constructor({ flex, basis, basisFactor, child }) {
7
+ super({ flex, basis, basisFactor });
11
8
  this.x = 0;
12
9
  this.y = 0;
13
10
  this.width = 0;
@@ -20,17 +17,17 @@ class ExpandedElement extends pdf_element_1.FlexiblePDFElement {
20
17
  // Absolute placement from the parent; assignment (not +=) so re-layout is idempotent.
21
18
  this.x = offset.x;
22
19
  this.y = offset.y;
23
- element_validator_1.Validator.validateFlexElement(this);
20
+ Validator.validateFlexElement(this);
24
21
  if (constraints.hasBoundedHeight) {
25
- // A bounded region: fill it - the normal flex behaviour.
22
+ // A bounded region: fill it - the normal flex behavior.
26
23
  this.height = constraints.maxHeight;
27
- this.child.calculateLayout(box_constraints_1.BoxConstraints.loose(this.width, this.height), { x: this.x, y: this.y }, ctx);
24
+ this.child.calculateLayout(BoxConstraints.loose(this.width, this.height), { x: this.x, y: this.y }, ctx);
28
25
  }
29
26
  else {
30
27
  // Unbounded (measuring while paginating): there's no leftover space to fill, so
31
28
  // collapse to the child's natural height. This lets an overflowing column flow
32
29
  // instead of the flex silently hiding the overflow.
33
- const childSize = this.child.calculateLayout(box_constraints_1.BoxConstraints.loose(this.width, Infinity), { x: this.x, y: this.y }, ctx);
30
+ const childSize = this.child.calculateLayout(BoxConstraints.loose(this.width, Infinity), { x: this.x, y: this.y }, ctx);
34
31
  this.height = childSize.height;
35
32
  }
36
33
  // Top-left coordinates; the Y-flip now happens once at the IR -> backend seam.
@@ -43,7 +40,7 @@ class ExpandedElement extends pdf_element_1.FlexiblePDFElement {
43
40
  * whole Expanded moves on.
44
41
  */
45
42
  fragment(maxHeight, width, ctx) {
46
- if (!(0, fragmentation_1.isFragmentable)(this.child)) {
43
+ if (!isFragmentable(this.child)) {
47
44
  return { fitted: null, remainder: this };
48
45
  }
49
46
  const split = this.child.fragment(maxHeight, width, ctx);
@@ -53,7 +50,14 @@ class ExpandedElement extends pdf_element_1.FlexiblePDFElement {
53
50
  };
54
51
  }
55
52
  cloneWithChild(child) {
56
- return new ExpandedElement({ flex: this.flex, child });
53
+ // The basis has to come along: a fragment that lost it would claim only its share of the leftover,
54
+ // so a `flexBasis` slot would silently change width on the page it continues onto.
55
+ return new ExpandedElement({
56
+ flex: this.flex,
57
+ basis: this.basis,
58
+ basisFactor: this.basisFactor,
59
+ child,
60
+ });
57
61
  }
58
62
  getProps() {
59
63
  return {
@@ -61,8 +65,9 @@ class ExpandedElement extends pdf_element_1.FlexiblePDFElement {
61
65
  y: this.y,
62
66
  width: this.width,
63
67
  height: this.height,
68
+ basis: this.basis,
69
+ basisFactor: this.basisFactor,
64
70
  child: this.child,
65
71
  };
66
72
  }
67
73
  }
68
- exports.ExpandedElement = ExpandedElement;
@@ -0,0 +1,42 @@
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
+ /**
5
+ * A layout-TRANSPARENT wrapper that tries to keep its content on ONE page (CSS `break-inside: avoid`).
6
+ * It delegates all layout and rendering to its child, so the visual result is byte-identical to the
7
+ * unwrapped content; only pagination behaves differently.
8
+ *
9
+ * The rule, decided in `fragment`:
10
+ * 1. Fits in the space offered here -> place it whole.
11
+ * 2. Does not fit here but fits on a FRESH -> veto the split: defer the whole group to the next
12
+ * full page page (`fitted: null`), so it lands together there.
13
+ * 3. Taller than a whole page -> drop the veto and split normally. A group that can
14
+ * never fit on one page must break, or pagination
15
+ * could not terminate. Inner `keepTogether`s survive
16
+ * this (they are separate elements, re-evaluated when
17
+ * the child splits) - graceful degrade, outer->inner.
18
+ *
19
+ * A forced page break inside the group (a `PageBreak`, or a `breakBefore`/`breakAfter`) contradicts
20
+ * keeping it together: the break wins (CSS behaves the same), and we WARN once rather than silently
21
+ * swallowing either intent.
22
+ */
23
+ export declare class KeepTogetherElement extends PDFElement implements Fragmentable {
24
+ private child;
25
+ private warnedBreakConflict;
26
+ constructor({ child }: {
27
+ child: PDFElement;
28
+ });
29
+ calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
30
+ relativeSizeFactor(horizontal: boolean): number | undefined;
31
+ needsBoundedMain(horizontal: boolean): boolean;
32
+ hasForcedBreak(): boolean;
33
+ breaksBefore(): boolean;
34
+ breaksAfter(): boolean;
35
+ fragment(maxHeight: number, width: number, ctx: LayoutContext): FragmentResult;
36
+ /** Delegate the actual split to the child, unwrapping - once we have decided to break the group, the
37
+ * pieces just flow (any INNER keepTogether lives in the child subtree and still vetoes there). */
38
+ private splitChild;
39
+ getProps(): {
40
+ child: PDFElement;
41
+ };
42
+ }
@@ -0,0 +1,85 @@
1
+ import { BoxConstraints } from "../../layout/box-constraints.js";
2
+ import { isFragmentable } from "../../layout/fragmentation.js";
3
+ import { PDFElement } from "../pdf-element.js";
4
+ /**
5
+ * A layout-TRANSPARENT wrapper that tries to keep its content on ONE page (CSS `break-inside: avoid`).
6
+ * It delegates all layout and rendering to its child, so the visual result is byte-identical to the
7
+ * unwrapped content; only pagination behaves differently.
8
+ *
9
+ * The rule, decided in `fragment`:
10
+ * 1. Fits in the space offered here -> place it whole.
11
+ * 2. Does not fit here but fits on a FRESH -> veto the split: defer the whole group to the next
12
+ * full page page (`fitted: null`), so it lands together there.
13
+ * 3. Taller than a whole page -> drop the veto and split normally. A group that can
14
+ * never fit on one page must break, or pagination
15
+ * could not terminate. Inner `keepTogether`s survive
16
+ * this (they are separate elements, re-evaluated when
17
+ * the child splits) - graceful degrade, outer->inner.
18
+ *
19
+ * A forced page break inside the group (a `PageBreak`, or a `breakBefore`/`breakAfter`) contradicts
20
+ * keeping it together: the break wins (CSS behaves the same), and we WARN once rather than silently
21
+ * swallowing either intent.
22
+ */
23
+ export class KeepTogetherElement extends PDFElement {
24
+ constructor({ child }) {
25
+ super();
26
+ this.warnedBreakConflict = false;
27
+ this.child = child;
28
+ }
29
+ calculateLayout(constraints, offset, ctx) {
30
+ return this.child.calculateLayout(constraints, offset, ctx);
31
+ }
32
+ // Transparent: forward the sizing hints the flex parent reads, so a %-sized or Spacer-holding child
33
+ // keeps working when it is wrapped (the wrapper must not swallow these).
34
+ relativeSizeFactor(horizontal) {
35
+ return this.child.relativeSizeFactor(horizontal);
36
+ }
37
+ needsBoundedMain(horizontal) {
38
+ return this.child.needsBoundedMain(horizontal);
39
+ }
40
+ // Transparent to break control: a break-before/after on the wrapped element still applies to the group
41
+ // as a whole, and an inner forced break still forces the parent to fragment us (so `fragment` runs).
42
+ hasForcedBreak() {
43
+ return this.child.hasForcedBreak();
44
+ }
45
+ breaksBefore() {
46
+ return this.child.breaksBefore();
47
+ }
48
+ breaksAfter() {
49
+ return this.child.breaksAfter();
50
+ }
51
+ fragment(maxHeight, width, ctx) {
52
+ // Contradiction: a forced break inside the group beats keeping it together. Split at the break by
53
+ // delegating to the child (which honours it), and say so once - never keep such a group whole.
54
+ if (this.child.hasForcedBreak()) {
55
+ if (!this.warnedBreakConflict) {
56
+ this.warnedBreakConflict = true;
57
+ console.warn("keepTogether contains a forced page break (PageBreak / breakBefore / breakAfter). The break " +
58
+ "wins and the group is split. Remove the break, or the keepTogether, to resolve this.");
59
+ }
60
+ return this.splitChild(maxHeight, width, ctx);
61
+ }
62
+ const natural = this.child.calculateLayout(BoxConstraints.loose(width, Infinity), { x: 0, y: 0 }, ctx).height;
63
+ // 1. Fits in the offered space: keep whole.
64
+ if (natural <= maxHeight)
65
+ return { fitted: this, remainder: null };
66
+ // 2. Would fit on a fresh full page: veto the split, defer the whole group to the next page. Only
67
+ // reachable in a PARTIAL region (something is already on this page); alone on a full page,
68
+ // `maxHeight` IS the page body, so `natural > maxHeight` means case 3, never this.
69
+ const pageBody = ctx.pageBodyHeight ?? maxHeight;
70
+ if (natural <= pageBody)
71
+ return { fitted: null, remainder: this };
72
+ // 3. Bigger than a whole page: it can never be kept together, so split it.
73
+ return this.splitChild(maxHeight, width, ctx);
74
+ }
75
+ /** Delegate the actual split to the child, unwrapping - once we have decided to break the group, the
76
+ * pieces just flow (any INNER keepTogether lives in the child subtree and still vetoes there). */
77
+ splitChild(maxHeight, width, ctx) {
78
+ if (!isFragmentable(this.child))
79
+ return { fitted: null, remainder: this };
80
+ return this.child.fragment(maxHeight, width, ctx);
81
+ }
82
+ getProps() {
83
+ return { child: this.child };
84
+ }
85
+ }
@@ -0,0 +1,33 @@
1
+ import { PDFElement, LayoutContext } from "../pdf-element.js";
2
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
3
+ /**
4
+ * Makes its child a clickable hyperlink. `href` is an external URL; `dest` is an internal named
5
+ * destination (an `Anchor` elsewhere in the document) - exactly one is set. Layout-transparent: it
6
+ * delegates `calculateLayout` to the child and records the resulting box, which the renderer turns into
7
+ * a `Link` IR node (and the page renderer into a /Link annotation). The link draws nothing itself -
8
+ * style the child (e.g. a blue Text) if you want it to look like a link.
9
+ */
10
+ export declare class LinkElement extends PDFElement {
11
+ private href?;
12
+ private dest?;
13
+ private child;
14
+ private x;
15
+ private y;
16
+ private width;
17
+ private height;
18
+ constructor({ href, dest, child }: {
19
+ href?: string;
20
+ dest?: string;
21
+ child: PDFElement;
22
+ });
23
+ calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
24
+ getProps(): {
25
+ href: string | undefined;
26
+ dest: string | undefined;
27
+ child: PDFElement;
28
+ x: number;
29
+ y: number;
30
+ width: number;
31
+ height: number;
32
+ };
33
+ }
@@ -0,0 +1,39 @@
1
+ import { PDFElement } from "../pdf-element.js";
2
+ /**
3
+ * Makes its child a clickable hyperlink. `href` is an external URL; `dest` is an internal named
4
+ * destination (an `Anchor` elsewhere in the document) - exactly one is set. Layout-transparent: it
5
+ * delegates `calculateLayout` to the child and records the resulting box, which the renderer turns into
6
+ * a `Link` IR node (and the page renderer into a /Link annotation). The link draws nothing itself -
7
+ * style the child (e.g. a blue Text) if you want it to look like a link.
8
+ */
9
+ export class LinkElement extends PDFElement {
10
+ constructor({ href, dest, child }) {
11
+ super();
12
+ this.x = 0;
13
+ this.y = 0;
14
+ this.width = 0;
15
+ this.height = 0;
16
+ this.href = href;
17
+ this.dest = dest;
18
+ this.child = child;
19
+ }
20
+ calculateLayout(constraints, offset, ctx) {
21
+ const size = this.child.calculateLayout(constraints, offset, ctx);
22
+ this.x = offset.x;
23
+ this.y = offset.y;
24
+ this.width = size.width;
25
+ this.height = size.height;
26
+ return size;
27
+ }
28
+ getProps() {
29
+ return {
30
+ href: this.href,
31
+ dest: this.dest,
32
+ child: this.child,
33
+ x: this.x,
34
+ y: this.y,
35
+ width: this.width,
36
+ height: this.height,
37
+ };
38
+ }
39
+ }
@@ -1,8 +1,10 @@
1
- import { PDFElement, LayoutContext, WithChild, SizedPDFElement } from "../pdf-element";
2
- import { BoxConstraints, Offset, Size } from "../../layout/box-constraints";
3
- import { Fragmentable, FragmentResult } from "../../layout/fragmentation";
1
+ import { PDFElement, LayoutContext, WithChild, SizedPDFElement } from "../pdf-element.js";
2
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
3
+ import { Fragmentable, FragmentResult } from "../../layout/fragmentation.js";
4
+ import { type EdgeSpecs } from "../../layout/insets.js";
4
5
  interface PaddingElementParams extends WithChild {
5
- margin: [number, number, number, number];
6
+ /** Still unresolved: a side may be a percentage of the offered WIDTH (see `Insets`). */
7
+ margin: EdgeSpecs;
6
8
  }
7
9
  export declare class PaddingElement extends SizedPDFElement implements Fragmentable {
8
10
  private child;
@@ -15,6 +17,9 @@ export declare class PaddingElement extends SizedPDFElement implements Fragmenta
15
17
  * child can't be split, the whole padding moves on as the remainder.
16
18
  */
17
19
  fragment(maxHeight: number, width: number, ctx: LayoutContext): FragmentResult;
20
+ hasForcedBreak(): boolean;
21
+ breaksBefore(): boolean;
22
+ breaksAfter(): boolean;
18
23
  private cloneWithChild;
19
24
  calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
20
25
  getProps(): {
@@ -22,7 +27,7 @@ export declare class PaddingElement extends SizedPDFElement implements Fragmenta
22
27
  y: number;
23
28
  width: number | undefined;
24
29
  height: number | undefined;
25
- margin: [number, number, number, number];
30
+ margin: EdgeSpecs;
26
31
  child: PDFElement;
27
32
  };
28
33
  }
@@ -1,11 +1,9 @@
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
+ import { resolveEdges } from "../../layout/insets.js";
6
+ export class PaddingElement extends SizedPDFElement {
9
7
  constructor({ margin, child }) {
10
8
  super({ x: 0, y: 0 });
11
9
  this.child = child;
@@ -18,29 +16,41 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
18
16
  * child can't be split, the whole padding moves on as the remainder.
19
17
  */
20
18
  fragment(maxHeight, width, ctx) {
21
- if (!(0, fragmentation_1.isFragmentable)(this.child)) {
19
+ if (!isFragmentable(this.child)) {
22
20
  return { fitted: null, remainder: this };
23
21
  }
24
- const [marginTop, marginRight, marginBottom, marginLeft] = this.margin;
22
+ const [marginTop, marginRight, marginBottom, marginLeft] = resolveEdges(this.margin, width);
25
23
  const childWidth = width - marginLeft - marginRight;
26
24
  const childMaxHeight = maxHeight - marginTop - marginBottom;
27
25
  const split = this.child.fragment(childMaxHeight, childWidth, ctx);
28
26
  return {
29
27
  fitted: split.fitted ? this.cloneWithChild(split.fitted) : null,
30
28
  remainder: split.remainder ? this.cloneWithChild(split.remainder) : null,
29
+ forceBreak: split.forceBreak,
31
30
  };
32
31
  }
32
+ hasForcedBreak() {
33
+ return this.child.hasForcedBreak();
34
+ }
35
+ // Padding is a transparent single-child wrapper, so a break-before/after on the wrapped element must
36
+ // still be seen by the parent packer at this boundary (otherwise it is swallowed).
37
+ breaksBefore() {
38
+ return this.child.breaksBefore();
39
+ }
40
+ breaksAfter() {
41
+ return this.child.breaksAfter();
42
+ }
33
43
  cloneWithChild(child) {
34
44
  return new PaddingElement({ margin: this.margin, child });
35
45
  }
36
46
  calculateLayout(constraints, offset, ctx) {
37
- var _a;
38
47
  // Padding takes the width it is offered; its height shrink-wraps the child.
39
48
  if (constraints.hasBoundedWidth)
40
49
  this.width = constraints.maxWidth;
41
50
  this.x = offset.x;
42
51
  this.y = offset.y;
43
- const [marginTop, marginRight, marginBottom, marginLeft] = this.margin;
52
+ // Percentages resolve against the width we were OFFERED, so every pass gets the same answer.
53
+ const [marginTop, marginRight, marginBottom, marginLeft] = resolveEdges(this.margin, constraints.maxWidth);
44
54
  // The child is inset by the margins: shifted down/right, narrowed by the
45
55
  // horizontal margins, and left height-unbounded so it sizes to its own content.
46
56
  const childOffset = {
@@ -50,7 +60,7 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
50
60
  const childWidth = constraints.hasBoundedWidth
51
61
  ? Math.max(0, constraints.maxWidth - marginLeft - marginRight)
52
62
  : Infinity;
53
- const childConstraints = box_constraints_1.BoxConstraints.loose(childWidth, Infinity);
63
+ const childConstraints = BoxConstraints.loose(childWidth, Infinity);
54
64
  const childSize = this.child.calculateLayout(childConstraints, childOffset, ctx);
55
65
  this.height = childSize.height + marginTop + marginBottom;
56
66
  // Unbounded width (e.g. a fixed child in a Row): shrink-wrap to the child + insets,
@@ -58,9 +68,9 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
58
68
  if (!constraints.hasBoundedWidth) {
59
69
  this.width = childSize.width + marginLeft + marginRight;
60
70
  }
61
- element_validator_1.Validator.validateSizedElement(this);
71
+ Validator.validateSizedElement(this);
62
72
  // 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 };
73
+ return { width: this.width ?? 0, height: this.height };
64
74
  }
65
75
  getProps() {
66
76
  return {
@@ -73,4 +83,3 @@ class PaddingElement extends pdf_element_1.SizedPDFElement {
73
83
  };
74
84
  }
75
85
  }
76
- exports.PaddingElement = PaddingElement;
@@ -0,0 +1,17 @@
1
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
2
+ import { LayoutContext, PDFElement } from "../pdf-element.js";
3
+ /**
4
+ * A forced page break. Placed in a flow (a `Column`/`Row`/`Box`), it makes everything AFTER it start
5
+ * on a fresh page, no matter how much space is left. It takes zero space and draws nothing - the
6
+ * pagination packer consumes it at the cut, so it never reaches the render pass.
7
+ *
8
+ * Nesting works: a break deep inside a container is honoured because the packer fragments any child
9
+ * whose subtree `hasForcedBreak()`, and the resulting `forceBreak` bubbles up so the outer flow stops
10
+ * too. A break wins over a `keepTogether` (a forced break cannot be avoided) - CSS behaves the same.
11
+ */
12
+ export declare class PageBreakElement extends PDFElement {
13
+ calculateLayout(_constraints: BoxConstraints, _offset: Offset, _ctx: LayoutContext): Size;
14
+ isPageBreak(): boolean;
15
+ hasForcedBreak(): boolean;
16
+ getProps(): Record<string, never>;
17
+ }
@@ -0,0 +1,24 @@
1
+ import { PDFElement } from "../pdf-element.js";
2
+ /**
3
+ * A forced page break. Placed in a flow (a `Column`/`Row`/`Box`), it makes everything AFTER it start
4
+ * on a fresh page, no matter how much space is left. It takes zero space and draws nothing - the
5
+ * pagination packer consumes it at the cut, so it never reaches the render pass.
6
+ *
7
+ * Nesting works: a break deep inside a container is honoured because the packer fragments any child
8
+ * whose subtree `hasForcedBreak()`, and the resulting `forceBreak` bubbles up so the outer flow stops
9
+ * too. A break wins over a `keepTogether` (a forced break cannot be avoided) - CSS behaves the same.
10
+ */
11
+ export class PageBreakElement extends PDFElement {
12
+ calculateLayout(_constraints, _offset, _ctx) {
13
+ return { width: 0, height: 0 };
14
+ }
15
+ isPageBreak() {
16
+ return true;
17
+ }
18
+ hasForcedBreak() {
19
+ return true;
20
+ }
21
+ getProps() {
22
+ return {};
23
+ }
24
+ }
@@ -0,0 +1,32 @@
1
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
2
+ import { LayoutContext, PageInfo, PDFElement } from "../pdf-element.js";
3
+ /**
4
+ * Builds its subtree from the page it lands on, so a header, a footer or plain body content can show
5
+ * `pageNumber` / `pageCount`. The closure runs on EVERY layout, because the numbers differ between the
6
+ * two driver passes: pagination has to size the element before the page total exists, so it builds
7
+ * against a provisional "1 of 1"; the render pass then rebuilds it with the real `PageInfo`.
8
+ *
9
+ * Two consequences, and neither is magic - both come from the same chicken-and-egg: the content decides
10
+ * the page count that the content displays.
11
+ *
12
+ * 1. In the flowing BODY the box is reserved by the provisional build, so a much wider final string
13
+ * (`"9 of 10"` vs `"1 of 1"`) can paint slightly past it. Keep dynamic body content roughly constant
14
+ * in width.
15
+ * 2. A header/footer is re-laid out per page, so its real height is honoured - but the BODY band was
16
+ * already sized against the provisional build. A later page whose header is SHORTER simply gains
17
+ * room (harmless). A later page whose header is TALLER shrinks the band its body was measured for,
18
+ * and that body can overflow. So: a conditional header may shrink on later pages, never grow.
19
+ */
20
+ export declare class PageBuilderElement extends PDFElement {
21
+ private composed?;
22
+ private readonly build;
23
+ constructor({ build }: {
24
+ build: (info: PageInfo) => PDFElement;
25
+ });
26
+ /** The real page info during the render pass; a provisional "1 of 1" while paginating. */
27
+ private infoFrom;
28
+ calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
29
+ getProps(): {
30
+ composed: PDFElement | undefined;
31
+ };
32
+ }
@@ -0,0 +1,45 @@
1
+ import { PDFElement } from "../pdf-element.js";
2
+ import { resolvePageSize } from "../page-element.js";
3
+ /**
4
+ * Builds its subtree from the page it lands on, so a header, a footer or plain body content can show
5
+ * `pageNumber` / `pageCount`. The closure runs on EVERY layout, because the numbers differ between the
6
+ * two driver passes: pagination has to size the element before the page total exists, so it builds
7
+ * against a provisional "1 of 1"; the render pass then rebuilds it with the real `PageInfo`.
8
+ *
9
+ * Two consequences, and neither is magic - both come from the same chicken-and-egg: the content decides
10
+ * the page count that the content displays.
11
+ *
12
+ * 1. In the flowing BODY the box is reserved by the provisional build, so a much wider final string
13
+ * (`"9 of 10"` vs `"1 of 1"`) can paint slightly past it. Keep dynamic body content roughly constant
14
+ * in width.
15
+ * 2. A header/footer is re-laid out per page, so its real height is honoured - but the BODY band was
16
+ * already sized against the provisional build. A later page whose header is SHORTER simply gains
17
+ * room (harmless). A later page whose header is TALLER shrinks the band its body was measured for,
18
+ * and that body can overflow. So: a conditional header may shrink on later pages, never grow.
19
+ */
20
+ export class PageBuilderElement extends PDFElement {
21
+ constructor({ build }) {
22
+ super();
23
+ this.build = build;
24
+ }
25
+ /** The real page info during the render pass; a provisional "1 of 1" while paginating. */
26
+ infoFrom(ctx) {
27
+ return (ctx.pageInfo ?? {
28
+ pageNumber: 1,
29
+ pageCount: 1,
30
+ subPageNumber: 1,
31
+ subPageTotalPages: 1,
32
+ pageSize: resolvePageSize(ctx.pageConfig),
33
+ });
34
+ }
35
+ calculateLayout(constraints, offset, ctx) {
36
+ this.composed = this.build(this.infoFrom(ctx));
37
+ return this.composed.calculateLayout(constraints, offset, ctx);
38
+ }
39
+ // Named `composed` (not `child`) like DeferredElement: the pre-layout image walk keys on `child`, and
40
+ // this subtree does not exist yet when it runs. So an Image inside a PageBuilder skips aspect-ratio
41
+ // pre-resolution - give it both width and height, exactly as inside a Deferred/Table subtree.
42
+ getProps() {
43
+ return { composed: this.composed };
44
+ }
45
+ }
@@ -0,0 +1,47 @@
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, or failing that the page's content box. It takes ZERO space in the normal flow -
28
+ * `calculateLayout` returns `Size(0,0)` and instead registers a placement closure on the frame. The
29
+ * frame runs that closure once it knows its own size, so `right`/`bottom` resolve against the final
30
+ * box and the child can overflow it (a negative `top`/`left` makes it poke into / out of the
31
+ * corner, e.g. a badge or tab).
32
+ *
33
+ * Every page supplies a frame - header, footer and body alike - so within a document there is
34
+ * always one. Outside of one we REFUSE rather than draw: the element used to fall through to its
35
+ * child's default (0, 0), which is how a header watermark landed silently in the page corner
36
+ * (ISSUE-4). Content that lands somewhere unasked is worse than content that does not render.
37
+ */
38
+ export declare class PositionedElement extends PDFElement {
39
+ private child;
40
+ private insets;
41
+ constructor({ child, top, right, bottom, left, h, v, x, y }: PositionedElementParams);
42
+ calculateLayout(_constraints: BoxConstraints, _offset: Offset, ctx: LayoutContext): Size;
43
+ /** Lays the child out at the resolved position inside (or overflowing) the frame box. */
44
+ private placeInFrame;
45
+ getProps(): WithChild;
46
+ }
47
+ export {};