@jasy/pdf 1.0.0-beta.3 → 1.0.0-beta.5
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/dist/api/color.d.ts +1 -24
- package/dist/api/color.js +2 -278
- package/dist/api/content.d.ts +10 -5
- package/dist/api/content.js +29 -13
- package/dist/api/descriptor.js +30 -3
- package/dist/api/flow.d.ts +55 -0
- package/dist/api/flow.js +71 -0
- package/dist/api/font-url.d.ts +1 -2
- package/dist/api/font-url.js +8 -74
- package/dist/api/forms.d.ts +3 -0
- package/dist/api/forms.js +3 -0
- package/dist/api/gradient.d.ts +1 -53
- package/dist/api/gradient.js +2 -97
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.js +3 -0
- package/dist/api/layout.d.ts +6 -0
- package/dist/api/layout.js +9 -3
- package/dist/api/page-builder.d.ts +4 -0
- package/dist/api/page-builder.js +4 -0
- package/dist/api/structure.d.ts +10 -2
- package/dist/api/structure.js +9 -6
- package/dist/api/table.d.ts +5 -3
- package/dist/api/table.js +101 -22
- package/dist/api/text.d.ts +8 -8
- package/dist/api/text.js +6 -0
- package/dist/canvas/painter.d.ts +2 -2
- package/dist/canvas/painter.js +2 -2
- package/dist/common/color-input.d.ts +24 -0
- package/dist/common/color-input.js +278 -0
- package/dist/common/diagnostics.d.ts +61 -0
- package/dist/common/diagnostics.js +77 -0
- package/dist/common/gradient.d.ts +53 -0
- package/dist/common/gradient.js +97 -0
- package/dist/edit/acroform-reader.js +7 -7
- package/dist/edit/appearance.js +3 -3
- package/dist/edit/attachments.d.ts +52 -0
- package/dist/edit/attachments.js +178 -0
- package/dist/edit/document.d.ts +38 -8
- package/dist/edit/document.js +208 -51
- package/dist/edit/fill.js +8 -23
- package/dist/edit/filters.d.ts +15 -0
- package/dist/edit/filters.js +157 -0
- package/dist/edit/index.d.ts +4 -1
- package/dist/edit/index.js +3 -1
- package/dist/edit/objects.d.ts +3 -4
- package/dist/edit/objects.js +5 -18
- package/dist/elements/canvas-element.d.ts +3 -0
- package/dist/elements/canvas-element.js +14 -3
- package/dist/elements/container-element.d.ts +8 -1
- package/dist/elements/container-element.js +49 -17
- package/dist/elements/forms/checkbox-element.d.ts +2 -0
- package/dist/elements/forms/checkbox-element.js +12 -3
- package/dist/elements/forms/choice-element.d.ts +6 -1
- package/dist/elements/forms/choice-element.js +17 -6
- package/dist/elements/forms/field-font.d.ts +8 -0
- package/dist/elements/forms/field-font.js +5 -0
- package/dist/elements/forms/push-button-element.d.ts +6 -1
- package/dist/elements/forms/push-button-element.js +16 -4
- package/dist/elements/forms/radio-element.d.ts +2 -0
- package/dist/elements/forms/radio-element.js +12 -3
- package/dist/elements/forms/signature-element.d.ts +6 -1
- package/dist/elements/forms/signature-element.js +16 -4
- package/dist/elements/forms/text-field-element.d.ts +6 -1
- package/dist/elements/forms/text-field-element.js +16 -4
- package/dist/elements/image-element.d.ts +70 -21
- package/dist/elements/image-element.js +173 -52
- package/dist/elements/index.d.ts +3 -0
- package/dist/elements/index.js +3 -0
- package/dist/elements/layout/anchor-element.d.ts +8 -10
- package/dist/elements/layout/anchor-element.js +10 -18
- package/dist/elements/layout/bookmark-element.d.ts +9 -11
- package/dist/elements/layout/bookmark-element.js +11 -20
- package/dist/elements/layout/column-break-element.d.ts +17 -0
- package/dist/elements/layout/column-break-element.js +26 -0
- package/dist/elements/layout/default-text-style-element.d.ts +11 -13
- package/dist/elements/layout/default-text-style-element.js +14 -31
- package/dist/elements/layout/deferred-element.d.ts +20 -4
- package/dist/elements/layout/deferred-element.js +41 -9
- package/dist/elements/layout/expanded-element.d.ts +11 -0
- package/dist/elements/layout/expanded-element.js +53 -18
- package/dist/elements/layout/flow-element.d.ts +109 -0
- package/dist/elements/layout/flow-element.js +317 -0
- package/dist/elements/layout/keep-together-element.d.ts +8 -18
- package/dist/elements/layout/keep-together-element.js +33 -45
- package/dist/elements/layout/link-element.d.ts +8 -13
- package/dist/elements/layout/link-element.js +9 -19
- package/dist/elements/layout/padding-element.d.ts +18 -1
- package/dist/elements/layout/padding-element.js +63 -28
- package/dist/elements/layout/page-break-element.d.ts +4 -1
- package/dist/elements/layout/page-break-element.js +6 -1
- package/dist/elements/layout/page-builder-element.d.ts +5 -0
- package/dist/elements/layout/page-builder-element.js +13 -2
- package/dist/elements/layout/positioned-element.d.ts +23 -4
- package/dist/elements/layout/positioned-element.js +42 -12
- package/dist/elements/layout/proxy-element.d.ts +47 -0
- package/dist/elements/layout/proxy-element.js +106 -0
- package/dist/elements/layout/region-element.d.ts +53 -0
- package/dist/elements/layout/region-element.js +108 -0
- package/dist/elements/layout/repeating-header-element.d.ts +9 -0
- package/dist/elements/layout/repeating-header-element.js +55 -13
- package/dist/elements/layout/rotated-box-element.d.ts +6 -0
- package/dist/elements/layout/rotated-box-element.js +27 -14
- package/dist/elements/layout/rotated-element.d.ts +9 -0
- package/dist/elements/layout/rotated-element.js +33 -2
- package/dist/elements/layout/struct-group.d.ts +9 -17
- package/dist/elements/layout/struct-group.js +10 -35
- package/dist/elements/line-element.d.ts +1 -0
- package/dist/elements/line-element.js +6 -0
- package/dist/elements/page-element.d.ts +10 -3
- package/dist/elements/page-element.js +39 -31
- package/dist/elements/pdf-document-element.d.ts +3 -0
- package/dist/elements/pdf-document-element.js +7 -0
- package/dist/elements/pdf-element.d.ts +105 -16
- package/dist/elements/pdf-element.js +118 -19
- package/dist/elements/rectangle-element.d.ts +22 -2
- package/dist/elements/rectangle-element.js +119 -55
- package/dist/elements/row-element.d.ts +17 -12
- package/dist/elements/row-element.js +89 -9
- package/dist/elements/svg-element.d.ts +30 -6
- package/dist/elements/svg-element.js +91 -26
- package/dist/elements/text-element.d.ts +48 -13
- package/dist/elements/text-element.js +161 -116
- package/dist/forms/acroform.d.ts +9 -1
- package/dist/forms/acroform.js +83 -34
- package/dist/forms/appearance.d.ts +17 -6
- package/dist/forms/appearance.js +18 -16
- package/dist/ir/display-list.d.ts +18 -3
- package/dist/layout/box-constraints.d.ts +17 -0
- package/dist/layout/box-constraints.js +31 -0
- package/dist/layout/collect-images.d.ts +6 -4
- package/dist/layout/collect-images.js +14 -8
- package/dist/layout/flex-item.d.ts +11 -0
- package/dist/layout/flex-item.js +51 -0
- package/dist/layout/fragmentation.d.ts +23 -9
- package/dist/layout/fragmentation.js +62 -19
- package/dist/layout/layout-cache.d.ts +53 -0
- package/dist/layout/layout-cache.js +110 -0
- package/dist/platform/browser-fs.d.ts +1 -2
- package/dist/platform/browser-fs.js +3 -6
- package/dist/platform/node-fs.d.ts +0 -1
- package/dist/platform/node-fs.js +0 -4
- package/dist/renderer/anchor-renderer.d.ts +2 -1
- package/dist/renderer/anchor-renderer.js +5 -4
- package/dist/renderer/bookmark-renderer.d.ts +2 -1
- package/dist/renderer/bookmark-renderer.js +5 -4
- package/dist/renderer/canvas-renderer.d.ts +2 -1
- package/dist/renderer/canvas-renderer.js +5 -2
- package/dist/renderer/column-break-renderer.d.ts +8 -0
- package/dist/renderer/column-break-renderer.js +15 -0
- package/dist/renderer/container-renderer.d.ts +2 -1
- package/dist/renderer/container-renderer.js +6 -5
- package/dist/renderer/default-text-style-renderer.d.ts +2 -1
- package/dist/renderer/default-text-style-renderer.js +2 -3
- package/dist/renderer/deferred-renderer.d.ts +2 -1
- package/dist/renderer/deferred-renderer.js +2 -3
- package/dist/renderer/emoji-image.js +3 -1
- package/dist/renderer/expanded-renderer.d.ts +2 -1
- package/dist/renderer/expanded-renderer.js +2 -3
- package/dist/renderer/flow-renderer.d.ts +16 -0
- package/dist/renderer/flow-renderer.js +21 -0
- package/dist/renderer/form-field-renderer.d.ts +2 -1
- package/dist/renderer/form-field-renderer.js +16 -3
- package/dist/renderer/image-renderer.d.ts +2 -1
- package/dist/renderer/image-renderer.js +33 -53
- package/dist/renderer/index.d.ts +2 -0
- package/dist/renderer/index.js +2 -0
- package/dist/renderer/keep-together-renderer.d.ts +2 -1
- package/dist/renderer/keep-together-renderer.js +2 -3
- package/dist/renderer/line-renderer.d.ts +2 -1
- package/dist/renderer/line-renderer.js +7 -2
- package/dist/renderer/link-renderer.d.ts +2 -1
- package/dist/renderer/link-renderer.js +36 -5
- package/dist/renderer/padding-renderer.d.ts +2 -1
- package/dist/renderer/padding-renderer.js +5 -5
- package/dist/renderer/page-break-renderer.d.ts +6 -5
- package/dist/renderer/page-break-renderer.js +14 -7
- package/dist/renderer/page-builder-renderer.d.ts +2 -1
- package/dist/renderer/page-builder-renderer.js +2 -3
- package/dist/renderer/page-renderer.js +30 -10
- package/dist/renderer/pdf-backend.d.ts +4 -3
- package/dist/renderer/pdf-backend.js +14 -7
- package/dist/renderer/pdf-document-renderer.d.ts +1 -8
- package/dist/renderer/pdf-document-renderer.js +17 -17
- package/dist/renderer/pdf-renderer.js +20 -11
- package/dist/renderer/positioned-renderer.d.ts +18 -1
- package/dist/renderer/positioned-renderer.js +43 -6
- package/dist/renderer/rectangle-renderer.d.ts +2 -1
- package/dist/renderer/rectangle-renderer.js +18 -8
- package/dist/renderer/repeating-header-renderer.d.ts +2 -1
- package/dist/renderer/repeating-header-renderer.js +6 -5
- package/dist/renderer/rotated-renderer.d.ts +2 -1
- package/dist/renderer/rotated-renderer.js +9 -5
- package/dist/renderer/row-renderer.d.ts +2 -1
- package/dist/renderer/row-renderer.js +6 -5
- package/dist/renderer/struct-group-renderer.d.ts +2 -1
- package/dist/renderer/struct-group-renderer.js +2 -3
- package/dist/renderer/svg-renderer.d.ts +2 -1
- package/dist/renderer/svg-renderer.js +8 -2
- package/dist/renderer/text-renderer.d.ts +4 -6
- package/dist/renderer/text-renderer.js +114 -127
- package/dist/svg/gradients.js +5 -0
- package/dist/svg/index.d.ts +1 -1
- package/dist/svg/index.js +36 -6
- package/dist/svg/style.d.ts +2 -0
- package/dist/svg/style.js +12 -1
- package/dist/text/advance.d.ts +4 -0
- package/dist/text/advance.js +17 -4
- package/dist/text/bidi.d.ts +0 -2
- package/dist/text/bidi.js +0 -10
- package/dist/text/glyph-coverage.d.ts +1 -1
- package/dist/text/glyph-coverage.js +7 -3
- package/dist/text/hyphen-breaks.d.ts +17 -0
- package/dist/text/hyphen-breaks.js +54 -0
- package/dist/text/line-breaker.d.ts +55 -29
- package/dist/text/line-breaker.js +453 -188
- package/dist/text/line-metrics.d.ts +8 -3
- package/dist/text/line-metrics.js +11 -2
- package/dist/text/pdf-text-string.d.ts +21 -0
- package/dist/text/pdf-text-string.js +114 -0
- package/dist/text/text-decoration.d.ts +5 -5
- package/dist/text/text-decoration.js +5 -5
- package/dist/text/word-splitting.d.ts +15 -2
- package/dist/text/word-splitting.js +45 -13
- package/dist/utils/afm-parser.d.ts +2 -0
- package/dist/utils/afm-parser.js +10 -1
- package/dist/utils/dest-registry.d.ts +1 -1
- package/dist/utils/dest-registry.js +3 -2
- package/dist/utils/fetch-bytes.d.ts +19 -0
- package/dist/utils/fetch-bytes.js +79 -0
- package/dist/utils/flex-layout.d.ts +16 -14
- package/dist/utils/flex-layout.js +427 -217
- package/dist/utils/font-metrics.d.ts +4 -3
- package/dist/utils/image-helper.d.ts +59 -11
- package/dist/utils/image-helper.js +209 -81
- package/dist/utils/pdf-object-manager.d.ts +17 -6
- package/dist/utils/pdf-object-manager.js +70 -20
- package/dist/utils/renderer-registry.d.ts +49 -2
- package/dist/utils/renderer-registry.js +40 -0
- package/dist/utils/struct-tree.d.ts +24 -0
- package/dist/utils/struct-tree.js +61 -9
- package/dist/utils/ttf-parser.d.ts +4 -0
- package/dist/utils/ttf-parser.js +30 -6
- package/dist/validators/element-validator.js +2 -1
- package/package.json +1 -1
- package/dist/elements/layout/sized-container-element.d.ts +0 -14
- package/dist/elements/layout/sized-container-element.js +0 -32
package/dist/api/color.d.ts
CHANGED
|
@@ -1,24 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Every way to name a color. 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 color 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 color means the same thing no matter how it was written.
|
|
23
|
-
*/
|
|
24
|
-
export declare function toColor(input: ColorInput): Color;
|
|
1
|
+
export * from "../common/color-input.js";
|
package/dist/api/color.js
CHANGED
|
@@ -1,278 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export function rgb(r, g, b) {
|
|
4
|
-
return new Color(r, g, b, 1);
|
|
5
|
-
}
|
|
6
|
-
/** Channels 0–255, alpha 0–1. */
|
|
7
|
-
export function rgba(r, g, b, a) {
|
|
8
|
-
return new Color(r, g, b, a);
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Normalizes any `ColorInput` to an engine `Color`. The single funnel every factory uses,
|
|
12
|
-
* so a color means the same thing no matter how it was written.
|
|
13
|
-
*/
|
|
14
|
-
export function toColor(input) {
|
|
15
|
-
if (input instanceof Color)
|
|
16
|
-
return input;
|
|
17
|
-
if (typeof input === "number")
|
|
18
|
-
return fromArgbNumber(input);
|
|
19
|
-
const s = input.trim().toLowerCase();
|
|
20
|
-
if (s.startsWith("#"))
|
|
21
|
-
return fromHex(s);
|
|
22
|
-
const named = CSS_COLORS[s];
|
|
23
|
-
if (named)
|
|
24
|
-
return new Color(named[0], named[1], named[2], named[3] ?? 1);
|
|
25
|
-
const call = /^([a-z-]+)\(([^)]*)\)$/.exec(s);
|
|
26
|
-
if (call)
|
|
27
|
-
return fromFunction(call[1], call[2], input);
|
|
28
|
-
throw new Error(`Unknown color: "${input}"`);
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* The CSS colour FUNCTIONS. `rgb()`/`rgba()` and `hsl()`/`hsla()` are the sRGB family, so they convert
|
|
32
|
-
* exactly and are supported; a wide-gamut function (`color()`, `lab()`, `oklch()`) is named and
|
|
33
|
-
* refused rather than silently squashed into sRGB, since the result would be a colour nobody chose.
|
|
34
|
-
*
|
|
35
|
-
* Both syntaxes are accepted, because both occur in the wild: the legacy comma form
|
|
36
|
-
* `rgb(20, 90, 170)` and the modern space form with an optional slash-alpha `rgb(20 90 170 / 50%)`.
|
|
37
|
-
*/
|
|
38
|
-
function fromFunction(name, body, original) {
|
|
39
|
-
if (name !== "rgb" && name !== "rgba" && name !== "hsl" && name !== "hsla") {
|
|
40
|
-
throw new Error(`Unsupported color function "${name}()" in "${String(original)}". ` +
|
|
41
|
-
`Use a hex value, a CSS colour name, rgb()/rgba() or hsl()/hsla().`);
|
|
42
|
-
}
|
|
43
|
-
const [main, alphaPart] = body.split("/");
|
|
44
|
-
const parts = main
|
|
45
|
-
.trim()
|
|
46
|
-
.split(/[\s,]+/)
|
|
47
|
-
.filter(Boolean);
|
|
48
|
-
const alphaText = alphaPart !== undefined ? alphaPart.trim() : parts[3];
|
|
49
|
-
if (parts.length < 3)
|
|
50
|
-
throw new Error(`Unknown color: "${String(original)}"`);
|
|
51
|
-
const alpha = alphaText === undefined ? 1 : ratio(alphaText, original);
|
|
52
|
-
const [a, b, c] = parts;
|
|
53
|
-
if (name === "rgb" || name === "rgba") {
|
|
54
|
-
return new Color(channel(a, original), channel(b, original), channel(c, original), alpha);
|
|
55
|
-
}
|
|
56
|
-
const [r, g, bl] = hslToRgb(number(a, original), ratio(b, original), ratio(c, original));
|
|
57
|
-
return new Color(r, g, bl, alpha);
|
|
58
|
-
}
|
|
59
|
-
const NUMERIC = /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/;
|
|
60
|
-
/**
|
|
61
|
-
* One component of a colour function. `Number.parseFloat` stops at the first character it cannot use
|
|
62
|
-
* and returns what it had, so `rgb(20abc, 90, 170)` would silently become `rgb(20, 90, 170)` - a
|
|
63
|
-
* colour nobody wrote. The whole token has to be a number.
|
|
64
|
-
*/
|
|
65
|
-
function number(text, original) {
|
|
66
|
-
const t = text.trim();
|
|
67
|
-
if (!NUMERIC.test(t))
|
|
68
|
-
throw new Error(`Unknown color: "${String(original)}"`);
|
|
69
|
-
return Number(t);
|
|
70
|
-
}
|
|
71
|
-
/** An rgb channel: 0-255, or a percentage of 255. */
|
|
72
|
-
const channel = (text, original) => text.trim().endsWith("%")
|
|
73
|
-
? (number(text.trim().slice(0, -1), original) / 100) * 255
|
|
74
|
-
: number(text, original);
|
|
75
|
-
/** A 0..1 ratio written either as a number or as a percentage (alpha, saturation, lightness). */
|
|
76
|
-
const ratio = (text, original) => text.trim().endsWith("%")
|
|
77
|
-
? number(text.trim().slice(0, -1), original) / 100
|
|
78
|
-
: number(text, original);
|
|
79
|
-
/** CSS hue-saturation-lightness to 0-255 channels. */
|
|
80
|
-
function hslToRgb(hue, s, l) {
|
|
81
|
-
const h = ((hue % 360) + 360) % 360;
|
|
82
|
-
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
83
|
-
const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
|
|
84
|
-
const m = l - c / 2;
|
|
85
|
-
const sector = Math.floor(h / 60) % 6;
|
|
86
|
-
const rgbPrime = [
|
|
87
|
-
[c, x, 0],
|
|
88
|
-
[x, c, 0],
|
|
89
|
-
[0, c, x],
|
|
90
|
-
[0, x, c],
|
|
91
|
-
[x, 0, c],
|
|
92
|
-
[c, 0, x],
|
|
93
|
-
][sector];
|
|
94
|
-
return rgbPrime.map((v) => Math.round((v + m) * 255));
|
|
95
|
-
}
|
|
96
|
-
/** Flutter ARGB: 0xAARRGGBB, alpha FIRST. A 6-digit number has alpha 0x00 = transparent. */
|
|
97
|
-
function fromArgbNumber(n) {
|
|
98
|
-
const a = (n >>> 24) & 0xff;
|
|
99
|
-
const r = (n >>> 16) & 0xff;
|
|
100
|
-
const g = (n >>> 8) & 0xff;
|
|
101
|
-
const b = n & 0xff;
|
|
102
|
-
return new Color(r, g, b, a / 255);
|
|
103
|
-
}
|
|
104
|
-
/** CSS hex: #RGB, #RGBA, #RRGGBB, #RRGGBBAA. Alpha is LAST. */
|
|
105
|
-
function fromHex(s) {
|
|
106
|
-
const hex = s.slice(1);
|
|
107
|
-
const expand = (h) => h
|
|
108
|
-
.split("")
|
|
109
|
-
.map((c) => c + c)
|
|
110
|
-
.join("");
|
|
111
|
-
let full;
|
|
112
|
-
if (hex.length === 3 || hex.length === 4)
|
|
113
|
-
full = expand(hex);
|
|
114
|
-
else if (hex.length === 6 || hex.length === 8)
|
|
115
|
-
full = hex;
|
|
116
|
-
else
|
|
117
|
-
throw new Error(`Invalid hex color: "${s}"`);
|
|
118
|
-
const r = parseInt(full.slice(0, 2), 16);
|
|
119
|
-
const g = parseInt(full.slice(2, 4), 16);
|
|
120
|
-
const b = parseInt(full.slice(4, 6), 16);
|
|
121
|
-
const a = full.length === 8 ? parseInt(full.slice(6, 8), 16) / 255 : 1;
|
|
122
|
-
if ([r, g, b].some(Number.isNaN))
|
|
123
|
-
throw new Error(`Invalid hex color: "${s}"`);
|
|
124
|
-
return new Color(r, g, b, a);
|
|
125
|
-
}
|
|
126
|
-
// The full CSS named-color set (~148, incl. the synonyms grey/gray and `transparent`).
|
|
127
|
-
// [r, g, b] or [r, g, b, alpha]. Lower-cased keys; `toColor` lower-cases the input.
|
|
128
|
-
const CSS_COLORS = {
|
|
129
|
-
transparent: [0, 0, 0, 0],
|
|
130
|
-
aliceblue: [240, 248, 255],
|
|
131
|
-
antiquewhite: [250, 235, 215],
|
|
132
|
-
aqua: [0, 255, 255],
|
|
133
|
-
aquamarine: [127, 255, 212],
|
|
134
|
-
azure: [240, 255, 255],
|
|
135
|
-
beige: [245, 245, 220],
|
|
136
|
-
bisque: [255, 228, 196],
|
|
137
|
-
black: [0, 0, 0],
|
|
138
|
-
blanchedalmond: [255, 235, 205],
|
|
139
|
-
blue: [0, 0, 255],
|
|
140
|
-
blueviolet: [138, 43, 226],
|
|
141
|
-
brown: [165, 42, 42],
|
|
142
|
-
burlywood: [222, 184, 135],
|
|
143
|
-
cadetblue: [95, 158, 160],
|
|
144
|
-
chartreuse: [127, 255, 0],
|
|
145
|
-
chocolate: [210, 105, 30],
|
|
146
|
-
coral: [255, 127, 80],
|
|
147
|
-
cornflowerblue: [100, 149, 237],
|
|
148
|
-
cornsilk: [255, 248, 220],
|
|
149
|
-
crimson: [220, 20, 60],
|
|
150
|
-
cyan: [0, 255, 255],
|
|
151
|
-
darkblue: [0, 0, 139],
|
|
152
|
-
darkcyan: [0, 139, 139],
|
|
153
|
-
darkgoldenrod: [184, 134, 11],
|
|
154
|
-
darkgray: [169, 169, 169],
|
|
155
|
-
darkgrey: [169, 169, 169],
|
|
156
|
-
darkgreen: [0, 100, 0],
|
|
157
|
-
darkkhaki: [189, 183, 107],
|
|
158
|
-
darkmagenta: [139, 0, 139],
|
|
159
|
-
darkolivegreen: [85, 107, 47],
|
|
160
|
-
darkorange: [255, 140, 0],
|
|
161
|
-
darkorchid: [153, 50, 204],
|
|
162
|
-
darkred: [139, 0, 0],
|
|
163
|
-
darksalmon: [233, 150, 122],
|
|
164
|
-
darkseagreen: [143, 188, 143],
|
|
165
|
-
darkslateblue: [72, 61, 139],
|
|
166
|
-
darkslategray: [47, 79, 79],
|
|
167
|
-
darkslategrey: [47, 79, 79],
|
|
168
|
-
darkturquoise: [0, 206, 209],
|
|
169
|
-
darkviolet: [148, 0, 211],
|
|
170
|
-
deeppink: [255, 20, 147],
|
|
171
|
-
deepskyblue: [0, 191, 255],
|
|
172
|
-
dimgray: [105, 105, 105],
|
|
173
|
-
dimgrey: [105, 105, 105],
|
|
174
|
-
dodgerblue: [30, 144, 255],
|
|
175
|
-
firebrick: [178, 34, 34],
|
|
176
|
-
floralwhite: [255, 250, 240],
|
|
177
|
-
forestgreen: [34, 139, 34],
|
|
178
|
-
fuchsia: [255, 0, 255],
|
|
179
|
-
gainsboro: [220, 220, 220],
|
|
180
|
-
ghostwhite: [248, 248, 255],
|
|
181
|
-
gold: [255, 215, 0],
|
|
182
|
-
goldenrod: [218, 165, 32],
|
|
183
|
-
gray: [128, 128, 128],
|
|
184
|
-
grey: [128, 128, 128],
|
|
185
|
-
green: [0, 128, 0],
|
|
186
|
-
greenyellow: [173, 255, 47],
|
|
187
|
-
honeydew: [240, 255, 240],
|
|
188
|
-
hotpink: [255, 105, 180],
|
|
189
|
-
indianred: [205, 92, 92],
|
|
190
|
-
indigo: [75, 0, 130],
|
|
191
|
-
ivory: [255, 255, 240],
|
|
192
|
-
khaki: [240, 230, 140],
|
|
193
|
-
lavender: [230, 230, 250],
|
|
194
|
-
lavenderblush: [255, 240, 245],
|
|
195
|
-
lawngreen: [124, 252, 0],
|
|
196
|
-
lemonchiffon: [255, 250, 205],
|
|
197
|
-
lightblue: [173, 216, 230],
|
|
198
|
-
lightcoral: [240, 128, 128],
|
|
199
|
-
lightcyan: [224, 255, 255],
|
|
200
|
-
lightgoldenrodyellow: [250, 250, 210],
|
|
201
|
-
lightgray: [211, 211, 211],
|
|
202
|
-
lightgrey: [211, 211, 211],
|
|
203
|
-
lightgreen: [144, 238, 144],
|
|
204
|
-
lightpink: [255, 182, 193],
|
|
205
|
-
lightsalmon: [255, 160, 122],
|
|
206
|
-
lightseagreen: [32, 178, 170],
|
|
207
|
-
lightskyblue: [135, 206, 250],
|
|
208
|
-
lightslategray: [119, 136, 153],
|
|
209
|
-
lightslategrey: [119, 136, 153],
|
|
210
|
-
lightsteelblue: [176, 196, 222],
|
|
211
|
-
lightyellow: [255, 255, 224],
|
|
212
|
-
lime: [0, 255, 0],
|
|
213
|
-
limegreen: [50, 205, 50],
|
|
214
|
-
linen: [250, 240, 230],
|
|
215
|
-
magenta: [255, 0, 255],
|
|
216
|
-
maroon: [128, 0, 0],
|
|
217
|
-
mediumaquamarine: [102, 205, 170],
|
|
218
|
-
mediumblue: [0, 0, 205],
|
|
219
|
-
mediumorchid: [186, 85, 211],
|
|
220
|
-
mediumpurple: [147, 112, 219],
|
|
221
|
-
mediumseagreen: [60, 179, 113],
|
|
222
|
-
mediumslateblue: [123, 104, 238],
|
|
223
|
-
mediumspringgreen: [0, 250, 154],
|
|
224
|
-
mediumturquoise: [72, 209, 204],
|
|
225
|
-
mediumvioletred: [199, 21, 133],
|
|
226
|
-
midnightblue: [25, 25, 112],
|
|
227
|
-
mintcream: [245, 255, 250],
|
|
228
|
-
mistyrose: [255, 228, 225],
|
|
229
|
-
moccasin: [255, 228, 181],
|
|
230
|
-
navajowhite: [255, 222, 173],
|
|
231
|
-
navy: [0, 0, 128],
|
|
232
|
-
oldlace: [253, 245, 230],
|
|
233
|
-
olive: [128, 128, 0],
|
|
234
|
-
olivedrab: [107, 142, 35],
|
|
235
|
-
orange: [255, 165, 0],
|
|
236
|
-
orangered: [255, 69, 0],
|
|
237
|
-
orchid: [218, 112, 214],
|
|
238
|
-
palegoldenrod: [238, 232, 170],
|
|
239
|
-
palegreen: [152, 251, 152],
|
|
240
|
-
paleturquoise: [175, 238, 238],
|
|
241
|
-
palevioletred: [219, 112, 147],
|
|
242
|
-
papayawhip: [255, 239, 213],
|
|
243
|
-
peachpuff: [255, 218, 185],
|
|
244
|
-
peru: [205, 133, 63],
|
|
245
|
-
pink: [255, 192, 203],
|
|
246
|
-
plum: [221, 160, 221],
|
|
247
|
-
powderblue: [176, 224, 230],
|
|
248
|
-
purple: [128, 0, 128],
|
|
249
|
-
rebeccapurple: [102, 51, 153],
|
|
250
|
-
red: [255, 0, 0],
|
|
251
|
-
rosybrown: [188, 143, 143],
|
|
252
|
-
royalblue: [65, 105, 225],
|
|
253
|
-
saddlebrown: [139, 69, 19],
|
|
254
|
-
salmon: [250, 128, 114],
|
|
255
|
-
sandybrown: [244, 164, 96],
|
|
256
|
-
seagreen: [46, 139, 87],
|
|
257
|
-
seashell: [255, 245, 238],
|
|
258
|
-
sienna: [160, 82, 45],
|
|
259
|
-
silver: [192, 192, 192],
|
|
260
|
-
skyblue: [135, 206, 235],
|
|
261
|
-
slateblue: [106, 90, 205],
|
|
262
|
-
slategray: [112, 128, 144],
|
|
263
|
-
slategrey: [112, 128, 144],
|
|
264
|
-
snow: [255, 250, 250],
|
|
265
|
-
springgreen: [0, 255, 127],
|
|
266
|
-
steelblue: [70, 130, 180],
|
|
267
|
-
tan: [210, 180, 140],
|
|
268
|
-
teal: [0, 128, 128],
|
|
269
|
-
thistle: [216, 191, 216],
|
|
270
|
-
tomato: [255, 99, 71],
|
|
271
|
-
turquoise: [64, 224, 208],
|
|
272
|
-
violet: [238, 130, 238],
|
|
273
|
-
wheat: [245, 222, 179],
|
|
274
|
-
white: [255, 255, 255],
|
|
275
|
-
whitesmoke: [245, 245, 245],
|
|
276
|
-
yellow: [255, 255, 0],
|
|
277
|
-
yellowgreen: [154, 205, 50],
|
|
278
|
-
};
|
|
1
|
+
// Lives in `common/` because the engine reads it too; this is its public face.
|
|
2
|
+
export * from "../common/color-input.js";
|
package/dist/api/content.d.ts
CHANGED
|
@@ -27,18 +27,23 @@ export interface SvgOptions extends BoundsInput {
|
|
|
27
27
|
/** Alternate text (tagged PDF). With it the drawing is a `Figure`; without it, decoration. */
|
|
28
28
|
alt?: string;
|
|
29
29
|
}
|
|
30
|
-
/** An image source: a local file path (Node), raw bytes
|
|
30
|
+
/** An image source: a URL (`http(s):`, `data:`), a local file path (Node), raw bytes, or a `CustomImage`. */
|
|
31
31
|
export type ImageSource = string | Uint8Array | CustomImage;
|
|
32
32
|
/** How the image fills its box (locked §4). Mirrors CSS `object-fit`. */
|
|
33
33
|
export type ImageFit = "none" | "contain" | "cover" | "fill";
|
|
34
|
+
/** Where an image sits in its own box - the image's counterpart of a Text's `align`. */
|
|
35
|
+
export type ImageAlign = "center" | "top" | "bottom" | "left" | "right" | "top left" | "top right" | "bottom left" | "bottom right";
|
|
34
36
|
export interface ImageOptions extends BoundsInput {
|
|
35
37
|
/** Size on each axis: points (fixed) or a percentage string like `"50%"` (a fraction of the offered
|
|
36
38
|
* space). Pin exactly ONE axis and the other follows the image's aspect ratio (CSS `height: auto`). */
|
|
37
39
|
width?: SizeInput;
|
|
38
40
|
height?: SizeInput;
|
|
39
|
-
/**
|
|
40
|
-
*
|
|
41
|
+
/** How the image fills its box (CSS `object-fit`). Default `fill`. Given no size, the box is the image's
|
|
42
|
+
* own size, scaled down to fit what is offered (never up) - so `fill` draws it undistorted. */
|
|
41
43
|
fit?: ImageFit;
|
|
44
|
+
/** Where the image sits in its box when `fit` leaves space or cuts it off. Default `"center"`; a
|
|
45
|
+
* portrait in a `cover` box keeps its top with `"top"`. */
|
|
46
|
+
align?: ImageAlign;
|
|
42
47
|
/** Corner radius in points (rounds the image box). */
|
|
43
48
|
radius?: RadiusInput;
|
|
44
49
|
/** Alternate text for accessibility (tagged PDF): describes the image for screen readers. With `alt`
|
|
@@ -73,8 +78,8 @@ export declare function Canvas(paint: CanvasPaint): CanvasElement;
|
|
|
73
78
|
*/
|
|
74
79
|
export declare function Svg(source: SvgSource, opts?: SvgOptions): SvgElement;
|
|
75
80
|
/**
|
|
76
|
-
* An image. `src` is a local file path
|
|
77
|
-
* `CustomImage
|
|
81
|
+
* An image. `src` is a URL (fetched when the document renders), a local file path, raw bytes, or a
|
|
82
|
+
* ready `CustomImage`. Maps to an `ImageElement`.
|
|
78
83
|
*
|
|
79
84
|
* An SVG source is routed to `Svg` instead, so `Image({ src: "logo.svg" })` just works and a logo
|
|
80
85
|
* stays a VECTOR in the PDF rather than becoming a bitmap.
|
package/dist/api/content.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LineElement } from "../elements/line-element.js";
|
|
2
2
|
import { PaddingElement } from "../elements/layout/padding-element.js";
|
|
3
|
-
import { ImageElement, CustomLocalImage, CustomBytesImage, BoxFit, } from "../elements/image-element.js";
|
|
3
|
+
import { ImageElement, CustomLocalImage, CustomBytesImage, CustomUrlImage, isImageUrl, BoxFit, } from "../elements/image-element.js";
|
|
4
4
|
import { toColor } from "./color.js";
|
|
5
5
|
import { toEdges } from "./insets.js";
|
|
6
6
|
import { toBounds, toDimension, toRadius, } from "./dimension.js";
|
|
@@ -33,6 +33,17 @@ const FIT = {
|
|
|
33
33
|
cover: BoxFit.cover,
|
|
34
34
|
fill: BoxFit.fill,
|
|
35
35
|
};
|
|
36
|
+
const IMAGE_ALIGN = {
|
|
37
|
+
center: { x: 0.5, y: 0.5 },
|
|
38
|
+
top: { x: 0.5, y: 0 },
|
|
39
|
+
bottom: { x: 0.5, y: 1 },
|
|
40
|
+
left: { x: 0, y: 0.5 },
|
|
41
|
+
right: { x: 1, y: 0.5 },
|
|
42
|
+
"top left": { x: 0, y: 0 },
|
|
43
|
+
"top right": { x: 1, y: 0 },
|
|
44
|
+
"bottom left": { x: 0, y: 1 },
|
|
45
|
+
"bottom right": { x: 1, y: 1 },
|
|
46
|
+
};
|
|
36
47
|
export function Canvas(a, b) {
|
|
37
48
|
const opts = typeof a === "function" ? {} : a;
|
|
38
49
|
const paint = typeof a === "function" ? a : b;
|
|
@@ -84,13 +95,17 @@ export function Svg(source, opts = {}) {
|
|
|
84
95
|
/** SVG is recognised by its extension or by its own opening bytes - never by a caller having to say. */
|
|
85
96
|
function isSvg(src) {
|
|
86
97
|
if (typeof src === "string") {
|
|
98
|
+
// A URL by its media type (`data:image/svg+xml`) or the extension of its PATH - a query may follow.
|
|
99
|
+
const path = isImageUrl(src) ? src.trim().replace(/[?#].*$/, "") : src.trim();
|
|
100
|
+
if (/^data:image\/svg\+xml[;,]/i.test(src.trim()))
|
|
101
|
+
return true;
|
|
87
102
|
// `.svgz` is a GZIPPED svg. It is caught here rather than left to the image path, because the
|
|
88
103
|
// error a user needs says what the file is - not "unsupported image bytes".
|
|
89
|
-
if (/\.svgz$/i.test(
|
|
104
|
+
if (/\.svgz$/i.test(path)) {
|
|
90
105
|
throw new Error("@jasy/pdf: SVGZ (a gzip-compressed SVG) is not supported. Decompress it first " +
|
|
91
106
|
"(`gunzip logo.svgz`) and pass the plain .svg.");
|
|
92
107
|
}
|
|
93
|
-
return /\.svg$/i.test(
|
|
108
|
+
return /\.svg$/i.test(path) || /^\s*[<\ufeff]/.test(src);
|
|
94
109
|
}
|
|
95
110
|
if (src instanceof Uint8Array) {
|
|
96
111
|
const head = new TextDecoder().decode(src.subarray(0, 200)).trimStart();
|
|
@@ -99,8 +114,8 @@ function isSvg(src) {
|
|
|
99
114
|
return false;
|
|
100
115
|
}
|
|
101
116
|
/**
|
|
102
|
-
* An image. `src` is a local file path
|
|
103
|
-
* `CustomImage
|
|
117
|
+
* An image. `src` is a URL (fetched when the document renders), a local file path, raw bytes, or a
|
|
118
|
+
* ready `CustomImage`. Maps to an `ImageElement`.
|
|
104
119
|
*
|
|
105
120
|
* An SVG source is routed to `Svg` instead, so `Image({ src: "logo.svg" })` just works and a logo
|
|
106
121
|
* stays a VECTOR in the PDF rather than becoming a bitmap.
|
|
@@ -114,6 +129,10 @@ export function Image(src, opts = {}) {
|
|
|
114
129
|
if (opts.radius !== undefined) {
|
|
115
130
|
throw new Error("@jasy/pdf: radius is not supported for an SVG yet - wrap it in a Box instead.");
|
|
116
131
|
}
|
|
132
|
+
if (opts.align !== undefined) {
|
|
133
|
+
throw new Error("@jasy/pdf: align is not supported for an SVG yet - it is always drawn centred in its box. " +
|
|
134
|
+
"Size the box to the drawing, or place it with the parent's align.");
|
|
135
|
+
}
|
|
117
136
|
return Svg(src, opts);
|
|
118
137
|
}
|
|
119
138
|
return rasterImage(src, opts);
|
|
@@ -121,15 +140,11 @@ export function Image(src, opts = {}) {
|
|
|
121
140
|
function rasterImage(src, opts = {}) {
|
|
122
141
|
const w = opts.width !== undefined ? toDimension(opts.width) : undefined;
|
|
123
142
|
const h = opts.height !== undefined ? toDimension(opts.height) : undefined;
|
|
124
|
-
// ANY explicit size scales the image into the box (fit: fill), which is what `<img width height>`
|
|
125
|
-
// does in HTML and what react-pdf does. Two pinned axes used to keep `none` - drawing the image at
|
|
126
|
-
// its pixel size regardless - so a logo asked for at 48x48 spanned a third of the page.
|
|
127
|
-
// An image with NO size given still draws at its intrinsic size, as an unsized `<img>` does.
|
|
128
|
-
const sized = opts.width !== undefined || opts.height !== undefined || opts.aspectRatio !== undefined;
|
|
129
|
-
const fit = opts.fit ? FIT[opts.fit] : sized ? BoxFit.fill : undefined;
|
|
130
143
|
return new ImageElement({
|
|
131
144
|
image: typeof src === "string"
|
|
132
|
-
?
|
|
145
|
+
? isImageUrl(src)
|
|
146
|
+
? new CustomUrlImage(src)
|
|
147
|
+
: new CustomLocalImage(src)
|
|
133
148
|
: src instanceof Uint8Array
|
|
134
149
|
? new CustomBytesImage(src)
|
|
135
150
|
: src,
|
|
@@ -138,7 +153,8 @@ function rasterImage(src, opts = {}) {
|
|
|
138
153
|
widthFactor: w?.factor,
|
|
139
154
|
heightFactor: h?.factor,
|
|
140
155
|
...toBounds(opts),
|
|
141
|
-
fit,
|
|
156
|
+
fit: opts.fit ? FIT[opts.fit] : undefined,
|
|
157
|
+
align: opts.align ? IMAGE_ALIGN[opts.align] : undefined,
|
|
142
158
|
radius: opts.radius !== undefined ? toRadius(opts.radius) : undefined,
|
|
143
159
|
alt: opts.alt,
|
|
144
160
|
})
|
package/dist/api/descriptor.js
CHANGED
|
@@ -2,8 +2,9 @@ import { Text, Paragraph, span } from "./text.js";
|
|
|
2
2
|
import { Column, Row, Box, Padding, Spacer, PageBreak, keepTogether, Expanded, Positioned, Link, Anchor, Bookmark, Rotated, RotatedBox, } from "./layout.js";
|
|
3
3
|
import { Canvas, Divider, Image, Svg } from "./content.js";
|
|
4
4
|
import { Page, Document, DefaultTextStyle } from "./structure.js";
|
|
5
|
-
import {
|
|
5
|
+
import { PageBuilder, PageCount, PageNumber, SubPageCount, SubPageNumber, } from "./page-builder.js";
|
|
6
6
|
import { Table } from "./table.js";
|
|
7
|
+
import { ColumnBreak, Flow, FlowWithoutRegionError, Region, SplitView, } from "./flow.js";
|
|
7
8
|
import { Checkbox, Dropdown, ListBox, PushButton, RadioGroup, SignatureField, TextField, } from "./forms.js";
|
|
8
9
|
// Element children (Column/Row/Box/Page/…) → built recursively. Text/Paragraph children are
|
|
9
10
|
// strings or `span` descriptors and become content instead.
|
|
@@ -104,6 +105,20 @@ const REGISTRY = {
|
|
|
104
105
|
const body = rows.filter((r) => !r.props?.header);
|
|
105
106
|
return Table({ ...props, header: header ? rowCells(header) : undefined }, body.map(rowCells));
|
|
106
107
|
},
|
|
108
|
+
// A Flow's `page` is a function prop: the binding renders one page of the template per call.
|
|
109
|
+
flow: (props, children) => Flow({
|
|
110
|
+
gap: props.gap,
|
|
111
|
+
balance: props.balance,
|
|
112
|
+
template: (info) => {
|
|
113
|
+
const page = props.page?.(info) ?? [];
|
|
114
|
+
if (page.length === 0)
|
|
115
|
+
throw new FlowWithoutRegionError();
|
|
116
|
+
return wrappedChild(page);
|
|
117
|
+
},
|
|
118
|
+
}, elementChildren(children)),
|
|
119
|
+
region: (props) => Region(props),
|
|
120
|
+
"column-break": () => ColumnBreak(),
|
|
121
|
+
"split-view": (props, children) => SplitView(props, elementChildren(children)),
|
|
107
122
|
positioned: (props, children) => Positioned(props, elementChildren(children)[0]),
|
|
108
123
|
"default-text-style": (props, children) => DefaultTextStyle(props, elementChildren(children)),
|
|
109
124
|
// Navigation. `Link` takes exactly one of `href` (a URL) or `to` (an `Anchor` name) - the factory
|
|
@@ -114,10 +129,22 @@ const REGISTRY = {
|
|
|
114
129
|
// Transforms.
|
|
115
130
|
rotated: (props, children) => Rotated(props, wrappedChild(children)),
|
|
116
131
|
"rotated-box": (props, children) => RotatedBox(props, wrappedChild(children)),
|
|
117
|
-
// Page numbers. `
|
|
118
|
-
//
|
|
132
|
+
// Page numbers. A binding renders `build` per page, like a Flow's `page`; nothing built is an empty
|
|
133
|
+
// Column, so a builder can show something on some pages only.
|
|
134
|
+
"page-builder": (props) => {
|
|
135
|
+
// A descriptor posted as JSON loses its functions; say so here, not mid-layout.
|
|
136
|
+
if (typeof props.build !== "function") {
|
|
137
|
+
throw new Error("A page-builder needs a `build` function prop (lost if the descriptor went through JSON).");
|
|
138
|
+
}
|
|
139
|
+
return PageBuilder((info) => {
|
|
140
|
+
const built = props.build(info) ?? [];
|
|
141
|
+
return built.length === 0 ? Column([]) : wrappedChild(built);
|
|
142
|
+
});
|
|
143
|
+
},
|
|
119
144
|
"page-number": (props) => PageNumber(props),
|
|
120
145
|
"page-count": (props) => PageCount(props),
|
|
146
|
+
"sub-page-number": (props) => SubPageNumber(props),
|
|
147
|
+
"sub-page-count": (props) => SubPageCount(props),
|
|
121
148
|
// Form fields. The three list-like ones take their choices as a SECOND argument in TypeScript; a
|
|
122
149
|
// template has no second argument, so here they arrive as an `options` prop. `choiceList` accepts both
|
|
123
150
|
// the short spelling and the explicit one, because an export value and its label are usually the same
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { FlowElement, type FlowTemplate } from "../elements/layout/flow-element.js";
|
|
2
|
+
import { RegionElement } from "../elements/layout/region-element.js";
|
|
3
|
+
import { ColumnBreakElement } from "../elements/layout/column-break-element.js";
|
|
4
|
+
import { PDFElement } from "../elements/pdf-element.js";
|
|
5
|
+
import { BoundsInput, SizeInput } from "./dimension.js";
|
|
6
|
+
export type { FlowPage, FlowTemplate } from "../elements/layout/flow-element.js";
|
|
7
|
+
export { FlowRegionsEmptyError, FlowUnboundedError, FlowWithoutRegionError, RegionInPageBuilderError, } from "../elements/layout/flow-element.js";
|
|
8
|
+
export { RegionOutsideFlowError, RegionReusedError } from "../elements/layout/region-element.js";
|
|
9
|
+
export interface FlowOptions {
|
|
10
|
+
/** The layout of one page of the Flow, built per page; its `Region`s are where the content goes. */
|
|
11
|
+
template: FlowTemplate;
|
|
12
|
+
/** Space between the content's elements, in points. */
|
|
13
|
+
gap?: number;
|
|
14
|
+
/** On the last page, spread the content so the Regions come out about equally full (default false). */
|
|
15
|
+
balance?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Content flowing through the `Region`s of a template: the first Region full, then the next, then the
|
|
19
|
+
* next page. It takes its height from where it sits - the rest of the page, or a box with a height.
|
|
20
|
+
*
|
|
21
|
+
* @experimental The shape may still change.
|
|
22
|
+
*/
|
|
23
|
+
export declare function Flow(opts: FlowOptions, content: PDFElement[]): FlowElement;
|
|
24
|
+
export interface RegionOptions extends BoundsInput {
|
|
25
|
+
width?: SizeInput;
|
|
26
|
+
height?: SizeInput;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A place in a `Flow`'s template that the content flows through, in tree order. Sized by the layout
|
|
30
|
+
* around it (`Expanded`, `width`, `height`); with nothing given it fills what it is offered.
|
|
31
|
+
*
|
|
32
|
+
* @experimental
|
|
33
|
+
*/
|
|
34
|
+
export declare function Region(opts?: RegionOptions): RegionElement;
|
|
35
|
+
/** Continue in the next `Region` of the Flow it sits in (from the last one, the next page's first). */
|
|
36
|
+
export declare function ColumnBreak(): ColumnBreakElement;
|
|
37
|
+
export interface SplitViewOptions {
|
|
38
|
+
/** How many columns, side by side and equally wide (default 2). */
|
|
39
|
+
columns?: number;
|
|
40
|
+
/** Gap between both the columns and the content's elements (default 0). */
|
|
41
|
+
gap?: number;
|
|
42
|
+
/** Gap between the content's elements (overrides `gap`). */
|
|
43
|
+
rowGap?: number;
|
|
44
|
+
/** Gap between the columns (overrides `gap`). */
|
|
45
|
+
colGap?: number;
|
|
46
|
+
/** On the last page, columns of about equal height, as CSS columns are (default true). */
|
|
47
|
+
balance?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Newspaper columns: the content fills the first column, then the next, then the next page. A `Flow`
|
|
51
|
+
* with a ready template - for anything else (a title area, columns of different widths) build your own.
|
|
52
|
+
*
|
|
53
|
+
* @experimental
|
|
54
|
+
*/
|
|
55
|
+
export declare function SplitView(opts: SplitViewOptions, content: PDFElement[]): FlowElement;
|
package/dist/api/flow.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ContainerElement } from "../elements/container-element.js";
|
|
2
|
+
import { FlowElement } from "../elements/layout/flow-element.js";
|
|
3
|
+
import { RegionElement } from "../elements/layout/region-element.js";
|
|
4
|
+
import { ColumnBreakElement } from "../elements/layout/column-break-element.js";
|
|
5
|
+
import { toBounds, toDimension } from "./dimension.js";
|
|
6
|
+
import { Expanded, Row } from "./layout.js";
|
|
7
|
+
export { FlowRegionsEmptyError, FlowUnboundedError, FlowWithoutRegionError, RegionInPageBuilderError, } from "../elements/layout/flow-element.js";
|
|
8
|
+
export { RegionOutsideFlowError, RegionReusedError } from "../elements/layout/region-element.js";
|
|
9
|
+
/**
|
|
10
|
+
* Content flowing through the `Region`s of a template: the first Region full, then the next, then the
|
|
11
|
+
* next page. It takes its height from where it sits - the rest of the page, or a box with a height.
|
|
12
|
+
*
|
|
13
|
+
* @experimental The shape may still change.
|
|
14
|
+
*/
|
|
15
|
+
export function Flow(opts, content) {
|
|
16
|
+
return new FlowElement({
|
|
17
|
+
content: new ContainerElement({ x: 0, y: 0, children: content, gap: opts.gap }),
|
|
18
|
+
template: opts.template,
|
|
19
|
+
balance: opts.balance,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A place in a `Flow`'s template that the content flows through, in tree order. Sized by the layout
|
|
24
|
+
* around it (`Expanded`, `width`, `height`); with nothing given it fills what it is offered.
|
|
25
|
+
*
|
|
26
|
+
* @experimental
|
|
27
|
+
*/
|
|
28
|
+
export function Region(opts = {}) {
|
|
29
|
+
const w = opts.width !== undefined ? toDimension(opts.width) : undefined;
|
|
30
|
+
const h = opts.height !== undefined ? toDimension(opts.height) : undefined;
|
|
31
|
+
return new RegionElement({
|
|
32
|
+
width: w?.points,
|
|
33
|
+
height: h?.points,
|
|
34
|
+
widthFactor: w?.factor,
|
|
35
|
+
heightFactor: h?.factor,
|
|
36
|
+
...toBounds(opts),
|
|
37
|
+
})
|
|
38
|
+
.withAlignSelf(opts.alignSelf)
|
|
39
|
+
.withOrder(opts.order)
|
|
40
|
+
.withFlexShrink(opts.flexShrink);
|
|
41
|
+
}
|
|
42
|
+
/** Continue in the next `Region` of the Flow it sits in (from the last one, the next page's first). */
|
|
43
|
+
export function ColumnBreak() {
|
|
44
|
+
return new ColumnBreakElement();
|
|
45
|
+
}
|
|
46
|
+
/** A value as the author wrote it: `"2"` quoted, `NaN` as NaN. */
|
|
47
|
+
const shown = (value) => typeof value === "string" ? JSON.stringify(value) : String(value);
|
|
48
|
+
/**
|
|
49
|
+
* Newspaper columns: the content fills the first column, then the next, then the next page. A `Flow`
|
|
50
|
+
* with a ready template - for anything else (a title area, columns of different widths) build your own.
|
|
51
|
+
*
|
|
52
|
+
* @experimental
|
|
53
|
+
*/
|
|
54
|
+
export function SplitView(opts, content) {
|
|
55
|
+
const columns = opts.columns ?? 2;
|
|
56
|
+
if (!Number.isInteger(columns) || columns < 1) {
|
|
57
|
+
throw new Error(`Invalid SplitView columns ${shown(columns)}: use a whole number of 1 or more.`);
|
|
58
|
+
}
|
|
59
|
+
for (const key of ["gap", "rowGap", "colGap"]) {
|
|
60
|
+
const value = opts[key];
|
|
61
|
+
if (value !== undefined && !(Number.isFinite(value) && value >= 0)) {
|
|
62
|
+
throw new Error(`Invalid SplitView ${key} ${shown(value)}: use a number of points, 0 or more.`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const colGap = opts.colGap ?? opts.gap;
|
|
66
|
+
return Flow({
|
|
67
|
+
gap: opts.rowGap ?? opts.gap,
|
|
68
|
+
balance: opts.balance ?? true,
|
|
69
|
+
template: () => Row({ gap: colGap }, Array.from({ length: columns }, () => Expanded(Region()))),
|
|
70
|
+
}, content);
|
|
71
|
+
}
|
package/dist/api/font-url.d.ts
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* same contract, differing only in being async. So the failure lands where you asked for the font,
|
|
6
6
|
* not somewhere inside a later render.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* port, unlike the filesystem read beside it.
|
|
8
|
+
* The fetch itself - timeout, size ceiling - is `utils/fetch-bytes.ts`, shared with images.
|
|
10
9
|
*/
|
|
11
10
|
/** One font file by URL, or a styled family of them. Mirrors `FontSource`, with strings meaning URLs. */
|
|
12
11
|
export type UrlFontSource = string | {
|