@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
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/jasy-pdf/jasy/main/docs/logo.png" width="130" alt="jasy">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">jasy</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<b>ZUGFeRD & XRechnung e-invoices in pure TypeScript - generate, validate, read.</b><br>
|
|
9
|
+
A Flutter-style PDF engine underneath. The EN-16931 maths done <i>for</i> you. Zero Java, zero upload.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<code>npm i @jasy/zugferd</code> · <code>npx @jasy/cli</code> · MIT
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Don't believe us. Point it at your own invoice.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx @jasy/cli validate ./your-invoice.pdf
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<img src="https://raw.githubusercontent.com/jasy-pdf/jasy/main/docs/validate.png" width="430" alt="jasy validate: VALID">
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
That `✓` is the **same official KoSIT Schematron + veraPDF the big players run** - against the EN 16931
|
|
29
|
+
**and** the German XRechnung (BR-DE) rules, plus PDF/A-3. Your file, your terminal, in seconds. No
|
|
30
|
+
account, no upload, nothing leaves your machine.
|
|
31
|
+
|
|
32
|
+
> Java has **Mustang**. PHP has **horstoeko**. Python has **factur-x**.<br>
|
|
33
|
+
> Node had nothing. **Now it has jasy.**
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## You bring the line items. jasy does the rest.
|
|
38
|
+
|
|
39
|
+
You never compute a total, a VAT breakdown or a rounding again. You hand jasy the line items - it
|
|
40
|
+
**derives** the document totals and the EN-16931 VAT breakdown, spec-correct. That is *why* the
|
|
41
|
+
invoices validate: the amounts are correct **by construction**, so the single biggest class of
|
|
42
|
+
EN-16931 failures (the BR-CO total checks) simply cannot happen.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { renderZugferd } from "@jasy/zugferd";
|
|
46
|
+
|
|
47
|
+
const { bytes, xml } = await renderZugferd({
|
|
48
|
+
number: "RE-2026-001",
|
|
49
|
+
issueDate: "2026-06-17",
|
|
50
|
+
currency: "EUR",
|
|
51
|
+
seller: { name: "Northwind Studio GmbH", vatId: "DE123456789",
|
|
52
|
+
address: { city: "Berlin", postCode: "10115", country: "DE" } },
|
|
53
|
+
buyer: { name: "Globex Corporation Ltd",
|
|
54
|
+
address: { city: "Munich", postCode: "80331", country: "DE" } },
|
|
55
|
+
lines: [
|
|
56
|
+
{ name: "Brand identity design", quantity: 2, unit: "HUR", netUnitPrice: 100,
|
|
57
|
+
vat: { category: "S", ratePercent: 19 } },
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
// bytes -> a valid ZUGFeRD PDF/A-3 · xml -> the embedded EN-16931 XML
|
|
61
|
+
// totals, tax breakdown and rounding: computed for you.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
One object in. A conformant, human-readable PDF/A-3 **and** the EN-16931 CII/UBL XML out. ZUGFeRD and
|
|
65
|
+
XRechnung work out of the box - no config, no template wrangling.
|
|
66
|
+
|
|
67
|
+
<p align="center">
|
|
68
|
+
<img src="https://raw.githubusercontent.com/jasy-pdf/jasy/main/docs/invoice.png" width="450" alt="a generated ZUGFeRD invoice">
|
|
69
|
+
</p>
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## The whole loop, from the terminal
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
jasy read invoice.pdf # identify + show: parties, line items, totals
|
|
77
|
+
jasy validate invoice.pdf # EN 16931 + XRechnung + PDF/A (exit 1 if invalid)
|
|
78
|
+
jasy export invoice.pdf -o out.xlsx # read it back: JSON · TXT · Excel
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
<p align="center">
|
|
82
|
+
<img src="https://raw.githubusercontent.com/jasy-pdf/jasy/main/docs/read.png" width="520" alt="the jasy terminal: invoice + checks + export">
|
|
83
|
+
</p>
|
|
84
|
+
|
|
85
|
+
Reads **CII and UBL**, real third-party invoices included - not just our own output.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## A PDF engine that reads like Flutter
|
|
90
|
+
|
|
91
|
+
Underneath it all is a declarative, component-based PDF engine - written from the byte stream up, no
|
|
92
|
+
headless browser, no `pdf-lib`. You describe the document; it lays it out and paginates.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { Document, Page, Column, Text, renderToBytes } from "@jasy/pdf";
|
|
96
|
+
|
|
97
|
+
const pdf = await renderToBytes(
|
|
98
|
+
Document([
|
|
99
|
+
Page({ size: "A4", margin: 48 }, [
|
|
100
|
+
Column({ gap: 8 }, [
|
|
101
|
+
Text("Invoice RE-2026-001", { size: 24, bold: true, color: "steelblue" }),
|
|
102
|
+
Text("Thank you for your business.", { color: "gray" }),
|
|
103
|
+
]),
|
|
104
|
+
]),
|
|
105
|
+
]),
|
|
106
|
+
);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Real text layout (Adobe AFM metrics, kerning, word-wrap), flexbox-style `gap` / `justify` / `align`,
|
|
110
|
+
boxes with radius and alpha, images, custom TrueType fonts, and **real pagination** - content that
|
|
111
|
+
overflows flows onto the next page, headers and footers repeat.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Under the hood - and every bit is real
|
|
116
|
+
|
|
117
|
+
This is not a wrapper around someone else's renderer. It is built from the byte stream up, and you can
|
|
118
|
+
verify all of it:
|
|
119
|
+
|
|
120
|
+
- **Hand-rolled PDF writer.** No `pdf-lib`, no PDFKit, no Java, no headless Chrome - the byte stream is ours.
|
|
121
|
+
- **Font subsetting.** Only the glyphs you actually use are embedded, with the PDF/A subset tag - a
|
|
122
|
+
740 KB font ships as a ~76 KB subset, and the text stays copy- and searchable.
|
|
123
|
+
- **Compression.** Content streams and images are FlateDecode-compressed; the spreadsheets `jasy export`
|
|
124
|
+
writes are real `.xlsx` ZIPs we deflate with our own writer and CRC32, zero dependencies.
|
|
125
|
+
- **Real font metrics.** Text is laid out with the Adobe AFM metrics of the standard-14 fonts - kerning
|
|
126
|
+
and word-wrap are *computed*, not guessed.
|
|
127
|
+
- **PDF/A-3, matched not approximated.** The conformance graph is hand-built and **passes veraPDF**, the
|
|
128
|
+
official ISO 19005 validator.
|
|
129
|
+
- **Byte-exact round-trips.** Generate and parse are inverses: `generate → parse → regenerate` reproduces
|
|
130
|
+
the identical XML. 307 tests hold the line.
|
|
131
|
+
- **Schematron, local.** The official EN-16931 + XRechnung rules run via saxon-js (the real XSLT, in pure
|
|
132
|
+
JS) - no Java, no upload.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Packages
|
|
137
|
+
|
|
138
|
+
| Package | What it is |
|
|
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 |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Why you can trust it
|
|
147
|
+
|
|
148
|
+
- **307 tests, green.** The generator and the parser are **byte-exact inverses**:
|
|
149
|
+
`generate → parse → regenerate` reproduces the identical XML. Nothing is silently lost.
|
|
150
|
+
- **The same rules the authorities use** - the official KoSIT EN-16931 + XRechnung Schematron, and the
|
|
151
|
+
official **veraPDF** for the full ISO 19005 (PDF/A) check.
|
|
152
|
+
- **Proven on real third-party invoices**, not only our own.
|
|
153
|
+
- **100% local.** No upload, no service, no account - DSGVO-safe by construction.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Honest scope
|
|
158
|
+
|
|
159
|
+
jasy targets the documents that matter here: invoices, reports, quotes, datasheets. It is **not** a
|
|
160
|
+
LaTeX / WeasyPrint replacement - no microtypography, hyphenation or bidi, and arbitrary multi-page flow
|
|
161
|
+
of *any* content is still maturing. For e-invoices (a table, totals, a footer) it is complete - they
|
|
162
|
+
even paginate. We would rather under-promise and over-deliver in the demo above.
|
|
163
|
+
|
|
164
|
+
> **Status:** young and pre-1.0. The API can still shift between minor versions. Everything shown here
|
|
165
|
+
> works and is tested.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
<p align="center">
|
|
170
|
+
MIT · built by <a href="https://github.com/jasy-pdf">Florian Heuberger</a>
|
|
171
|
+
</p>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PDFElement } from "../elements/pdf-element";
|
|
2
|
+
/**
|
|
3
|
+
* Lets a container factory be called either `F(children)` or `F(opts, children)` - the
|
|
4
|
+
* same ergonomic shape across Document/Page/Column/Row/Box. When the first argument is the
|
|
5
|
+
* child array, options default to empty.
|
|
6
|
+
*/
|
|
7
|
+
export declare function splitArgs<O>(a: O | PDFElement[], b?: PDFElement[]): {
|
|
8
|
+
opts: O;
|
|
9
|
+
children: PDFElement[];
|
|
10
|
+
};
|
package/dist/api/args.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.splitArgs = splitArgs;
|
|
4
|
+
/**
|
|
5
|
+
* Lets a container factory be called either `F(children)` or `F(opts, children)` - the
|
|
6
|
+
* same ergonomic shape across Document/Page/Column/Row/Box. When the first argument is the
|
|
7
|
+
* child array, options default to empty.
|
|
8
|
+
*/
|
|
9
|
+
function splitArgs(a, b) {
|
|
10
|
+
if (Array.isArray(a))
|
|
11
|
+
return { opts: {}, children: a };
|
|
12
|
+
return { opts: a, children: b !== null && b !== void 0 ? b : [] };
|
|
13
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Color } from "../common/color";
|
|
2
|
+
/**
|
|
3
|
+
* Every way to name a colour. The FORM picks the convention, so there is never a guess
|
|
4
|
+
* (locked design §2):
|
|
5
|
+
*
|
|
6
|
+
* | form | example | meaning |
|
|
7
|
+
* |---------------------------|--------------------------|--------------------------------|
|
|
8
|
+
* | named (full CSS set) | `"steelblue"`, `"transparent"` | the ~148 CSS colour names |
|
|
9
|
+
* | hex 6 / 3 | `"#1450aa"` / `"#14a"` | CSS RGB |
|
|
10
|
+
* | hex 8 / 4 | `"#1450aacc"` / `"#14ac"`| CSS RGBA (alpha LAST) |
|
|
11
|
+
* | number | `0xff1450aa` | Flutter ARGB (alpha FIRST) |
|
|
12
|
+
* | `rgb()` / `rgba()` | `rgb(20,90,170)` | channels 0–255 (`rgba` a=0–1) |
|
|
13
|
+
* | `Color` instance | `new Color(20,90,170)` | the engine layer, still valid |
|
|
14
|
+
*/
|
|
15
|
+
export type ColorInput = string | number | Color;
|
|
16
|
+
/** Channels 0–255, fully opaque. */
|
|
17
|
+
export declare function rgb(r: number, g: number, b: number): Color;
|
|
18
|
+
/** Channels 0–255, alpha 0–1. */
|
|
19
|
+
export declare function rgba(r: number, g: number, b: number, a: number): Color;
|
|
20
|
+
/**
|
|
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.
|
|
23
|
+
*/
|
|
24
|
+
export declare function toColor(input: ColorInput): Color;
|
|
@@ -0,0 +1,215 @@
|
|
|
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");
|
|
7
|
+
/** Channels 0–255, fully opaque. */
|
|
8
|
+
function rgb(r, g, b) {
|
|
9
|
+
return new color_1.Color(r, g, b, 1);
|
|
10
|
+
}
|
|
11
|
+
/** Channels 0–255, alpha 0–1. */
|
|
12
|
+
function rgba(r, g, b, a) {
|
|
13
|
+
return new color_1.Color(r, g, b, a);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 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.
|
|
18
|
+
*/
|
|
19
|
+
function toColor(input) {
|
|
20
|
+
var _a;
|
|
21
|
+
if (input instanceof color_1.Color)
|
|
22
|
+
return input;
|
|
23
|
+
if (typeof input === "number")
|
|
24
|
+
return fromArgbNumber(input);
|
|
25
|
+
const s = input.trim().toLowerCase();
|
|
26
|
+
if (s.startsWith("#"))
|
|
27
|
+
return fromHex(s);
|
|
28
|
+
const named = CSS_COLORS[s];
|
|
29
|
+
if (named)
|
|
30
|
+
return new color_1.Color(named[0], named[1], named[2], (_a = named[3]) !== null && _a !== void 0 ? _a : 1);
|
|
31
|
+
throw new Error(`Unknown color: "${input}"`);
|
|
32
|
+
}
|
|
33
|
+
/** Flutter ARGB: 0xAARRGGBB, alpha FIRST. A 6-digit number has alpha 0x00 = transparent. */
|
|
34
|
+
function fromArgbNumber(n) {
|
|
35
|
+
const a = (n >>> 24) & 0xff;
|
|
36
|
+
const r = (n >>> 16) & 0xff;
|
|
37
|
+
const g = (n >>> 8) & 0xff;
|
|
38
|
+
const b = n & 0xff;
|
|
39
|
+
return new color_1.Color(r, g, b, a / 255);
|
|
40
|
+
}
|
|
41
|
+
/** CSS hex: #RGB, #RGBA, #RRGGBB, #RRGGBBAA. Alpha is LAST. */
|
|
42
|
+
function fromHex(s) {
|
|
43
|
+
const hex = s.slice(1);
|
|
44
|
+
const expand = (h) => h
|
|
45
|
+
.split("")
|
|
46
|
+
.map((c) => c + c)
|
|
47
|
+
.join("");
|
|
48
|
+
let full;
|
|
49
|
+
if (hex.length === 3 || hex.length === 4)
|
|
50
|
+
full = expand(hex);
|
|
51
|
+
else if (hex.length === 6 || hex.length === 8)
|
|
52
|
+
full = hex;
|
|
53
|
+
else
|
|
54
|
+
throw new Error(`Invalid hex color: "${s}"`);
|
|
55
|
+
const r = parseInt(full.slice(0, 2), 16);
|
|
56
|
+
const g = parseInt(full.slice(2, 4), 16);
|
|
57
|
+
const b = parseInt(full.slice(4, 6), 16);
|
|
58
|
+
const a = full.length === 8 ? parseInt(full.slice(6, 8), 16) / 255 : 1;
|
|
59
|
+
if ([r, g, b].some(Number.isNaN))
|
|
60
|
+
throw new Error(`Invalid hex color: "${s}"`);
|
|
61
|
+
return new color_1.Color(r, g, b, a);
|
|
62
|
+
}
|
|
63
|
+
// The full CSS named-color set (~148, incl. the synonyms grey/gray and `transparent`).
|
|
64
|
+
// [r, g, b] or [r, g, b, alpha]. Lower-cased keys; `toColor` lower-cases the input.
|
|
65
|
+
const CSS_COLORS = {
|
|
66
|
+
transparent: [0, 0, 0, 0],
|
|
67
|
+
aliceblue: [240, 248, 255],
|
|
68
|
+
antiquewhite: [250, 235, 215],
|
|
69
|
+
aqua: [0, 255, 255],
|
|
70
|
+
aquamarine: [127, 255, 212],
|
|
71
|
+
azure: [240, 255, 255],
|
|
72
|
+
beige: [245, 245, 220],
|
|
73
|
+
bisque: [255, 228, 196],
|
|
74
|
+
black: [0, 0, 0],
|
|
75
|
+
blanchedalmond: [255, 235, 205],
|
|
76
|
+
blue: [0, 0, 255],
|
|
77
|
+
blueviolet: [138, 43, 226],
|
|
78
|
+
brown: [165, 42, 42],
|
|
79
|
+
burlywood: [222, 184, 135],
|
|
80
|
+
cadetblue: [95, 158, 160],
|
|
81
|
+
chartreuse: [127, 255, 0],
|
|
82
|
+
chocolate: [210, 105, 30],
|
|
83
|
+
coral: [255, 127, 80],
|
|
84
|
+
cornflowerblue: [100, 149, 237],
|
|
85
|
+
cornsilk: [255, 248, 220],
|
|
86
|
+
crimson: [220, 20, 60],
|
|
87
|
+
cyan: [0, 255, 255],
|
|
88
|
+
darkblue: [0, 0, 139],
|
|
89
|
+
darkcyan: [0, 139, 139],
|
|
90
|
+
darkgoldenrod: [184, 134, 11],
|
|
91
|
+
darkgray: [169, 169, 169],
|
|
92
|
+
darkgrey: [169, 169, 169],
|
|
93
|
+
darkgreen: [0, 100, 0],
|
|
94
|
+
darkkhaki: [189, 183, 107],
|
|
95
|
+
darkmagenta: [139, 0, 139],
|
|
96
|
+
darkolivegreen: [85, 107, 47],
|
|
97
|
+
darkorange: [255, 140, 0],
|
|
98
|
+
darkorchid: [153, 50, 204],
|
|
99
|
+
darkred: [139, 0, 0],
|
|
100
|
+
darksalmon: [233, 150, 122],
|
|
101
|
+
darkseagreen: [143, 188, 143],
|
|
102
|
+
darkslateblue: [72, 61, 139],
|
|
103
|
+
darkslategray: [47, 79, 79],
|
|
104
|
+
darkslategrey: [47, 79, 79],
|
|
105
|
+
darkturquoise: [0, 206, 209],
|
|
106
|
+
darkviolet: [148, 0, 211],
|
|
107
|
+
deeppink: [255, 20, 147],
|
|
108
|
+
deepskyblue: [0, 191, 255],
|
|
109
|
+
dimgray: [105, 105, 105],
|
|
110
|
+
dimgrey: [105, 105, 105],
|
|
111
|
+
dodgerblue: [30, 144, 255],
|
|
112
|
+
firebrick: [178, 34, 34],
|
|
113
|
+
floralwhite: [255, 250, 240],
|
|
114
|
+
forestgreen: [34, 139, 34],
|
|
115
|
+
fuchsia: [255, 0, 255],
|
|
116
|
+
gainsboro: [220, 220, 220],
|
|
117
|
+
ghostwhite: [248, 248, 255],
|
|
118
|
+
gold: [255, 215, 0],
|
|
119
|
+
goldenrod: [218, 165, 32],
|
|
120
|
+
gray: [128, 128, 128],
|
|
121
|
+
grey: [128, 128, 128],
|
|
122
|
+
green: [0, 128, 0],
|
|
123
|
+
greenyellow: [173, 255, 47],
|
|
124
|
+
honeydew: [240, 255, 240],
|
|
125
|
+
hotpink: [255, 105, 180],
|
|
126
|
+
indianred: [205, 92, 92],
|
|
127
|
+
indigo: [75, 0, 130],
|
|
128
|
+
ivory: [255, 255, 240],
|
|
129
|
+
khaki: [240, 230, 140],
|
|
130
|
+
lavender: [230, 230, 250],
|
|
131
|
+
lavenderblush: [255, 240, 245],
|
|
132
|
+
lawngreen: [124, 252, 0],
|
|
133
|
+
lemonchiffon: [255, 250, 205],
|
|
134
|
+
lightblue: [173, 216, 230],
|
|
135
|
+
lightcoral: [240, 128, 128],
|
|
136
|
+
lightcyan: [224, 255, 255],
|
|
137
|
+
lightgoldenrodyellow: [250, 250, 210],
|
|
138
|
+
lightgray: [211, 211, 211],
|
|
139
|
+
lightgrey: [211, 211, 211],
|
|
140
|
+
lightgreen: [144, 238, 144],
|
|
141
|
+
lightpink: [255, 182, 193],
|
|
142
|
+
lightsalmon: [255, 160, 122],
|
|
143
|
+
lightseagreen: [32, 178, 170],
|
|
144
|
+
lightskyblue: [135, 206, 250],
|
|
145
|
+
lightslategray: [119, 136, 153],
|
|
146
|
+
lightslategrey: [119, 136, 153],
|
|
147
|
+
lightsteelblue: [176, 196, 222],
|
|
148
|
+
lightyellow: [255, 255, 224],
|
|
149
|
+
lime: [0, 255, 0],
|
|
150
|
+
limegreen: [50, 205, 50],
|
|
151
|
+
linen: [250, 240, 230],
|
|
152
|
+
magenta: [255, 0, 255],
|
|
153
|
+
maroon: [128, 0, 0],
|
|
154
|
+
mediumaquamarine: [102, 205, 170],
|
|
155
|
+
mediumblue: [0, 0, 205],
|
|
156
|
+
mediumorchid: [186, 85, 211],
|
|
157
|
+
mediumpurple: [147, 112, 219],
|
|
158
|
+
mediumseagreen: [60, 179, 113],
|
|
159
|
+
mediumslateblue: [123, 104, 238],
|
|
160
|
+
mediumspringgreen: [0, 250, 154],
|
|
161
|
+
mediumturquoise: [72, 209, 204],
|
|
162
|
+
mediumvioletred: [199, 21, 133],
|
|
163
|
+
midnightblue: [25, 25, 112],
|
|
164
|
+
mintcream: [245, 255, 250],
|
|
165
|
+
mistyrose: [255, 228, 225],
|
|
166
|
+
moccasin: [255, 228, 181],
|
|
167
|
+
navajowhite: [255, 222, 173],
|
|
168
|
+
navy: [0, 0, 128],
|
|
169
|
+
oldlace: [253, 245, 230],
|
|
170
|
+
olive: [128, 128, 0],
|
|
171
|
+
olivedrab: [107, 142, 35],
|
|
172
|
+
orange: [255, 165, 0],
|
|
173
|
+
orangered: [255, 69, 0],
|
|
174
|
+
orchid: [218, 112, 214],
|
|
175
|
+
palegoldenrod: [238, 232, 170],
|
|
176
|
+
palegreen: [152, 251, 152],
|
|
177
|
+
paleturquoise: [175, 238, 238],
|
|
178
|
+
palevioletred: [219, 112, 147],
|
|
179
|
+
papayawhip: [255, 239, 213],
|
|
180
|
+
peachpuff: [255, 218, 185],
|
|
181
|
+
peru: [205, 133, 63],
|
|
182
|
+
pink: [255, 192, 203],
|
|
183
|
+
plum: [221, 160, 221],
|
|
184
|
+
powderblue: [176, 224, 230],
|
|
185
|
+
purple: [128, 0, 128],
|
|
186
|
+
rebeccapurple: [102, 51, 153],
|
|
187
|
+
red: [255, 0, 0],
|
|
188
|
+
rosybrown: [188, 143, 143],
|
|
189
|
+
royalblue: [65, 105, 225],
|
|
190
|
+
saddlebrown: [139, 69, 19],
|
|
191
|
+
salmon: [250, 128, 114],
|
|
192
|
+
sandybrown: [244, 164, 96],
|
|
193
|
+
seagreen: [46, 139, 87],
|
|
194
|
+
seashell: [255, 245, 238],
|
|
195
|
+
sienna: [160, 82, 45],
|
|
196
|
+
silver: [192, 192, 192],
|
|
197
|
+
skyblue: [135, 206, 235],
|
|
198
|
+
slateblue: [106, 90, 205],
|
|
199
|
+
slategray: [112, 128, 144],
|
|
200
|
+
slategrey: [112, 128, 144],
|
|
201
|
+
snow: [255, 250, 250],
|
|
202
|
+
springgreen: [0, 255, 127],
|
|
203
|
+
steelblue: [70, 130, 180],
|
|
204
|
+
tan: [210, 180, 140],
|
|
205
|
+
teal: [0, 128, 128],
|
|
206
|
+
thistle: [216, 191, 216],
|
|
207
|
+
tomato: [255, 99, 71],
|
|
208
|
+
turquoise: [64, 224, 208],
|
|
209
|
+
violet: [238, 130, 238],
|
|
210
|
+
wheat: [245, 222, 179],
|
|
211
|
+
white: [255, 255, 255],
|
|
212
|
+
whitesmoke: [245, 245, 245],
|
|
213
|
+
yellow: [255, 255, 0],
|
|
214
|
+
yellowgreen: [154, 205, 50],
|
|
215
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
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";
|
|
5
|
+
/** A horizontal rule (locked §4). */
|
|
6
|
+
export interface DividerOptions {
|
|
7
|
+
/** Line colour (default a light grey). */
|
|
8
|
+
color?: ColorInput;
|
|
9
|
+
/** Line thickness in points (default 1). */
|
|
10
|
+
thickness?: number;
|
|
11
|
+
/** Space above/below the rule (default a small vertical gap). */
|
|
12
|
+
margin?: Insets;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A horizontal rule that spans the parent's width. Maps to a `LineElement` (hiding its
|
|
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.
|
|
18
|
+
*/
|
|
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;
|
|
22
|
+
/** How the image fills its box (locked §4). Mirrors CSS `object-fit`. */
|
|
23
|
+
export type ImageFit = "none" | "contain" | "cover" | "fill";
|
|
24
|
+
export interface ImageOptions {
|
|
25
|
+
width?: number;
|
|
26
|
+
height?: number;
|
|
27
|
+
/** Fit within the box (default `none`). */
|
|
28
|
+
fit?: ImageFit;
|
|
29
|
+
/** Corner radius in points (rounds the image box). */
|
|
30
|
+
radius?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* An image. `src` is a local file path (wrapped in a `CustomLocalImage`) or a ready
|
|
34
|
+
* `CustomImage` for non-filesystem sources. Maps to an `ImageElement`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function Image(src: ImageSource, opts?: ImageOptions): ImageElement;
|
|
@@ -0,0 +1,50 @@
|
|
|
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");
|
|
10
|
+
const DEFAULT_DIVIDER_COLOR = "lightgray";
|
|
11
|
+
const DEFAULT_DIVIDER_MARGIN = { y: 6 };
|
|
12
|
+
/**
|
|
13
|
+
* A horizontal rule that spans the parent's width. Maps to a `LineElement` (hiding its
|
|
14
|
+
* `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.
|
|
16
|
+
*/
|
|
17
|
+
function Divider(opts = {}) {
|
|
18
|
+
var _a, _b, _c;
|
|
19
|
+
const line = new line_element_1.LineElement({
|
|
20
|
+
x: 0,
|
|
21
|
+
y: 0,
|
|
22
|
+
xEnd: 0, // resolved to the parent's width at layout time
|
|
23
|
+
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,
|
|
26
|
+
});
|
|
27
|
+
return new padding_element_1.PaddingElement({
|
|
28
|
+
margin: (0, insets_1.toEdges)((_c = opts.margin) !== null && _c !== void 0 ? _c : DEFAULT_DIVIDER_MARGIN),
|
|
29
|
+
child: line,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
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,
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* An image. `src` is a local file path (wrapped in a `CustomLocalImage`) or a ready
|
|
40
|
+
* `CustomImage` for non-filesystem sources. Maps to an `ImageElement`.
|
|
41
|
+
*/
|
|
42
|
+
function Image(src, opts = {}) {
|
|
43
|
+
return new image_element_1.ImageElement({
|
|
44
|
+
image: typeof src === "string" ? new image_element_1.CustomLocalImage(src) : src,
|
|
45
|
+
width: opts.width,
|
|
46
|
+
height: opts.height,
|
|
47
|
+
fit: opts.fit ? FIT[opts.fit] : undefined,
|
|
48
|
+
radius: opts.radius,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PDFElement } from "../elements/pdf-element";
|
|
2
|
+
import { PDFDocumentElement } from "../elements/pdf-document-element";
|
|
3
|
+
/**
|
|
4
|
+
* The framework-agnostic contract (the firewall). A binding (Vue/React, or any tree-builder)
|
|
5
|
+
* produces a tree of these plain descriptors; `build` turns each node into an engine element
|
|
6
|
+
* through the SAME factories the programmatic API uses - one mapping, shared by every binding.
|
|
7
|
+
*/
|
|
8
|
+
export interface Descriptor {
|
|
9
|
+
type: string;
|
|
10
|
+
props?: Record<string, any>;
|
|
11
|
+
children?: DescriptorChild[];
|
|
12
|
+
}
|
|
13
|
+
export type DescriptorChild = Descriptor | string;
|
|
14
|
+
/** A registry entry: turn a node's props + raw children into an engine element. */
|
|
15
|
+
export type ElementFactory = (props: any, children: DescriptorChild[]) => PDFElement;
|
|
16
|
+
/**
|
|
17
|
+
* Registers a custom element type, so a binding (or a user-defined component) can introduce
|
|
18
|
+
* its own tag that resolves to an engine element through this same seam. Overwrites an
|
|
19
|
+
* existing type of the same name.
|
|
20
|
+
*/
|
|
21
|
+
export declare function registerElement(type: string, factory: ElementFactory): void;
|
|
22
|
+
/** Turns one descriptor node (or bare string → `Text`) into an engine element. */
|
|
23
|
+
export declare function build(node: DescriptorChild): PDFElement;
|
|
24
|
+
/** Builds a descriptor tree whose root is a `document` into the renderable root element. */
|
|
25
|
+
export declare function buildDocument(root: Descriptor): PDFDocumentElement;
|
|
@@ -0,0 +1,71 @@
|
|
|
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");
|
|
10
|
+
// Element children (Column/Row/Box/Page/…) → built recursively. Text/Paragraph children are
|
|
11
|
+
// strings or `span` descriptors and become content instead.
|
|
12
|
+
function elementChildren(children) {
|
|
13
|
+
return children.map(build);
|
|
14
|
+
}
|
|
15
|
+
function textOf(node) {
|
|
16
|
+
var _a;
|
|
17
|
+
if (typeof node === "string")
|
|
18
|
+
return node;
|
|
19
|
+
const first = (_a = node.children) === null || _a === void 0 ? void 0 : _a[0];
|
|
20
|
+
return typeof first === "string" ? first : "";
|
|
21
|
+
}
|
|
22
|
+
function toSegment(c) {
|
|
23
|
+
if (typeof c === "string")
|
|
24
|
+
return (0, text_1.span)(c);
|
|
25
|
+
if (c.type === "span")
|
|
26
|
+
return (0, text_1.span)(textOf(c), c.props);
|
|
27
|
+
throw new Error(`A Text child must be a string or a span, got "${c.type}"`);
|
|
28
|
+
}
|
|
29
|
+
function textContent(children) {
|
|
30
|
+
if (children.length === 1 && typeof children[0] === "string")
|
|
31
|
+
return children[0];
|
|
32
|
+
return children.map(toSegment);
|
|
33
|
+
}
|
|
34
|
+
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),
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Registers a custom element type, so a binding (or a user-defined component) can introduce
|
|
50
|
+
* its own tag that resolves to an engine element through this same seam. Overwrites an
|
|
51
|
+
* existing type of the same name.
|
|
52
|
+
*/
|
|
53
|
+
function registerElement(type, factory) {
|
|
54
|
+
REGISTRY[type] = factory;
|
|
55
|
+
}
|
|
56
|
+
/** Turns one descriptor node (or bare string → `Text`) into an engine element. */
|
|
57
|
+
function build(node) {
|
|
58
|
+
var _a, _b;
|
|
59
|
+
if (typeof node === "string")
|
|
60
|
+
return (0, text_1.Text)(node);
|
|
61
|
+
const factory = REGISTRY[node.type];
|
|
62
|
+
if (!factory)
|
|
63
|
+
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 : []);
|
|
65
|
+
}
|
|
66
|
+
/** Builds a descriptor tree whose root is a `document` into the renderable root element. */
|
|
67
|
+
function buildDocument(root) {
|
|
68
|
+
if (root.type !== "document")
|
|
69
|
+
throw new Error(`Expected a "document" root, got "${root.type}"`);
|
|
70
|
+
return build(root);
|
|
71
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
// The intuitive API layer: declarative factory functions + input normalizers that compile
|
|
18
|
+
// down to the core engine elements. A thin, curated surface ON TOP of the engine - the
|
|
19
|
+
// 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);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spacing input for padding / margin (locked design §3). Units are PDF points. Every form
|
|
3
|
+
* normalizes to the engine's `[top, right, bottom, left]` via `toEdges`, so you can reach
|
|
4
|
+
* for whichever shape fits and never think about the engine order.
|
|
5
|
+
*/
|
|
6
|
+
export type Insets = number | {
|
|
7
|
+
x?: number;
|
|
8
|
+
y?: number;
|
|
9
|
+
} | {
|
|
10
|
+
top?: number;
|
|
11
|
+
right?: number;
|
|
12
|
+
bottom?: number;
|
|
13
|
+
left?: number;
|
|
14
|
+
} | [number, number, number, number];
|
|
15
|
+
/** Normalizes any `Insets` to the engine's `[top, right, bottom, left]`. */
|
|
16
|
+
export declare function toEdges(i: Insets): [number, number, number, number];
|