@jasy/pdf 1.0.0-alpha.1
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.
- package/README.md +171 -0
- package/dist/api/args.d.ts +10 -0
- package/dist/api/args.js +13 -0
- package/dist/api/color.d.ts +24 -0
- package/dist/api/color.js +215 -0
- package/dist/api/content.d.ts +36 -0
- package/dist/api/content.js +50 -0
- package/dist/api/descriptor.d.ts +25 -0
- package/dist/api/descriptor.js +71 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.js +27 -0
- package/dist/api/insets.d.ts +16 -0
- package/dist/api/insets.js +21 -0
- package/dist/api/layout.d.ts +72 -0
- package/dist/api/layout.js +99 -0
- package/dist/api/structure.d.ts +80 -0
- package/dist/api/structure.js +125 -0
- package/dist/api/table.d.ts +37 -0
- package/dist/api/table.js +87 -0
- package/dist/api/text.d.ts +28 -0
- package/dist/api/text.js +61 -0
- package/dist/assets/Courier-Bold.afm +342 -0
- package/dist/assets/Courier-BoldOblique.afm +342 -0
- package/dist/assets/Courier-Oblique.afm +342 -0
- package/dist/assets/Courier.afm +342 -0
- package/dist/assets/Helvetica-Bold.afm +2827 -0
- package/dist/assets/Helvetica-BoldOblique.afm +2827 -0
- package/dist/assets/Helvetica-Oblique.afm +3051 -0
- package/dist/assets/Helvetica.afm +3051 -0
- package/dist/assets/Symbol.afm +213 -0
- package/dist/assets/Times-Bold.afm +2588 -0
- package/dist/assets/Times-BoldItalic.afm +2384 -0
- package/dist/assets/Times-Italic.afm +2667 -0
- package/dist/assets/Times-Roman.afm +2419 -0
- package/dist/assets/ZapfDingbats.afm +225 -0
- package/dist/assets/agl.txt +695 -0
- package/dist/common/color.d.ts +37 -0
- package/dist/common/color.js +62 -0
- package/dist/constants/page-sizes.d.ts +44 -0
- package/dist/constants/page-sizes.js +92 -0
- package/dist/constants/pdf-parts.d.ts +5 -0
- package/dist/constants/pdf-parts.js +8 -0
- package/dist/elements/container-element.d.ts +35 -0
- package/dist/elements/container-element.js +91 -0
- package/dist/elements/image-element.d.ts +56 -0
- package/dist/elements/image-element.js +151 -0
- package/dist/elements/index.d.ts +10 -0
- package/dist/elements/index.js +28 -0
- package/dist/elements/layout/deferred-element.d.ts +19 -0
- package/dist/elements/layout/deferred-element.js +33 -0
- package/dist/elements/layout/expanded-element.d.ts +30 -0
- package/dist/elements/layout/expanded-element.js +68 -0
- package/dist/elements/layout/padding-element.d.ts +29 -0
- package/dist/elements/layout/padding-element.js +76 -0
- package/dist/elements/layout/repeating-header-element.d.ts +29 -0
- package/dist/elements/layout/repeating-header-element.js +60 -0
- package/dist/elements/layout/sized-container-element.d.ts +14 -0
- package/dist/elements/layout/sized-container-element.js +37 -0
- package/dist/elements/line-element.d.ts +31 -0
- package/dist/elements/line-element.js +44 -0
- package/dist/elements/page-element.d.ts +58 -0
- package/dist/elements/page-element.js +90 -0
- package/dist/elements/pdf-document-element.d.ts +13 -0
- package/dist/elements/pdf-document-element.js +22 -0
- package/dist/elements/pdf-element.d.ts +67 -0
- package/dist/elements/pdf-element.js +55 -0
- package/dist/elements/rectangle-element.d.ts +55 -0
- package/dist/elements/rectangle-element.js +120 -0
- package/dist/elements/row-element.d.ts +42 -0
- package/dist/elements/row-element.js +54 -0
- package/dist/elements/text-element.d.ts +59 -0
- package/dist/elements/text-element.js +137 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +21 -0
- package/dist/ir/display-list.d.ts +74 -0
- package/dist/ir/display-list.js +2 -0
- package/dist/layout/box-constraints.d.ts +56 -0
- package/dist/layout/box-constraints.js +73 -0
- package/dist/layout/fragmentation.d.ts +42 -0
- package/dist/layout/fragmentation.js +61 -0
- package/dist/renderer/container-renderer.d.ts +6 -0
- package/dist/renderer/container-renderer.js +30 -0
- package/dist/renderer/deferred-renderer.d.ts +6 -0
- package/dist/renderer/deferred-renderer.js +25 -0
- package/dist/renderer/expanded-renderer.d.ts +6 -0
- package/dist/renderer/expanded-renderer.js +23 -0
- package/dist/renderer/image-renderer.d.ts +6 -0
- package/dist/renderer/image-renderer.js +85 -0
- package/dist/renderer/index.d.ts +10 -0
- package/dist/renderer/index.js +26 -0
- package/dist/renderer/line-renderer.d.ts +6 -0
- package/dist/renderer/line-renderer.js +30 -0
- package/dist/renderer/padding-renderer.d.ts +6 -0
- package/dist/renderer/padding-renderer.js +23 -0
- package/dist/renderer/page-renderer.d.ts +5 -0
- package/dist/renderer/page-renderer.js +81 -0
- package/dist/renderer/pdf-backend.d.ts +45 -0
- package/dist/renderer/pdf-backend.js +184 -0
- package/dist/renderer/pdf-config.d.ts +8 -0
- package/dist/renderer/pdf-config.js +17 -0
- package/dist/renderer/pdf-document-class.d.ts +42 -0
- package/dist/renderer/pdf-document-class.js +118 -0
- package/dist/renderer/pdf-document-renderer.d.ts +20 -0
- package/dist/renderer/pdf-document-renderer.js +104 -0
- package/dist/renderer/pdf-renderer.d.ts +5 -0
- package/dist/renderer/pdf-renderer.js +92 -0
- package/dist/renderer/rectangle-renderer.d.ts +8 -0
- package/dist/renderer/rectangle-renderer.js +61 -0
- package/dist/renderer/repeating-header-renderer.d.ts +6 -0
- package/dist/renderer/repeating-header-renderer.js +28 -0
- package/dist/renderer/row-renderer.d.ts +6 -0
- package/dist/renderer/row-renderer.js +30 -0
- package/dist/renderer/text-renderer.d.ts +9 -0
- package/dist/renderer/text-renderer.js +125 -0
- package/dist/text/line-breaker.d.ts +40 -0
- package/dist/text/line-breaker.js +106 -0
- package/dist/utils/afm-parser.d.ts +12 -0
- package/dist/utils/afm-parser.js +91 -0
- package/dist/utils/flex-layout.d.ts +53 -0
- package/dist/utils/flex-layout.js +119 -0
- package/dist/utils/font-metrics.d.ts +12 -0
- package/dist/utils/font-metrics.js +2 -0
- package/dist/utils/font-path.d.ts +1 -0
- package/dist/utils/font-path.js +19 -0
- package/dist/utils/image-helper.d.ts +43 -0
- package/dist/utils/image-helper.js +206 -0
- package/dist/utils/pdf-object-manager.d.ts +97 -0
- package/dist/utils/pdf-object-manager.js +645 -0
- package/dist/utils/renderer-registry.d.ts +6 -0
- package/dist/utils/renderer-registry.js +19 -0
- package/dist/utils/ttf-parser.d.ts +29 -0
- package/dist/utils/ttf-parser.js +191 -0
- package/dist/utils/ttf-subsetter.d.ts +1 -0
- package/dist/utils/ttf-subsetter.js +161 -0
- package/dist/utils/utf8-to-windows1252-encoder.d.ts +2 -0
- package/dist/utils/utf8-to-windows1252-encoder.js +55 -0
- package/dist/validators/element-validator.d.ts +8 -0
- package/dist/validators/element-validator.js +61 -0
- package/package.json +50 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeferredElement = void 0;
|
|
4
|
+
const fragmentation_1 = require("../../layout/fragmentation");
|
|
5
|
+
const pdf_element_1 = require("../pdf-element");
|
|
6
|
+
/**
|
|
7
|
+
* Builds its subtree at layout time via `resolve(ctx)`, so the tree can depend on font
|
|
8
|
+
* metrics (e.g. a Table resolving `"auto"` column widths from cell content). The engine
|
|
9
|
+
* stays table-agnostic - the closure comes from the API layer.
|
|
10
|
+
*/
|
|
11
|
+
class DeferredElement extends pdf_element_1.PDFElement {
|
|
12
|
+
constructor(resolve) {
|
|
13
|
+
super();
|
|
14
|
+
this.resolve = resolve;
|
|
15
|
+
}
|
|
16
|
+
build(ctx) {
|
|
17
|
+
this.composed = this.resolve(ctx);
|
|
18
|
+
return this.composed;
|
|
19
|
+
}
|
|
20
|
+
calculateLayout(constraints, offset, ctx) {
|
|
21
|
+
return this.build(ctx).calculateLayout(constraints, offset, ctx);
|
|
22
|
+
}
|
|
23
|
+
fragment(maxHeight, width, ctx) {
|
|
24
|
+
const c = this.build(ctx);
|
|
25
|
+
return (0, fragmentation_1.isFragmentable)(c)
|
|
26
|
+
? c.fragment(maxHeight, width, ctx)
|
|
27
|
+
: { fitted: this, remainder: null };
|
|
28
|
+
}
|
|
29
|
+
getProps() {
|
|
30
|
+
return { composed: this.composed };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.DeferredElement = DeferredElement;
|
|
@@ -0,0 +1,30 @@
|
|
|
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";
|
|
4
|
+
interface ExpandedElementParams extends FlexibleElement, WithChild {
|
|
5
|
+
}
|
|
6
|
+
export declare class ExpandedElement extends FlexiblePDFElement implements Fragmentable {
|
|
7
|
+
private child;
|
|
8
|
+
private x;
|
|
9
|
+
private y;
|
|
10
|
+
private width;
|
|
11
|
+
private height;
|
|
12
|
+
constructor({ flex, child }: ExpandedElementParams);
|
|
13
|
+
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
14
|
+
/**
|
|
15
|
+
* When the column paginates, a flex region can't "fill" across pages, so it delegates to
|
|
16
|
+
* its child: the child splits and each half is re-wrapped in an Expanded (which then
|
|
17
|
+
* fills the leftover space on whichever page it lands). If the child can't split, the
|
|
18
|
+
* whole Expanded moves on.
|
|
19
|
+
*/
|
|
20
|
+
fragment(maxHeight: number, width: number, ctx: LayoutContext): FragmentResult;
|
|
21
|
+
private cloneWithChild;
|
|
22
|
+
getProps(): {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
child: PDFElement;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
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 });
|
|
11
|
+
this.x = 0;
|
|
12
|
+
this.y = 0;
|
|
13
|
+
this.width = 0;
|
|
14
|
+
this.height = 0;
|
|
15
|
+
this.child = child;
|
|
16
|
+
}
|
|
17
|
+
calculateLayout(constraints, offset, ctx) {
|
|
18
|
+
if (constraints.hasBoundedWidth)
|
|
19
|
+
this.width = constraints.maxWidth;
|
|
20
|
+
// Absolute placement from the parent; assignment (not +=) so re-layout is idempotent.
|
|
21
|
+
this.x = offset.x;
|
|
22
|
+
this.y = offset.y;
|
|
23
|
+
element_validator_1.Validator.validateFlexElement(this);
|
|
24
|
+
if (constraints.hasBoundedHeight) {
|
|
25
|
+
// A bounded region: fill it - the normal flex behaviour.
|
|
26
|
+
this.height = constraints.maxHeight;
|
|
27
|
+
this.child.calculateLayout(box_constraints_1.BoxConstraints.loose(this.width, this.height), { x: this.x, y: this.y }, ctx);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Unbounded (measuring while paginating): there's no leftover space to fill, so
|
|
31
|
+
// collapse to the child's natural height. This lets an overflowing column flow
|
|
32
|
+
// 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);
|
|
34
|
+
this.height = childSize.height;
|
|
35
|
+
}
|
|
36
|
+
// Top-left coordinates; the Y-flip now happens once at the IR -> backend seam.
|
|
37
|
+
return { width: this.width, height: this.height };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* When the column paginates, a flex region can't "fill" across pages, so it delegates to
|
|
41
|
+
* its child: the child splits and each half is re-wrapped in an Expanded (which then
|
|
42
|
+
* fills the leftover space on whichever page it lands). If the child can't split, the
|
|
43
|
+
* whole Expanded moves on.
|
|
44
|
+
*/
|
|
45
|
+
fragment(maxHeight, width, ctx) {
|
|
46
|
+
if (!(0, fragmentation_1.isFragmentable)(this.child)) {
|
|
47
|
+
return { fitted: null, remainder: this };
|
|
48
|
+
}
|
|
49
|
+
const split = this.child.fragment(maxHeight, width, ctx);
|
|
50
|
+
return {
|
|
51
|
+
fitted: split.fitted ? this.cloneWithChild(split.fitted) : null,
|
|
52
|
+
remainder: split.remainder ? this.cloneWithChild(split.remainder) : null,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
cloneWithChild(child) {
|
|
56
|
+
return new ExpandedElement({ flex: this.flex, child });
|
|
57
|
+
}
|
|
58
|
+
getProps() {
|
|
59
|
+
return {
|
|
60
|
+
x: this.x,
|
|
61
|
+
y: this.y,
|
|
62
|
+
width: this.width,
|
|
63
|
+
height: this.height,
|
|
64
|
+
child: this.child,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.ExpandedElement = ExpandedElement;
|
|
@@ -0,0 +1,29 @@
|
|
|
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";
|
|
4
|
+
interface PaddingElementParams extends WithChild {
|
|
5
|
+
margin: [number, number, number, number];
|
|
6
|
+
}
|
|
7
|
+
export declare class PaddingElement extends SizedPDFElement implements Fragmentable {
|
|
8
|
+
private child;
|
|
9
|
+
private margin;
|
|
10
|
+
constructor({ margin, child }: PaddingElementParams);
|
|
11
|
+
/**
|
|
12
|
+
* Splits the padded box across pages (box-decoration-break: clone - every fragment
|
|
13
|
+
* keeps its full top/bottom inset). The child is fragmented into the space left after
|
|
14
|
+
* reserving the vertical insets; each half is re-wrapped in its own padding. If the
|
|
15
|
+
* child can't be split, the whole padding moves on as the remainder.
|
|
16
|
+
*/
|
|
17
|
+
fragment(maxHeight: number, width: number, ctx: LayoutContext): FragmentResult;
|
|
18
|
+
private cloneWithChild;
|
|
19
|
+
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
20
|
+
getProps(): {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
width: number | undefined;
|
|
24
|
+
height: number | undefined;
|
|
25
|
+
margin: [number, number, number, number];
|
|
26
|
+
child: PDFElement;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
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 {
|
|
9
|
+
constructor({ margin, child }) {
|
|
10
|
+
super({ x: 0, y: 0 });
|
|
11
|
+
this.child = child;
|
|
12
|
+
this.margin = margin;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Splits the padded box across pages (box-decoration-break: clone - every fragment
|
|
16
|
+
* keeps its full top/bottom inset). The child is fragmented into the space left after
|
|
17
|
+
* reserving the vertical insets; each half is re-wrapped in its own padding. If the
|
|
18
|
+
* child can't be split, the whole padding moves on as the remainder.
|
|
19
|
+
*/
|
|
20
|
+
fragment(maxHeight, width, ctx) {
|
|
21
|
+
if (!(0, fragmentation_1.isFragmentable)(this.child)) {
|
|
22
|
+
return { fitted: null, remainder: this };
|
|
23
|
+
}
|
|
24
|
+
const [marginTop, marginRight, marginBottom, marginLeft] = this.margin;
|
|
25
|
+
const childWidth = width - marginLeft - marginRight;
|
|
26
|
+
const childMaxHeight = maxHeight - marginTop - marginBottom;
|
|
27
|
+
const split = this.child.fragment(childMaxHeight, childWidth, ctx);
|
|
28
|
+
return {
|
|
29
|
+
fitted: split.fitted ? this.cloneWithChild(split.fitted) : null,
|
|
30
|
+
remainder: split.remainder ? this.cloneWithChild(split.remainder) : null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
cloneWithChild(child) {
|
|
34
|
+
return new PaddingElement({ margin: this.margin, child });
|
|
35
|
+
}
|
|
36
|
+
calculateLayout(constraints, offset, ctx) {
|
|
37
|
+
var _a;
|
|
38
|
+
// Padding takes the width it is offered; its height shrink-wraps the child.
|
|
39
|
+
if (constraints.hasBoundedWidth)
|
|
40
|
+
this.width = constraints.maxWidth;
|
|
41
|
+
this.x = offset.x;
|
|
42
|
+
this.y = offset.y;
|
|
43
|
+
const [marginTop, marginRight, marginBottom, marginLeft] = this.margin;
|
|
44
|
+
// The child is inset by the margins: shifted down/right, narrowed by the
|
|
45
|
+
// horizontal margins, and left height-unbounded so it sizes to its own content.
|
|
46
|
+
const childOffset = {
|
|
47
|
+
x: this.x + marginLeft,
|
|
48
|
+
y: this.y + marginTop,
|
|
49
|
+
};
|
|
50
|
+
const childWidth = constraints.hasBoundedWidth
|
|
51
|
+
? Math.max(0, constraints.maxWidth - marginLeft - marginRight)
|
|
52
|
+
: Infinity;
|
|
53
|
+
const childConstraints = box_constraints_1.BoxConstraints.loose(childWidth, Infinity);
|
|
54
|
+
const childSize = this.child.calculateLayout(childConstraints, childOffset, ctx);
|
|
55
|
+
this.height = childSize.height + marginTop + marginBottom;
|
|
56
|
+
// Unbounded width (e.g. a fixed child in a Row): shrink-wrap to the child + insets,
|
|
57
|
+
// mirroring how Container/Row shrink-wrap. Bounded width was set above (unchanged).
|
|
58
|
+
if (!constraints.hasBoundedWidth) {
|
|
59
|
+
this.width = childSize.width + marginLeft + marginRight;
|
|
60
|
+
}
|
|
61
|
+
element_validator_1.Validator.validateSizedElement(this);
|
|
62
|
+
// 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 };
|
|
64
|
+
}
|
|
65
|
+
getProps() {
|
|
66
|
+
return {
|
|
67
|
+
x: this.x,
|
|
68
|
+
y: this.y,
|
|
69
|
+
width: this.width,
|
|
70
|
+
height: this.height,
|
|
71
|
+
margin: this.margin,
|
|
72
|
+
child: this.child,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.PaddingElement = PaddingElement;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BoxConstraints, Offset, Size } from "../../layout/box-constraints";
|
|
2
|
+
import { Fragmentable, FragmentResult } from "../../layout/fragmentation";
|
|
3
|
+
import { LayoutContext, PDFElement } from "../pdf-element";
|
|
4
|
+
/**
|
|
5
|
+
* Stacks a `header` above a `body` and, when it paginates, **repeats the header on every
|
|
6
|
+
* fragment**. Used by `Table` so column headings reappear at the top of each page. Layout
|
|
7
|
+
* is just header-then-body (like a 2-row Column); the magic is in `fragment`: it splits the
|
|
8
|
+
* body and re-wraps each piece with the same header, so every physical page gets its own.
|
|
9
|
+
*/
|
|
10
|
+
export declare class RepeatingHeaderElement extends PDFElement implements Fragmentable {
|
|
11
|
+
private header;
|
|
12
|
+
private body;
|
|
13
|
+
private gap;
|
|
14
|
+
private x;
|
|
15
|
+
private y;
|
|
16
|
+
private width;
|
|
17
|
+
private height;
|
|
18
|
+
constructor(header: PDFElement, body: PDFElement, gap?: number);
|
|
19
|
+
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
20
|
+
fragment(maxHeight: number, width: number, ctx: LayoutContext): FragmentResult;
|
|
21
|
+
getProps(): {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
header: PDFElement;
|
|
27
|
+
body: PDFElement;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
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");
|
|
7
|
+
/**
|
|
8
|
+
* Stacks a `header` above a `body` and, when it paginates, **repeats the header on every
|
|
9
|
+
* fragment**. Used by `Table` so column headings reappear at the top of each page. Layout
|
|
10
|
+
* is just header-then-body (like a 2-row Column); the magic is in `fragment`: it splits the
|
|
11
|
+
* body and re-wraps each piece with the same header, so every physical page gets its own.
|
|
12
|
+
*/
|
|
13
|
+
class RepeatingHeaderElement extends pdf_element_1.PDFElement {
|
|
14
|
+
constructor(header, body, gap = 0) {
|
|
15
|
+
super();
|
|
16
|
+
this.header = header;
|
|
17
|
+
this.body = body;
|
|
18
|
+
this.gap = gap;
|
|
19
|
+
this.x = 0;
|
|
20
|
+
this.y = 0;
|
|
21
|
+
this.width = 0;
|
|
22
|
+
this.height = 0;
|
|
23
|
+
}
|
|
24
|
+
calculateLayout(constraints, offset, ctx) {
|
|
25
|
+
this.x = offset.x;
|
|
26
|
+
this.y = offset.y;
|
|
27
|
+
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);
|
|
30
|
+
this.width = width;
|
|
31
|
+
this.height = h.height + this.gap + b.height;
|
|
32
|
+
return { width: this.width, height: this.height };
|
|
33
|
+
}
|
|
34
|
+
fragment(maxHeight, width, ctx) {
|
|
35
|
+
// 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))
|
|
38
|
+
return { fitted: this, remainder: null };
|
|
39
|
+
const split = this.body.fragment(Math.max(0, maxHeight - headerHeight - this.gap), width, ctx);
|
|
40
|
+
// Body fits whole → the whole thing fits on this page.
|
|
41
|
+
if (split.remainder === null)
|
|
42
|
+
return { fitted: this, remainder: null };
|
|
43
|
+
// Re-wrap each body piece with the SAME header → it reappears on the next page too.
|
|
44
|
+
return {
|
|
45
|
+
fitted: split.fitted ? new RepeatingHeaderElement(this.header, split.fitted, this.gap) : null,
|
|
46
|
+
remainder: new RepeatingHeaderElement(this.header, split.remainder, this.gap),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
getProps() {
|
|
50
|
+
return {
|
|
51
|
+
x: this.x,
|
|
52
|
+
y: this.y,
|
|
53
|
+
width: this.width,
|
|
54
|
+
height: this.height,
|
|
55
|
+
header: this.header,
|
|
56
|
+
body: this.body,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.RepeatingHeaderElement = RepeatingHeaderElement;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SizedElement, WithChildren, SizedPDFElement, LayoutContext } from "../pdf-element";
|
|
2
|
+
import { BoxConstraints, Offset, Size } from "../../layout/box-constraints";
|
|
3
|
+
interface ContainerElementParams extends SizedElement, WithChildren {
|
|
4
|
+
color?: [number, number, number];
|
|
5
|
+
backgroundColor?: [number, number, number];
|
|
6
|
+
borderWidth?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class SizedContainerElement extends SizedPDFElement {
|
|
9
|
+
private children;
|
|
10
|
+
constructor({ width, height, children }: ContainerElementParams);
|
|
11
|
+
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
12
|
+
getProps(): ContainerElementParams;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
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 {
|
|
7
|
+
constructor({ width, height, children }) {
|
|
8
|
+
super({ x: 0, y: 0, width, height });
|
|
9
|
+
this.children = children;
|
|
10
|
+
}
|
|
11
|
+
calculateLayout(constraints, offset, ctx) {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
if (constraints.hasBoundedWidth)
|
|
14
|
+
this.width = constraints.maxWidth;
|
|
15
|
+
if (constraints.hasBoundedHeight)
|
|
16
|
+
this.height = constraints.maxHeight;
|
|
17
|
+
// Absolute placement from the parent; assignment (not +=) so re-layout is idempotent.
|
|
18
|
+
this.x = offset.x;
|
|
19
|
+
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;
|
|
22
|
+
if (this.children)
|
|
23
|
+
this.children.forEach((child) => child.calculateLayout(box_constraints_1.BoxConstraints.loose(width, height), { x: this.x, y: this.y }, ctx));
|
|
24
|
+
// Top-left coordinates; the Y-flip now happens once at the IR -> backend seam.
|
|
25
|
+
return { width, height };
|
|
26
|
+
}
|
|
27
|
+
getProps() {
|
|
28
|
+
return {
|
|
29
|
+
x: this.x,
|
|
30
|
+
y: this.y,
|
|
31
|
+
width: this.width,
|
|
32
|
+
height: this.height,
|
|
33
|
+
children: this.children,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.SizedContainerElement = SizedContainerElement;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Color } from "../common/color";
|
|
2
|
+
import { BoxConstraints, Offset, Size } from "../layout/box-constraints";
|
|
3
|
+
import { LayoutContext, SizedElement, SizedPDFElement } from "./pdf-element";
|
|
4
|
+
interface LineElementParams extends SizedElement {
|
|
5
|
+
color?: Color;
|
|
6
|
+
strokeWidth?: number;
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
xEnd: number;
|
|
10
|
+
yEnd: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class LineElement extends SizedPDFElement {
|
|
13
|
+
private color?;
|
|
14
|
+
private strokeWidth?;
|
|
15
|
+
private xEnd;
|
|
16
|
+
private yEnd;
|
|
17
|
+
private sizeMemory;
|
|
18
|
+
constructor({ color, strokeWidth, x, y, xEnd, yEnd }: LineElementParams);
|
|
19
|
+
calculateLayout(constraints: BoxConstraints, offset: Offset, _ctx: LayoutContext): Size;
|
|
20
|
+
getProps(): {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
xEnd: number;
|
|
24
|
+
yEnd: number;
|
|
25
|
+
height: number | undefined;
|
|
26
|
+
width: number | undefined;
|
|
27
|
+
color: Color | undefined;
|
|
28
|
+
strokeWidth: number | undefined;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
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 }) {
|
|
8
|
+
super({ x: x, y: y, width: xEnd, height: y + yEnd });
|
|
9
|
+
this.color = color;
|
|
10
|
+
this.strokeWidth = strokeWidth ? strokeWidth : 1;
|
|
11
|
+
this.x = x;
|
|
12
|
+
this.y = y;
|
|
13
|
+
this.xEnd = xEnd;
|
|
14
|
+
this.yEnd = yEnd;
|
|
15
|
+
this.sizeMemory = { x, y, width: xEnd, height: yEnd };
|
|
16
|
+
}
|
|
17
|
+
calculateLayout(constraints, offset, _ctx) {
|
|
18
|
+
var _a, _b;
|
|
19
|
+
// Set relative to parent
|
|
20
|
+
this.x = this.sizeMemory.x + offset.x;
|
|
21
|
+
this.y = this.sizeMemory.y + offset.y;
|
|
22
|
+
// The line spans the parent's width, so it needs a bounded width to anchor its end.
|
|
23
|
+
if (!constraints.hasBoundedWidth) {
|
|
24
|
+
throw new Error("The LineElement must be placed inside a parent container that defines its width");
|
|
25
|
+
}
|
|
26
|
+
this.xEnd = offset.x + constraints.maxWidth - this.sizeMemory.width;
|
|
27
|
+
this.yEnd = offset.y + this.sizeMemory.height;
|
|
28
|
+
// 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 };
|
|
30
|
+
}
|
|
31
|
+
getProps() {
|
|
32
|
+
return {
|
|
33
|
+
x: this.x,
|
|
34
|
+
y: this.y,
|
|
35
|
+
xEnd: this.xEnd,
|
|
36
|
+
yEnd: this.yEnd,
|
|
37
|
+
height: this.height,
|
|
38
|
+
width: this.width,
|
|
39
|
+
color: this.color,
|
|
40
|
+
strokeWidth: this.strokeWidth,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.LineElement = LineElement;
|
|
@@ -0,0 +1,58 @@
|
|
|
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";
|
|
7
|
+
export interface PDFPageConfig {
|
|
8
|
+
pageSize?: PageSize;
|
|
9
|
+
orientation?: Orientation;
|
|
10
|
+
margin?: Margin;
|
|
11
|
+
colorMode?: ColorMode;
|
|
12
|
+
defaultFont?: DefaultFont;
|
|
13
|
+
}
|
|
14
|
+
interface PDFPageParams extends WithChildren {
|
|
15
|
+
config?: PDFPageConfig;
|
|
16
|
+
/** Laid out at the TOP of the content box, repeated on every physical page. */
|
|
17
|
+
header?: PDFElement;
|
|
18
|
+
/** Laid out at the BOTTOM of the content box, repeated on every physical page. */
|
|
19
|
+
footer?: PDFElement;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The content box of a page (inside the margins, orientation applied) for a fully
|
|
23
|
+
* resolved config. Single source of truth, shared by `PageElement` layout and the page
|
|
24
|
+
* driver so they can never drift.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolvePageContentBox(config: PDFPageConfig): {
|
|
27
|
+
origin: Offset;
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
};
|
|
31
|
+
/** The body region of a page once the (optional) header/footer bands are subtracted. */
|
|
32
|
+
export interface PageBands {
|
|
33
|
+
bodyOrigin: Offset;
|
|
34
|
+
bodyWidth: number;
|
|
35
|
+
bodyHeight: number;
|
|
36
|
+
headerHeight: number;
|
|
37
|
+
footerHeight: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Lays out the header (top) and footer (bottom) of a page and returns the body band left
|
|
41
|
+
* in between. Header/footer take their natural height against the content width; the body
|
|
42
|
+
* gets `contentHeight - headerHeight - footerHeight`. Shared by `PageElement.calculateLayout`
|
|
43
|
+
* (placement) and the page driver (so its fragmentation `maxHeight` matches exactly). With
|
|
44
|
+
* no header/footer the bands are zero and the body equals the full content box - identical
|
|
45
|
+
* to a page without them.
|
|
46
|
+
*/
|
|
47
|
+
export declare function layoutPageBands(config: PDFPageConfig, header: PDFElement | undefined, footer: PDFElement | undefined, ctx: LayoutContext): PageBands;
|
|
48
|
+
export declare class PageElement extends PDFElement {
|
|
49
|
+
private config;
|
|
50
|
+
private children;
|
|
51
|
+
private header?;
|
|
52
|
+
private footer?;
|
|
53
|
+
constructor({ children, config, header, footer }: PDFPageParams);
|
|
54
|
+
calculateLayout(_constraints: BoxConstraints, _offset: Offset, ctx: LayoutContext): Size;
|
|
55
|
+
getProps(): PDFPageParams;
|
|
56
|
+
addTextElement(element: TextElement): this;
|
|
57
|
+
}
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
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");
|
|
10
|
+
/**
|
|
11
|
+
* The content box of a page (inside the margins, orientation applied) for a fully
|
|
12
|
+
* resolved config. Single source of truth, shared by `PageElement` layout and the page
|
|
13
|
+
* driver so they can never drift.
|
|
14
|
+
*/
|
|
15
|
+
function resolvePageContentBox(config) {
|
|
16
|
+
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) {
|
|
20
|
+
[width, height] = [height, width];
|
|
21
|
+
}
|
|
22
|
+
return { origin: { x: margin.left, y: margin.top }, width, height };
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Lays out the header (top) and footer (bottom) of a page and returns the body band left
|
|
26
|
+
* in between. Header/footer take their natural height against the content width; the body
|
|
27
|
+
* gets `contentHeight - headerHeight - footerHeight`. Shared by `PageElement.calculateLayout`
|
|
28
|
+
* (placement) and the page driver (so its fragmentation `maxHeight` matches exactly). With
|
|
29
|
+
* no header/footer the bands are zero and the body equals the full content box - identical
|
|
30
|
+
* to a page without them.
|
|
31
|
+
*/
|
|
32
|
+
function layoutPageBands(config, header, footer, ctx) {
|
|
33
|
+
const { origin, width, height } = resolvePageContentBox(config);
|
|
34
|
+
let headerHeight = 0;
|
|
35
|
+
if (header) {
|
|
36
|
+
headerHeight = header.calculateLayout(box_constraints_1.BoxConstraints.loose(width, Infinity), origin, ctx).height;
|
|
37
|
+
}
|
|
38
|
+
let footerHeight = 0;
|
|
39
|
+
if (footer) {
|
|
40
|
+
// 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);
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
bodyOrigin: { x: origin.x, y: origin.y + headerHeight },
|
|
46
|
+
bodyWidth: width,
|
|
47
|
+
bodyHeight: Math.max(0, height - headerHeight - footerHeight),
|
|
48
|
+
headerHeight,
|
|
49
|
+
footerHeight,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
class PageElement extends pdf_element_1.PDFElement {
|
|
53
|
+
constructor({ children, config, header, footer }) {
|
|
54
|
+
super();
|
|
55
|
+
this.children = children;
|
|
56
|
+
this.config = config !== null && config !== void 0 ? config : {};
|
|
57
|
+
this.header = header;
|
|
58
|
+
this.footer = footer;
|
|
59
|
+
}
|
|
60
|
+
calculateLayout(_constraints, _offset, ctx) {
|
|
61
|
+
// Merge the document defaults (carried in the context) with this page's overrides,
|
|
62
|
+
// then hand descendants a context bound to THIS page's geometry. This is what
|
|
63
|
+
// fixes the old last-page-wins global page-config bug.
|
|
64
|
+
this.config = Object.assign(Object.assign({}, ctx.pageConfig), this.config);
|
|
65
|
+
const pageCtx = {
|
|
66
|
+
metrics: ctx.metrics,
|
|
67
|
+
pageConfig: this.config,
|
|
68
|
+
};
|
|
69
|
+
// Place the header/footer bands; the body gets the region left in between (the whole
|
|
70
|
+
// content box when there is neither - byte-identical to a plain page).
|
|
71
|
+
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));
|
|
74
|
+
const { width, height } = resolvePageContentBox(this.config);
|
|
75
|
+
return { width, height };
|
|
76
|
+
}
|
|
77
|
+
getProps() {
|
|
78
|
+
return {
|
|
79
|
+
children: this.children,
|
|
80
|
+
config: this.config,
|
|
81
|
+
header: this.header,
|
|
82
|
+
footer: this.footer,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
addTextElement(element) {
|
|
86
|
+
this.children.push(element);
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.PageElement = PageElement;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PageElement } from "./page-element";
|
|
2
|
+
import { BoxConstraints, Offset, Size } from "../layout/box-constraints";
|
|
3
|
+
import { LayoutContext, PDFElement, WithChildren } from "./pdf-element";
|
|
4
|
+
interface PDFDocumentParams extends WithChildren {
|
|
5
|
+
children: PageElement[];
|
|
6
|
+
}
|
|
7
|
+
export declare class PDFDocumentElement extends PDFElement {
|
|
8
|
+
private children;
|
|
9
|
+
constructor({ children }: PDFDocumentParams);
|
|
10
|
+
calculateLayout(_constraints: BoxConstraints, _offset: Offset, ctx: LayoutContext): Size;
|
|
11
|
+
getProps(): PDFDocumentParams;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
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 }) {
|
|
8
|
+
super();
|
|
9
|
+
this.children = children;
|
|
10
|
+
}
|
|
11
|
+
calculateLayout(_constraints, _offset, ctx) {
|
|
12
|
+
// The document is the root: each page derives its own geometry, so it ignores the
|
|
13
|
+
// incoming constraints/offset. It has no size of its own.
|
|
14
|
+
const origin = { x: 0, y: 0 };
|
|
15
|
+
this.children.forEach((child) => child.calculateLayout(new box_constraints_1.BoxConstraints(), origin, ctx));
|
|
16
|
+
return { width: 0, height: 0 };
|
|
17
|
+
}
|
|
18
|
+
getProps() {
|
|
19
|
+
return { children: this.children };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.PDFDocumentElement = PDFDocumentElement;
|