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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +3 -3
  2. package/dist/api/args.d.ts +1 -1
  3. package/dist/api/args.js +2 -5
  4. package/dist/api/color.d.ts +4 -4
  5. package/dist/api/color.js +11 -17
  6. package/dist/api/content.d.ts +8 -8
  7. package/dist/api/content.js +23 -24
  8. package/dist/api/descriptor.d.ts +2 -2
  9. package/dist/api/descriptor.js +75 -31
  10. package/dist/api/index.d.ts +8 -8
  11. package/dist/api/index.js +8 -24
  12. package/dist/api/insets.js +4 -8
  13. package/dist/api/layout.d.ts +18 -16
  14. package/dist/api/layout.js +41 -52
  15. package/dist/api/structure.d.ts +60 -13
  16. package/dist/api/structure.js +132 -88
  17. package/dist/api/table.d.ts +5 -5
  18. package/dist/api/table.js +28 -24
  19. package/dist/api/text.d.ts +27 -2
  20. package/dist/api/text.js +45 -27
  21. package/dist/assets/font-data.d.ts +2 -0
  22. package/dist/assets/font-data.js +6 -0
  23. package/dist/assets/font-data.ts +7 -0
  24. package/dist/common/color.js +1 -5
  25. package/dist/constants/page-sizes.js +3 -6
  26. package/dist/constants/pdf-parts.js +1 -4
  27. package/dist/elements/container-element.d.ts +4 -4
  28. package/dist/elements/container-element.js +9 -13
  29. package/dist/elements/image-element.d.ts +18 -2
  30. package/dist/elements/image-element.js +81 -105
  31. package/dist/elements/index.d.ts +12 -11
  32. package/dist/elements/index.js +12 -29
  33. package/dist/elements/layout/default-text-style-element.d.ts +30 -0
  34. package/dist/elements/layout/default-text-style-element.js +47 -0
  35. package/dist/elements/layout/deferred-element.d.ts +3 -3
  36. package/dist/elements/layout/deferred-element.js +4 -8
  37. package/dist/elements/layout/expanded-element.d.ts +3 -3
  38. package/dist/elements/layout/expanded-element.js +10 -14
  39. package/dist/elements/layout/padding-element.d.ts +3 -3
  40. package/dist/elements/layout/padding-element.js +9 -14
  41. package/dist/elements/layout/positioned-element.d.ts +17 -4
  42. package/dist/elements/layout/positioned-element.js +29 -25
  43. package/dist/elements/layout/repeating-header-element.d.ts +3 -3
  44. package/dist/elements/layout/repeating-header-element.js +8 -12
  45. package/dist/elements/layout/sized-container-element.d.ts +2 -2
  46. package/dist/elements/layout/sized-container-element.js +6 -11
  47. package/dist/elements/line-element.d.ts +3 -3
  48. package/dist/elements/line-element.js +5 -10
  49. package/dist/elements/page-element.d.ts +8 -6
  50. package/dist/elements/page-element.js +20 -23
  51. package/dist/elements/pdf-document-element.d.ts +10 -4
  52. package/dist/elements/pdf-document-element.js +11 -10
  53. package/dist/elements/pdf-element.d.ts +12 -3
  54. package/dist/elements/pdf-element.js +10 -19
  55. package/dist/elements/rectangle-element.d.ts +5 -5
  56. package/dist/elements/rectangle-element.js +19 -25
  57. package/dist/elements/row-element.d.ts +3 -3
  58. package/dist/elements/row-element.js +7 -11
  59. package/dist/elements/text-element.d.ts +37 -11
  60. package/dist/elements/text-element.js +64 -39
  61. package/dist/index.d.ts +3 -3
  62. package/dist/index.js +3 -19
  63. package/dist/ir/display-list.d.ts +4 -2
  64. package/dist/ir/display-list.js +1 -2
  65. package/dist/layout/box-constraints.js +2 -6
  66. package/dist/layout/fragmentation.d.ts +8 -1
  67. package/dist/layout/fragmentation.js +22 -10
  68. package/dist/platform/browser-fs.d.ts +2 -0
  69. package/dist/platform/browser-fs.js +9 -0
  70. package/dist/platform/browser-image.d.ts +5 -0
  71. package/dist/platform/browser-image.js +13 -0
  72. package/dist/platform/node-fs.d.ts +2 -0
  73. package/dist/platform/node-fs.js +10 -0
  74. package/dist/platform/node-image.d.ts +5 -0
  75. package/dist/platform/node-image.js +9 -0
  76. package/dist/renderer/container-renderer.d.ts +3 -3
  77. package/dist/renderer/container-renderer.js +12 -27
  78. package/dist/renderer/default-text-style-renderer.d.ts +6 -0
  79. package/dist/renderer/default-text-style-renderer.js +10 -0
  80. package/dist/renderer/deferred-renderer.d.ts +3 -3
  81. package/dist/renderer/deferred-renderer.js +8 -23
  82. package/dist/renderer/expanded-renderer.d.ts +3 -3
  83. package/dist/renderer/expanded-renderer.js +6 -21
  84. package/dist/renderer/image-renderer.d.ts +3 -3
  85. package/dist/renderer/image-renderer.js +77 -75
  86. package/dist/renderer/index.d.ts +10 -10
  87. package/dist/renderer/index.js +10 -26
  88. package/dist/renderer/line-renderer.d.ts +3 -3
  89. package/dist/renderer/line-renderer.js +13 -28
  90. package/dist/renderer/padding-renderer.d.ts +3 -3
  91. package/dist/renderer/padding-renderer.js +6 -21
  92. package/dist/renderer/page-renderer.d.ts +2 -2
  93. package/dist/renderer/page-renderer.js +61 -77
  94. package/dist/renderer/pdf-backend.d.ts +2 -2
  95. package/dist/renderer/pdf-backend.js +21 -19
  96. package/dist/renderer/pdf-config.js +4 -7
  97. package/dist/renderer/pdf-document-class.d.ts +5 -5
  98. package/dist/renderer/pdf-document-class.js +24 -41
  99. package/dist/renderer/pdf-document-renderer.d.ts +3 -3
  100. package/dist/renderer/pdf-document-renderer.js +71 -85
  101. package/dist/renderer/pdf-renderer.d.ts +2 -2
  102. package/dist/renderer/pdf-renderer.js +83 -93
  103. package/dist/renderer/positioned-renderer.d.ts +3 -3
  104. package/dist/renderer/positioned-renderer.js +8 -23
  105. package/dist/renderer/rectangle-renderer.d.ts +3 -3
  106. package/dist/renderer/rectangle-renderer.js +45 -52
  107. package/dist/renderer/repeating-header-renderer.d.ts +3 -3
  108. package/dist/renderer/repeating-header-renderer.js +11 -26
  109. package/dist/renderer/row-renderer.d.ts +3 -3
  110. package/dist/renderer/row-renderer.js +12 -27
  111. package/dist/renderer/text-renderer.d.ts +6 -5
  112. package/dist/renderer/text-renderer.js +33 -42
  113. package/dist/text/line-breaker.d.ts +8 -5
  114. package/dist/text/line-breaker.js +67 -16
  115. package/dist/text/text-style.d.ts +25 -0
  116. package/dist/text/text-style.js +29 -0
  117. package/dist/utils/afm-parser.js +3 -13
  118. package/dist/utils/bytes.d.ts +24 -0
  119. package/dist/utils/bytes.js +76 -0
  120. package/dist/utils/flex-layout.d.ts +2 -2
  121. package/dist/utils/flex-layout.js +15 -20
  122. package/dist/utils/font-metrics.d.ts +1 -1
  123. package/dist/utils/font-metrics.js +1 -2
  124. package/dist/utils/font-path.js +3 -6
  125. package/dist/utils/image-helper.d.ts +6 -5
  126. package/dist/utils/image-helper.js +101 -111
  127. package/dist/utils/md5.d.ts +4 -0
  128. package/dist/utils/md5.js +80 -0
  129. package/dist/utils/pdf-object-manager.d.ts +10 -6
  130. package/dist/utils/pdf-object-manager.js +89 -94
  131. package/dist/utils/renderer-registry.js +1 -5
  132. package/dist/utils/ttf-parser.d.ts +2 -2
  133. package/dist/utils/ttf-parser.js +32 -36
  134. package/dist/utils/ttf-subsetter.d.ts +1 -1
  135. package/dist/utils/ttf-subsetter.js +40 -42
  136. package/dist/utils/utf8-to-windows1252-encoder.js +1 -4
  137. package/dist/validators/element-validator.d.ts +2 -2
  138. package/dist/validators/element-validator.js +9 -13
  139. package/package.json +14 -2
package/README.md CHANGED
@@ -137,9 +137,9 @@ verify all of it:
137
137
 
138
138
  | Package | What it is |
139
139
  | --- | --- |
140
- | **[@jasy/zugferd](https://www.npmjs.com/package/@jasy/zugferd)** | ZUGFeRD / XRechnung: your data → PDF/A-3 + EN-16931 XML, with local validation. **The prize.** |
141
- | **[@jasy/cli](https://www.npmjs.com/package/@jasy/cli)** | the `jasy` terminal: read · validate · export, headless **and** interactive |
142
- | **[@jasy/pdf](https://www.npmjs.com/package/@jasy/pdf)** | the declarative, Flutter-style PDF layout engine that powers them |
140
+ | **[@jasy/zugferd](https://npmx.dev/@jasy/zugferd)** | ZUGFeRD / XRechnung: your data → PDF/A-3 + EN-16931 XML, with local validation. **The prize.** |
141
+ | **[@jasy/cli](https://npmx.dev/@jasy/cli)** | the `jasy` terminal: read · validate · export, headless **and** interactive |
142
+ | **[@jasy/pdf](https://npmx.dev/@jasy/pdf)** | the declarative, Flutter-style PDF layout engine that powers them |
143
143
 
144
144
  ---
145
145
 
@@ -1,4 +1,4 @@
1
- import { PDFElement } from "../elements/pdf-element";
1
+ import { PDFElement } from "../elements/pdf-element.js";
2
2
  /**
3
3
  * Lets a container factory be called either `F(children)` or `F(opts, children)` - the
4
4
  * same ergonomic shape across Document/Page/Column/Row/Box. When the first argument is the
package/dist/api/args.js CHANGED
@@ -1,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.splitArgs = splitArgs;
4
1
  /**
5
2
  * Lets a container factory be called either `F(children)` or `F(opts, children)` - the
6
3
  * same ergonomic shape across Document/Page/Column/Row/Box. When the first argument is the
7
4
  * child array, options default to empty.
8
5
  */
9
- function splitArgs(a, b) {
6
+ export function splitArgs(a, b) {
10
7
  if (Array.isArray(a))
11
8
  return { opts: {}, children: a };
12
- return { opts: a, children: b !== null && b !== void 0 ? b : [] };
9
+ return { opts: a, children: b ?? [] };
13
10
  }
@@ -1,11 +1,11 @@
1
- import { Color } from "../common/color";
1
+ import { Color } from "../common/color.js";
2
2
  /**
3
- * Every way to name a colour. The FORM picks the convention, so there is never a guess
3
+ * Every way to name a color. The FORM picks the convention, so there is never a guess
4
4
  * (locked design §2):
5
5
  *
6
6
  * | form | example | meaning |
7
7
  * |---------------------------|--------------------------|--------------------------------|
8
- * | named (full CSS set) | `"steelblue"`, `"transparent"` | the ~148 CSS colour names |
8
+ * | named (full CSS set) | `"steelblue"`, `"transparent"` | the ~148 CSS color names |
9
9
  * | hex 6 / 3 | `"#1450aa"` / `"#14a"` | CSS RGB |
10
10
  * | hex 8 / 4 | `"#1450aacc"` / `"#14ac"`| CSS RGBA (alpha LAST) |
11
11
  * | number | `0xff1450aa` | Flutter ARGB (alpha FIRST) |
@@ -19,6 +19,6 @@ export declare function rgb(r: number, g: number, b: number): Color;
19
19
  export declare function rgba(r: number, g: number, b: number, a: number): Color;
20
20
  /**
21
21
  * Normalizes any `ColorInput` to an engine `Color`. The single funnel every factory uses,
22
- * so a colour means the same thing no matter how it was written.
22
+ * so a color means the same thing no matter how it was written.
23
23
  */
24
24
  export declare function toColor(input: ColorInput): Color;
package/dist/api/color.js CHANGED
@@ -1,24 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.rgb = rgb;
4
- exports.rgba = rgba;
5
- exports.toColor = toColor;
6
- const color_1 = require("../common/color");
1
+ import { Color } from "../common/color.js";
7
2
  /** Channels 0–255, fully opaque. */
8
- function rgb(r, g, b) {
9
- return new color_1.Color(r, g, b, 1);
3
+ export function rgb(r, g, b) {
4
+ return new Color(r, g, b, 1);
10
5
  }
11
6
  /** Channels 0–255, alpha 0–1. */
12
- function rgba(r, g, b, a) {
13
- return new color_1.Color(r, g, b, a);
7
+ export function rgba(r, g, b, a) {
8
+ return new Color(r, g, b, a);
14
9
  }
15
10
  /**
16
11
  * Normalizes any `ColorInput` to an engine `Color`. The single funnel every factory uses,
17
- * so a colour means the same thing no matter how it was written.
12
+ * so a color means the same thing no matter how it was written.
18
13
  */
19
- function toColor(input) {
20
- var _a;
21
- if (input instanceof color_1.Color)
14
+ export function toColor(input) {
15
+ if (input instanceof Color)
22
16
  return input;
23
17
  if (typeof input === "number")
24
18
  return fromArgbNumber(input);
@@ -27,7 +21,7 @@ function toColor(input) {
27
21
  return fromHex(s);
28
22
  const named = CSS_COLORS[s];
29
23
  if (named)
30
- return new color_1.Color(named[0], named[1], named[2], (_a = named[3]) !== null && _a !== void 0 ? _a : 1);
24
+ return new Color(named[0], named[1], named[2], named[3] ?? 1);
31
25
  throw new Error(`Unknown color: "${input}"`);
32
26
  }
33
27
  /** Flutter ARGB: 0xAARRGGBB, alpha FIRST. A 6-digit number has alpha 0x00 = transparent. */
@@ -36,7 +30,7 @@ function fromArgbNumber(n) {
36
30
  const r = (n >>> 16) & 0xff;
37
31
  const g = (n >>> 8) & 0xff;
38
32
  const b = n & 0xff;
39
- return new color_1.Color(r, g, b, a / 255);
33
+ return new Color(r, g, b, a / 255);
40
34
  }
41
35
  /** CSS hex: #RGB, #RGBA, #RRGGBB, #RRGGBBAA. Alpha is LAST. */
42
36
  function fromHex(s) {
@@ -58,7 +52,7 @@ function fromHex(s) {
58
52
  const a = full.length === 8 ? parseInt(full.slice(6, 8), 16) / 255 : 1;
59
53
  if ([r, g, b].some(Number.isNaN))
60
54
  throw new Error(`Invalid hex color: "${s}"`);
61
- return new color_1.Color(r, g, b, a);
55
+ return new Color(r, g, b, a);
62
56
  }
63
57
  // The full CSS named-color set (~148, incl. the synonyms grey/gray and `transparent`).
64
58
  // [r, g, b] or [r, g, b, alpha]. Lower-cased keys; `toColor` lower-cases the input.
@@ -1,10 +1,10 @@
1
- import { ImageElement, CustomImage } from "../elements/image-element";
2
- import { PDFElement } from "../elements/pdf-element";
3
- import { ColorInput } from "./color";
4
- import { Insets } from "./insets";
1
+ import { ImageElement, CustomImage } from "../elements/image-element.js";
2
+ import { PDFElement } from "../elements/pdf-element.js";
3
+ import { ColorInput } from "./color.js";
4
+ import { Insets } from "./insets.js";
5
5
  /** A horizontal rule (locked §4). */
6
6
  export interface DividerOptions {
7
- /** Line colour (default a light grey). */
7
+ /** Line color (default a light gray). */
8
8
  color?: ColorInput;
9
9
  /** Line thickness in points (default 1). */
10
10
  thickness?: number;
@@ -14,11 +14,11 @@ export interface DividerOptions {
14
14
  /**
15
15
  * A horizontal rule that spans the parent's width. Maps to a `LineElement` (hiding its
16
16
  * `xEnd`/`yEnd` mechanics) wrapped in a `PaddingElement` - the line has no height of its
17
- * own, so the padding gives it vertical room and centres the rule. Use inside a Column.
17
+ * own, so the padding gives it vertical room and centers the rule. Use inside a Column.
18
18
  */
19
19
  export declare function Divider(opts?: DividerOptions): PDFElement;
20
- /** An image source: a local file path, or a `CustomImage` (e.g. a browser-supplied image). */
21
- export type ImageSource = string | CustomImage;
20
+ /** An image source: a local file path (Node), raw bytes (e.g. a browser fetch/upload), or a `CustomImage`. */
21
+ export type ImageSource = string | Uint8Array | CustomImage;
22
22
  /** How the image fills its box (locked §4). Mirrors CSS `object-fit`. */
23
23
  export type ImageFit = "none" | "contain" | "cover" | "fill";
24
24
  export interface ImageOptions {
@@ -1,47 +1,46 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Divider = Divider;
4
- exports.Image = Image;
5
- const line_element_1 = require("../elements/line-element");
6
- const padding_element_1 = require("../elements/layout/padding-element");
7
- const image_element_1 = require("../elements/image-element");
8
- const color_1 = require("./color");
9
- const insets_1 = require("./insets");
1
+ import { LineElement } from "../elements/line-element.js";
2
+ import { PaddingElement } from "../elements/layout/padding-element.js";
3
+ import { ImageElement, CustomLocalImage, CustomBytesImage, BoxFit, } from "../elements/image-element.js";
4
+ import { toColor } from "./color.js";
5
+ import { toEdges } from "./insets.js";
10
6
  const DEFAULT_DIVIDER_COLOR = "lightgray";
11
7
  const DEFAULT_DIVIDER_MARGIN = { y: 6 };
12
8
  /**
13
9
  * A horizontal rule that spans the parent's width. Maps to a `LineElement` (hiding its
14
10
  * `xEnd`/`yEnd` mechanics) wrapped in a `PaddingElement` - the line has no height of its
15
- * own, so the padding gives it vertical room and centres the rule. Use inside a Column.
11
+ * own, so the padding gives it vertical room and centers the rule. Use inside a Column.
16
12
  */
17
- function Divider(opts = {}) {
18
- var _a, _b, _c;
19
- const line = new line_element_1.LineElement({
13
+ export function Divider(opts = {}) {
14
+ const line = new LineElement({
20
15
  x: 0,
21
16
  y: 0,
22
17
  xEnd: 0, // resolved to the parent's width at layout time
23
18
  yEnd: 0, // horizontal: no vertical span
24
- color: (0, color_1.toColor)((_a = opts.color) !== null && _a !== void 0 ? _a : DEFAULT_DIVIDER_COLOR),
25
- strokeWidth: (_b = opts.thickness) !== null && _b !== void 0 ? _b : 1,
19
+ color: toColor(opts.color ?? DEFAULT_DIVIDER_COLOR),
20
+ strokeWidth: opts.thickness ?? 1,
26
21
  });
27
- return new padding_element_1.PaddingElement({
28
- margin: (0, insets_1.toEdges)((_c = opts.margin) !== null && _c !== void 0 ? _c : DEFAULT_DIVIDER_MARGIN),
22
+ return new PaddingElement({
23
+ margin: toEdges(opts.margin ?? DEFAULT_DIVIDER_MARGIN),
29
24
  child: line,
30
25
  });
31
26
  }
32
27
  const FIT = {
33
- none: image_element_1.BoxFit.none,
34
- contain: image_element_1.BoxFit.contain,
35
- cover: image_element_1.BoxFit.cover,
36
- fill: image_element_1.BoxFit.fill,
28
+ none: BoxFit.none,
29
+ contain: BoxFit.contain,
30
+ cover: BoxFit.cover,
31
+ fill: BoxFit.fill,
37
32
  };
38
33
  /**
39
34
  * An image. `src` is a local file path (wrapped in a `CustomLocalImage`) or a ready
40
35
  * `CustomImage` for non-filesystem sources. Maps to an `ImageElement`.
41
36
  */
42
- function Image(src, opts = {}) {
43
- return new image_element_1.ImageElement({
44
- image: typeof src === "string" ? new image_element_1.CustomLocalImage(src) : src,
37
+ export function Image(src, opts = {}) {
38
+ return new ImageElement({
39
+ image: typeof src === "string"
40
+ ? new CustomLocalImage(src)
41
+ : src instanceof Uint8Array
42
+ ? new CustomBytesImage(src)
43
+ : src,
45
44
  width: opts.width,
46
45
  height: opts.height,
47
46
  fit: opts.fit ? FIT[opts.fit] : undefined,
@@ -1,5 +1,5 @@
1
- import { PDFElement } from "../elements/pdf-element";
2
- import { PDFDocumentElement } from "../elements/pdf-document-element";
1
+ import { PDFElement } from "../elements/pdf-element.js";
2
+ import { PDFDocumentElement } from "../elements/pdf-document-element.js";
3
3
  /**
4
4
  * The framework-agnostic contract (the firewall). A binding (Vue/React, or any tree-builder)
5
5
  * produces a tree of these plain descriptors; `build` turns each node into an engine element
@@ -1,29 +1,24 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerElement = registerElement;
4
- exports.build = build;
5
- exports.buildDocument = buildDocument;
6
- const text_1 = require("./text");
7
- const layout_1 = require("./layout");
8
- const content_1 = require("./content");
9
- const structure_1 = require("./structure");
1
+ import { Text, Paragraph, span } from "./text.js";
2
+ import { Column, Row, Box, Padding, Spacer, Expanded, Positioned } from "./layout.js";
3
+ import { Divider, Image } from "./content.js";
4
+ import { Page, Document, DefaultTextStyle } from "./structure.js";
5
+ import { Table } from "./table.js";
10
6
  // Element children (Column/Row/Box/Page/…) → built recursively. Text/Paragraph children are
11
7
  // strings or `span` descriptors and become content instead.
12
8
  function elementChildren(children) {
13
9
  return children.map(build);
14
10
  }
15
11
  function textOf(node) {
16
- var _a;
17
12
  if (typeof node === "string")
18
13
  return node;
19
- const first = (_a = node.children) === null || _a === void 0 ? void 0 : _a[0];
14
+ const first = node.children?.[0];
20
15
  return typeof first === "string" ? first : "";
21
16
  }
22
17
  function toSegment(c) {
23
18
  if (typeof c === "string")
24
- return (0, text_1.span)(c);
19
+ return span(c);
25
20
  if (c.type === "span")
26
- return (0, text_1.span)(textOf(c), c.props);
21
+ return span(textOf(c), c.props);
27
22
  throw new Error(`A Text child must be a string or a span, got "${c.type}"`);
28
23
  }
29
24
  function textContent(children) {
@@ -31,40 +26,89 @@ function textContent(children) {
31
26
  return children[0];
32
27
  return children.map(toSegment);
33
28
  }
29
+ // A `<TableCell>`'s content → a `Cell`: a lone string stays a string (the table wraps it in Text);
30
+ // otherwise its children are built (a single element, or a Column of several).
31
+ function buildCell(cell) {
32
+ if (typeof cell === "string")
33
+ return cell;
34
+ const kids = cell.children ?? [];
35
+ if (kids.length === 1 && typeof kids[0] === "string")
36
+ return kids[0];
37
+ if (kids.length === 0)
38
+ return "";
39
+ const els = kids.map(build);
40
+ return els.length === 1 ? els[0] : Column(els);
41
+ }
42
+ // A `<TableRow>`'s `<TableCell>` children → one row of `Cell`s.
43
+ function rowCells(row) {
44
+ return (row.children ?? [])
45
+ .filter((c) => typeof c !== "string" && c.type === "table-cell")
46
+ .map(buildCell);
47
+ }
48
+ // A `#header` / `#footer` slot's content → one element (a Column if it holds several; strings → Text).
49
+ function slotElement(node) {
50
+ const els = (node.children ?? []).map((c) => (typeof c === "string" ? Text(c) : build(c)));
51
+ return els.length === 1 ? els[0] : Column(els);
52
+ }
34
53
  const REGISTRY = {
35
- document: (props, children) => (0, structure_1.Document)(props, elementChildren(children)),
36
- page: (props, children) => (0, structure_1.Page)(props, elementChildren(children)),
37
- column: (props, children) => (0, layout_1.Column)(props, elementChildren(children)),
38
- row: (props, children) => (0, layout_1.Row)(props, elementChildren(children)),
39
- box: (props, children) => (0, layout_1.Box)(props, elementChildren(children)),
40
- padding: (props, children) => { var _a; return (0, layout_1.Padding)((_a = props.insets) !== null && _a !== void 0 ? _a : 0, elementChildren(children)[0]); },
41
- expanded: (props, children) => (0, layout_1.Expanded)(props, elementChildren(children)[0]),
42
- spacer: (props) => (0, layout_1.Spacer)(props === null || props === void 0 ? void 0 : props.flex),
43
- divider: (props) => (0, content_1.Divider)(props),
44
- image: (props) => (0, content_1.Image)(props.src, props),
45
- text: (props, children) => (0, text_1.Text)(textContent(children), props),
46
- paragraph: (props, children) => (0, text_1.Paragraph)(textContent(children), props),
54
+ document: (props, children) => {
55
+ const doc = Document(props, elementChildren(children));
56
+ // A binding can register fonts declaratively: `fonts: { Name: bytes | path | family }`.
57
+ if (props.fonts) {
58
+ for (const [name, src] of Object.entries(props.fonts))
59
+ doc.addFont(name, src);
60
+ }
61
+ return doc;
62
+ },
63
+ page: (props, children) => {
64
+ // `#header` / `#footer` arrive as `page-header` / `page-footer` marker children (read raw); the rest
65
+ // is the body. Both repeat on every physical page the body paginates onto.
66
+ const slot = (type) => {
67
+ const m = children.find((c) => typeof c !== "string" && c.type === type);
68
+ return m ? slotElement(m) : undefined;
69
+ };
70
+ const body = children.filter((c) => typeof c === "string" || (c.type !== "page-header" && c.type !== "page-footer"));
71
+ return Page({ ...props, header: slot("page-header"), footer: slot("page-footer") }, elementChildren(body));
72
+ },
73
+ column: (props, children) => Column(props, elementChildren(children)),
74
+ row: (props, children) => Row(props, elementChildren(children)),
75
+ box: (props, children) => Box(props, elementChildren(children)),
76
+ padding: (props, children) => Padding(props.insets ?? 0, elementChildren(children)[0]),
77
+ expanded: (props, children) => Expanded(props, elementChildren(children)[0]),
78
+ spacer: (props) => Spacer(props?.flex),
79
+ divider: (props) => Divider(props),
80
+ image: (props) => Image(props.src, props),
81
+ text: (props, children) => Text(textContent(children), props),
82
+ paragraph: (props, children) => Paragraph(textContent(children), props),
83
+ // `<Table>` reads its `<TableRow>`/`<TableCell>` structure raw; one row may be marked `header`.
84
+ table: (props, children) => {
85
+ const rows = children.filter((c) => typeof c !== "string" && c.type === "table-row");
86
+ const header = rows.find((r) => r.props?.header);
87
+ const body = rows.filter((r) => !r.props?.header);
88
+ return Table({ ...props, header: header ? rowCells(header) : undefined }, body.map(rowCells));
89
+ },
90
+ positioned: (props, children) => Positioned(props, elementChildren(children)[0]),
91
+ "default-text-style": (props, children) => DefaultTextStyle(props, elementChildren(children)),
47
92
  };
48
93
  /**
49
94
  * Registers a custom element type, so a binding (or a user-defined component) can introduce
50
95
  * its own tag that resolves to an engine element through this same seam. Overwrites an
51
96
  * existing type of the same name.
52
97
  */
53
- function registerElement(type, factory) {
98
+ export function registerElement(type, factory) {
54
99
  REGISTRY[type] = factory;
55
100
  }
56
101
  /** Turns one descriptor node (or bare string → `Text`) into an engine element. */
57
- function build(node) {
58
- var _a, _b;
102
+ export function build(node) {
59
103
  if (typeof node === "string")
60
- return (0, text_1.Text)(node);
104
+ return Text(node);
61
105
  const factory = REGISTRY[node.type];
62
106
  if (!factory)
63
107
  throw new Error(`Unknown element type: "${node.type}"`);
64
- return factory((_a = node.props) !== null && _a !== void 0 ? _a : {}, (_b = node.children) !== null && _b !== void 0 ? _b : []);
108
+ return factory(node.props ?? {}, node.children ?? []);
65
109
  }
66
110
  /** Builds a descriptor tree whose root is a `document` into the renderable root element. */
67
- function buildDocument(root) {
111
+ export function buildDocument(root) {
68
112
  if (root.type !== "document")
69
113
  throw new Error(`Expected a "document" root, got "${root.type}"`);
70
114
  return build(root);
@@ -1,8 +1,8 @@
1
- export * from "./color";
2
- export * from "./insets";
3
- export * from "./text";
4
- export * from "./layout";
5
- export * from "./content";
6
- export * from "./structure";
7
- export * from "./table";
8
- export * from "./descriptor";
1
+ export * from "./color.js";
2
+ export * from "./insets.js";
3
+ export * from "./text.js";
4
+ export * from "./layout.js";
5
+ export * from "./content.js";
6
+ export * from "./structure.js";
7
+ export * from "./table.js";
8
+ export * from "./descriptor.js";
package/dist/api/index.js CHANGED
@@ -1,27 +1,11 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
1
  // The intuitive API layer: declarative factory functions + input normalizers that compile
18
2
  // down to the core engine elements. A thin, curated surface ON TOP of the engine - the
19
3
  // core classes stay untouched and remain exported for power users.
20
- __exportStar(require("./color"), exports);
21
- __exportStar(require("./insets"), exports);
22
- __exportStar(require("./text"), exports);
23
- __exportStar(require("./layout"), exports);
24
- __exportStar(require("./content"), exports);
25
- __exportStar(require("./structure"), exports);
26
- __exportStar(require("./table"), exports);
27
- __exportStar(require("./descriptor"), exports);
4
+ export * from "./color.js";
5
+ export * from "./insets.js";
6
+ export * from "./text.js";
7
+ export * from "./layout.js";
8
+ export * from "./content.js";
9
+ export * from "./structure.js";
10
+ export * from "./table.js";
11
+ export * from "./descriptor.js";
@@ -1,9 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toEdges = toEdges;
4
1
  /** Normalizes any `Insets` to the engine's `[top, right, bottom, left]`. */
5
- function toEdges(i) {
6
- var _a, _b, _c, _d, _e, _f;
2
+ export function toEdges(i) {
7
3
  if (typeof i === "number")
8
4
  return [i, i, i, i];
9
5
  if (Array.isArray(i))
@@ -13,9 +9,9 @@ function toEdges(i) {
13
9
  // axis interpretation (an empty object is all-zero either way).
14
10
  const o = i;
15
11
  if (o.x !== undefined || o.y !== undefined) {
16
- const x = (_a = o.x) !== null && _a !== void 0 ? _a : 0;
17
- const y = (_b = o.y) !== null && _b !== void 0 ? _b : 0;
12
+ const x = o.x ?? 0;
13
+ const y = o.y ?? 0;
18
14
  return [y, x, y, x];
19
15
  }
20
- return [(_c = o.top) !== null && _c !== void 0 ? _c : 0, (_d = o.right) !== null && _d !== void 0 ? _d : 0, (_e = o.bottom) !== null && _e !== void 0 ? _e : 0, (_f = o.left) !== null && _f !== void 0 ? _f : 0];
16
+ return [o.top ?? 0, o.right ?? 0, o.bottom ?? 0, o.left ?? 0];
21
17
  }
@@ -1,13 +1,13 @@
1
- import { ContainerElement } from "../elements/container-element";
2
- import { RowElement } from "../elements/row-element";
3
- import { RectangleElement } from "../elements/rectangle-element";
4
- import { ExpandedElement } from "../elements/layout/expanded-element";
5
- import { PaddingElement } from "../elements/layout/padding-element";
6
- import { PositionedElement, PositionedInsets } from "../elements/layout/positioned-element";
7
- import { PDFElement } from "../elements/pdf-element";
8
- import { MainAlign, CrossAlign } from "../utils/flex-layout";
9
- import { ColorInput } from "./color";
10
- import { Insets } from "./insets";
1
+ import { ContainerElement } from "../elements/container-element.js";
2
+ import { RowElement } from "../elements/row-element.js";
3
+ import { RectangleElement } from "../elements/rectangle-element.js";
4
+ import { ExpandedElement } from "../elements/layout/expanded-element.js";
5
+ import { PaddingElement } from "../elements/layout/padding-element.js";
6
+ import { PositionedElement, PositionedInsets } from "../elements/layout/positioned-element.js";
7
+ import { PDFElement } from "../elements/pdf-element.js";
8
+ import { MainAlign, CrossAlign } from "../utils/flex-layout.js";
9
+ import { ColorInput } from "./color.js";
10
+ import { Insets } from "./insets.js";
11
11
  /** Options shared by the `Column` and `Row` stacks (locked §4). */
12
12
  export interface StackOptions {
13
13
  /** Space inserted between children, in points. */
@@ -26,9 +26,9 @@ export declare function Row(children: PDFElement[]): RowElement;
26
26
  export declare function Row(opts: StackOptions, children: PDFElement[]): RowElement;
27
27
  /** A bordered / filled box that wraps its children (locked §4). */
28
28
  export interface BoxOptions {
29
- /** Border (stroke) colour. A box has a border only when `border` or `borderWidth` is set. */
29
+ /** Border (stroke) color. A box has a border only when `border` or `borderWidth` is set. */
30
30
  border?: ColorInput;
31
- /** Per-side border colours - override/add to `border`. Any of these makes the box draw
31
+ /** Per-side border colors - override/add to `border`. Any of these makes the box draw
32
32
  * individual side lines (sharp corners) instead of a uniform frame - this is how you get
33
33
  * grid lines (e.g. a cell with only `borderBottom` + `borderRight`). */
34
34
  borderTop?: ColorInput;
@@ -37,7 +37,7 @@ export interface BoxOptions {
37
37
  borderLeft?: ColorInput;
38
38
  /** Border thickness in points (default 1 when a border is present). */
39
39
  borderWidth?: number;
40
- /** Background fill colour. */
40
+ /** Background fill color. */
41
41
  bg?: ColorInput;
42
42
  /** Inner padding between the border and the children. */
43
43
  padding?: Insets;
@@ -63,9 +63,11 @@ export declare function Box(opts: BoxOptions, children: PDFElement[]): Rectangle
63
63
  /** Insets a single child by `padding` (a number / `{x,y}` / `{top,…}` / 4-tuple). */
64
64
  export declare function Padding(padding: Insets, child: PDFElement): PaddingElement;
65
65
  /**
66
- * Places a child OUT OF FLOW, relative to the nearest enclosing `relative` Box. Offsets are from
67
- * the frame's edges (points); a negative `top`/`left` lets the child poke into or out of the corner
68
- * - a badge, a tab, a ribbon. `Positioned({ top, left, right, bottom }, child)`.
66
+ * Places a child OUT OF FLOW, relative to the nearest enclosing `relative` Box. Two ways, pick per
67
+ * axis: pin to EDGES - `Positioned({ top, left, right, bottom }, child)`, where a negative value
68
+ * pokes into / out of the corner (a badge, a tab, a ribbon) and pinning both sides stretches; or
69
+ * ANCHOR + nudge - `Positioned({ h: "center", v: "end", x: -10, y: -8 }, child)`, i.e. centered /
70
+ * end-aligned with a pixel offset. An edge wins over an anchor on the same axis.
69
71
  */
70
72
  export declare function Positioned(opts: PositionedInsets, child: PDFElement): PositionedElement;
71
73
  /**