@jasy/pdf 1.0.0-beta.2 → 1.0.0-beta.4
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/content.d.ts +5 -5
- package/dist/api/content.js +12 -6
- 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/index.d.ts +2 -0
- package/dist/api/index.js +1 -0
- package/dist/api/layout.d.ts +6 -0
- package/dist/api/layout.js +7 -2
- 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 +99 -22
- package/dist/common/diagnostics.d.ts +53 -0
- package/dist/common/diagnostics.js +77 -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 +5 -1
- package/dist/elements/container-element.js +35 -15
- 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 +39 -1
- package/dist/elements/image-element.js +95 -12
- 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/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 +12 -4
- package/dist/elements/layout/deferred-element.js +24 -7
- package/dist/elements/layout/expanded-element.d.ts +7 -0
- package/dist/elements/layout/expanded-element.js +40 -18
- package/dist/elements/layout/keep-together-element.d.ts +8 -18
- package/dist/elements/layout/keep-together-element.js +21 -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 +15 -1
- package/dist/elements/layout/padding-element.js +55 -27
- 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 +11 -0
- package/dist/elements/layout/positioned-element.d.ts +14 -2
- package/dist/elements/layout/positioned-element.js +36 -10
- package/dist/elements/layout/proxy-element.d.ts +43 -0
- package/dist/elements/layout/proxy-element.js +94 -0
- package/dist/elements/layout/repeating-header-element.d.ts +6 -0
- package/dist/elements/layout/repeating-header-element.js +40 -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 +7 -0
- package/dist/elements/layout/rotated-element.js +25 -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 +75 -15
- package/dist/elements/pdf-element.js +68 -18
- package/dist/elements/rectangle-element.d.ts +14 -0
- package/dist/elements/rectangle-element.js +97 -52
- package/dist/elements/row-element.d.ts +11 -0
- package/dist/elements/row-element.js +58 -8
- package/dist/elements/svg-element.d.ts +30 -6
- package/dist/elements/svg-element.js +88 -17
- package/dist/elements/text-element.d.ts +40 -13
- package/dist/elements/text-element.js +144 -99
- 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 +12 -2
- package/dist/layout/box-constraints.d.ts +5 -0
- package/dist/layout/box-constraints.js +14 -0
- package/dist/layout/collect-images.d.ts +6 -4
- package/dist/layout/collect-images.js +6 -4
- package/dist/layout/flex-item.d.ts +9 -0
- package/dist/layout/flex-item.js +39 -0
- package/dist/layout/fragmentation.d.ts +12 -4
- package/dist/layout/fragmentation.js +37 -14
- package/dist/layout/layout-cache.d.ts +53 -0
- package/dist/layout/layout-cache.js +107 -0
- 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/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/expanded-renderer.d.ts +2 -1
- package/dist/renderer/expanded-renderer.js +2 -3
- 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 +5 -2
- 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 +28 -7
- package/dist/renderer/pdf-backend.d.ts +4 -3
- package/dist/renderer/pdf-backend.js +5 -5
- package/dist/renderer/pdf-document-renderer.d.ts +1 -8
- package/dist/renderer/pdf-document-renderer.js +15 -16
- package/dist/renderer/pdf-renderer.js +11 -11
- package/dist/renderer/positioned-renderer.d.ts +6 -1
- package/dist/renderer/positioned-renderer.js +6 -5
- package/dist/renderer/rectangle-renderer.d.ts +2 -1
- package/dist/renderer/rectangle-renderer.js +9 -4
- 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 +8 -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 +101 -111
- package/dist/svg/gradients.js +5 -0
- package/dist/svg/index.js +10 -1
- package/dist/svg/style.d.ts +2 -0
- package/dist/svg/style.js +11 -0
- package/dist/text/advance.d.ts +4 -0
- package/dist/text/advance.js +49 -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 +34 -31
- package/dist/text/line-breaker.js +364 -176
- package/dist/text/line-metrics.d.ts +6 -3
- package/dist/text/line-metrics.js +7 -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 +34 -8
- package/dist/utils/afm-parser.d.ts +3 -0
- package/dist/utils/afm-parser.js +19 -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 +13 -13
- package/dist/utils/flex-layout.js +318 -216
- package/dist/utils/font-metrics.d.ts +4 -3
- package/dist/utils/image-helper.js +2 -1
- package/dist/utils/pdf-object-manager.d.ts +11 -3
- package/dist/utils/pdf-object-manager.js +41 -15
- package/dist/utils/renderer-registry.d.ts +43 -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 +27 -4
- 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
|
@@ -16,26 +16,34 @@ export class ExpandedElement extends FlexiblePDFElement {
|
|
|
16
16
|
return this.child.minIntrinsicMain(horizontal, ctx);
|
|
17
17
|
}
|
|
18
18
|
calculateLayout(constraints, offset, ctx) {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
Validator.validateFlexElement(this);
|
|
20
|
+
const size = this.sizeWith(constraints, ctx, offset);
|
|
21
21
|
// Absolute placement from the parent; assignment (not +=) so re-layout is idempotent.
|
|
22
22
|
this.x = offset.x;
|
|
23
23
|
this.y = offset.y;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
|
|
24
|
+
this.width = size.width;
|
|
25
|
+
this.height = size.height;
|
|
26
|
+
return size;
|
|
27
|
+
}
|
|
28
|
+
computeSize(constraints, ctx) {
|
|
29
|
+
return this.sizeWith(constraints, ctx, null);
|
|
30
|
+
}
|
|
31
|
+
/** The one sizing path: with an `offset` the child is laid out there, with `null` only measured. */
|
|
32
|
+
sizeWith(constraints, ctx, offset) {
|
|
33
|
+
// It fills its MAIN axis only. Across it, it is an ordinary child: with no width bound it takes
|
|
34
|
+
// its content's width, from THIS call - never one left over from an earlier layout.
|
|
35
|
+
const width = constraints.hasBoundedWidth ? constraints.maxWidth : Infinity;
|
|
36
|
+
// A bounded region: fill it - the normal flex behavior. Unbounded (measuring while paginating):
|
|
37
|
+
// there's no leftover space to fill, so collapse to the child's natural height. This lets an
|
|
38
|
+
// overflowing column flow instead of the flex silently hiding the overflow.
|
|
39
|
+
const childConstraints = BoxConstraints.loose(width, constraints.hasBoundedHeight ? constraints.maxHeight : Infinity);
|
|
40
|
+
const childSize = offset
|
|
41
|
+
? this.child.calculateLayout(childConstraints, { x: offset.x, y: offset.y }, ctx)
|
|
42
|
+
: this.child.measure(childConstraints, ctx);
|
|
43
|
+
return {
|
|
44
|
+
width: constraints.hasBoundedWidth ? width : childSize.width,
|
|
45
|
+
height: constraints.hasBoundedHeight ? constraints.maxHeight : childSize.height,
|
|
46
|
+
};
|
|
39
47
|
}
|
|
40
48
|
/**
|
|
41
49
|
* When the column paginates, a flex region can't "fill" across pages, so it delegates to
|
|
@@ -51,8 +59,19 @@ export class ExpandedElement extends FlexiblePDFElement {
|
|
|
51
59
|
return {
|
|
52
60
|
fitted: split.fitted ? this.cloneWithChild(split.fitted) : null,
|
|
53
61
|
remainder: split.remainder ? this.cloneWithChild(split.remainder) : null,
|
|
62
|
+
forceBreak: split.forceBreak,
|
|
54
63
|
};
|
|
55
64
|
}
|
|
65
|
+
// A break inside the flex child is a break in the flow it sits in.
|
|
66
|
+
hasForcedBreak() {
|
|
67
|
+
return this.child.hasForcedBreak();
|
|
68
|
+
}
|
|
69
|
+
breaksBefore() {
|
|
70
|
+
return this.child.breaksBefore();
|
|
71
|
+
}
|
|
72
|
+
breaksAfter() {
|
|
73
|
+
return this.child.breaksAfter();
|
|
74
|
+
}
|
|
56
75
|
cloneWithChild(child) {
|
|
57
76
|
// The basis has to come along: a fragment that lost it would claim only its share of the leftover,
|
|
58
77
|
// so a `flexBasis` slot would silently change width on the page it continues onto.
|
|
@@ -61,7 +80,10 @@ export class ExpandedElement extends FlexiblePDFElement {
|
|
|
61
80
|
basis: this.basis,
|
|
62
81
|
basisFactor: this.basisFactor,
|
|
63
82
|
child,
|
|
64
|
-
});
|
|
83
|
+
}).asPieceOf(this);
|
|
84
|
+
}
|
|
85
|
+
layoutChildren() {
|
|
86
|
+
return [this.child];
|
|
65
87
|
}
|
|
66
88
|
getProps() {
|
|
67
89
|
return {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Fragmentable, FragmentResult } from "../../layout/fragmentation.js";
|
|
1
|
+
import { FragmentResult } from "../../layout/fragmentation.js";
|
|
3
2
|
import { LayoutContext, PDFElement } from "../pdf-element.js";
|
|
3
|
+
import { ProxyElement } from "./proxy-element.js";
|
|
4
4
|
/**
|
|
5
|
-
* A layout-
|
|
6
|
-
*
|
|
7
|
-
* unwrapped content; only pagination behaves differently.
|
|
5
|
+
* A layout-transparent wrapper (a `ProxyElement`) that tries to keep its content on ONE page (CSS
|
|
6
|
+
* `break-inside: avoid`). Only pagination behaves differently from the unwrapped content.
|
|
8
7
|
*
|
|
9
8
|
* The rule, decided in `fragment`:
|
|
10
9
|
* 1. Fits in the space offered here -> place it whole.
|
|
@@ -20,23 +19,14 @@ import { LayoutContext, PDFElement } from "../pdf-element.js";
|
|
|
20
19
|
* keeping it together: the break wins (CSS behaves the same), and we WARN once rather than silently
|
|
21
20
|
* swallowing either intent.
|
|
22
21
|
*/
|
|
23
|
-
export declare class KeepTogetherElement extends
|
|
24
|
-
private child;
|
|
25
|
-
private warnedBreakConflict;
|
|
22
|
+
export declare class KeepTogetherElement extends ProxyElement {
|
|
26
23
|
constructor({ child }: {
|
|
27
24
|
child: PDFElement;
|
|
28
25
|
});
|
|
29
|
-
|
|
30
|
-
minIntrinsicMain(horizontal: boolean, ctx: LayoutContext): number;
|
|
31
|
-
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
32
|
-
relativeSizeFactor(horizontal: boolean): number | undefined;
|
|
33
|
-
needsBoundedMain(horizontal: boolean): boolean;
|
|
34
|
-
hasForcedBreak(): boolean;
|
|
35
|
-
breaksBefore(): boolean;
|
|
36
|
-
breaksAfter(): boolean;
|
|
26
|
+
protected rewrap(child: PDFElement): PDFElement;
|
|
37
27
|
fragment(maxHeight: number, width: number, ctx: LayoutContext): FragmentResult;
|
|
38
|
-
/**
|
|
39
|
-
*
|
|
28
|
+
/** Split like any wrapper - once we have decided to break the group, the pieces flow bare but keep
|
|
29
|
+
* the group's place in the flex line (any INNER keepTogether lives in the child and still vetoes). */
|
|
40
30
|
private splitChild;
|
|
41
31
|
getProps(): {
|
|
42
32
|
child: PDFElement;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { BoxConstraints } from "../../layout/box-constraints.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ProxyElement } from "./proxy-element.js";
|
|
3
|
+
import { diagnose, pageOf } from "../../common/diagnostics.js";
|
|
4
4
|
/**
|
|
5
|
-
* A layout-
|
|
6
|
-
*
|
|
7
|
-
* unwrapped content; only pagination behaves differently.
|
|
5
|
+
* A layout-transparent wrapper (a `ProxyElement`) that tries to keep its content on ONE page (CSS
|
|
6
|
+
* `break-inside: avoid`). Only pagination behaves differently from the unwrapped content.
|
|
8
7
|
*
|
|
9
8
|
* The rule, decided in `fragment`:
|
|
10
9
|
* 1. Fits in the space offered here -> place it whole.
|
|
@@ -20,50 +19,29 @@ import { PDFElement } from "../pdf-element.js";
|
|
|
20
19
|
* keeping it together: the break wins (CSS behaves the same), and we WARN once rather than silently
|
|
21
20
|
* swallowing either intent.
|
|
22
21
|
*/
|
|
23
|
-
export class KeepTogetherElement extends
|
|
22
|
+
export class KeepTogetherElement extends ProxyElement {
|
|
24
23
|
constructor({ child }) {
|
|
25
|
-
super();
|
|
26
|
-
this.warnedBreakConflict = false;
|
|
27
|
-
this.child = child;
|
|
24
|
+
super(child);
|
|
28
25
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
calculateLayout(constraints, offset, ctx) {
|
|
34
|
-
return this.child.calculateLayout(constraints, offset, ctx);
|
|
35
|
-
}
|
|
36
|
-
// Transparent: forward the sizing hints the flex parent reads, so a %-sized or Spacer-holding child
|
|
37
|
-
// keeps working when it is wrapped (the wrapper must not swallow these).
|
|
38
|
-
relativeSizeFactor(horizontal) {
|
|
39
|
-
return this.child.relativeSizeFactor(horizontal);
|
|
40
|
-
}
|
|
41
|
-
needsBoundedMain(horizontal) {
|
|
42
|
-
return this.child.needsBoundedMain(horizontal);
|
|
43
|
-
}
|
|
44
|
-
// Transparent to break control: a break-before/after on the wrapped element still applies to the group
|
|
45
|
-
// as a whole, and an inner forced break still forces the parent to fragment us (so `fragment` runs).
|
|
46
|
-
hasForcedBreak() {
|
|
47
|
-
return this.child.hasForcedBreak();
|
|
48
|
-
}
|
|
49
|
-
breaksBefore() {
|
|
50
|
-
return this.child.breaksBefore();
|
|
51
|
-
}
|
|
52
|
-
breaksAfter() {
|
|
53
|
-
return this.child.breaksAfter();
|
|
26
|
+
// Once the group is broken, its pieces flow bare (see `splitChild`).
|
|
27
|
+
rewrap(child) {
|
|
28
|
+
return child;
|
|
54
29
|
}
|
|
55
30
|
fragment(maxHeight, width, ctx) {
|
|
56
31
|
// Contradiction: a forced break inside the group beats keeping it together. Split at the break by
|
|
57
32
|
// delegating to the child (which honours it), and say so once - never keep such a group whole.
|
|
58
33
|
if (this.child.hasForcedBreak()) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
34
|
+
diagnose(ctx.diagnostics, {
|
|
35
|
+
code: "keep-together-split",
|
|
36
|
+
severity: "warning",
|
|
37
|
+
message: "keepTogether contains a forced page break (PageBreak / breakBefore / breakAfter). The break " +
|
|
38
|
+
"wins and the group is split. Remove the break, or the keepTogether, to resolve this.",
|
|
39
|
+
about: this,
|
|
40
|
+
page: pageOf(ctx),
|
|
41
|
+
});
|
|
64
42
|
return this.splitChild(maxHeight, width, ctx);
|
|
65
43
|
}
|
|
66
|
-
const natural = this.child.
|
|
44
|
+
const natural = this.child.measure(BoxConstraints.loose(width, Infinity), ctx).height;
|
|
67
45
|
// 1. Fits in the offered space: keep whole.
|
|
68
46
|
if (natural <= maxHeight)
|
|
69
47
|
return { fitted: this, remainder: null };
|
|
@@ -76,12 +54,10 @@ export class KeepTogetherElement extends PDFElement {
|
|
|
76
54
|
// 3. Bigger than a whole page: it can never be kept together, so split it.
|
|
77
55
|
return this.splitChild(maxHeight, width, ctx);
|
|
78
56
|
}
|
|
79
|
-
/**
|
|
80
|
-
*
|
|
57
|
+
/** Split like any wrapper - once we have decided to break the group, the pieces flow bare but keep
|
|
58
|
+
* the group's place in the flex line (any INNER keepTogether lives in the child and still vetoes). */
|
|
81
59
|
splitChild(maxHeight, width, ctx) {
|
|
82
|
-
|
|
83
|
-
return { fitted: null, remainder: this };
|
|
84
|
-
return this.child.fragment(maxHeight, width, ctx);
|
|
60
|
+
return super.fragment(maxHeight, width, ctx);
|
|
85
61
|
}
|
|
86
62
|
getProps() {
|
|
87
63
|
return { child: this.child };
|
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
import { PDFElement
|
|
2
|
-
import {
|
|
1
|
+
import { PDFElement } from "../pdf-element.js";
|
|
2
|
+
import { ProxyElement } from "./proxy-element.js";
|
|
3
3
|
/**
|
|
4
4
|
* Makes its child a clickable hyperlink. `href` is an external URL; `dest` is an internal named
|
|
5
|
-
* destination (an `Anchor` elsewhere in the document) - exactly one is set. Layout-transparent
|
|
6
|
-
*
|
|
7
|
-
* a
|
|
8
|
-
*
|
|
5
|
+
* destination (an `Anchor` elsewhere in the document) - exactly one is set. Layout-transparent (a
|
|
6
|
+
* `ProxyElement`); the renderer turns the child's box into a `Link` IR node (and the page renderer into
|
|
7
|
+
* a /Link annotation). The link draws nothing itself - style the child (e.g. a blue Text) if you want it
|
|
8
|
+
* to look like a link. Split across pages, every piece stays clickable.
|
|
9
9
|
*/
|
|
10
|
-
export declare class LinkElement extends
|
|
10
|
+
export declare class LinkElement extends ProxyElement {
|
|
11
11
|
private href?;
|
|
12
12
|
private dest?;
|
|
13
|
-
private child;
|
|
14
|
-
private x;
|
|
15
|
-
private y;
|
|
16
|
-
private width;
|
|
17
|
-
private height;
|
|
18
13
|
constructor({ href, dest, child }: {
|
|
19
14
|
href?: string;
|
|
20
15
|
dest?: string;
|
|
21
16
|
child: PDFElement;
|
|
22
17
|
});
|
|
23
|
-
|
|
18
|
+
protected rewrap(child: PDFElement): PDFElement;
|
|
24
19
|
getProps(): {
|
|
25
20
|
href: string | undefined;
|
|
26
21
|
dest: string | undefined;
|
|
@@ -1,29 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProxyElement } from "./proxy-element.js";
|
|
2
2
|
/**
|
|
3
3
|
* Makes its child a clickable hyperlink. `href` is an external URL; `dest` is an internal named
|
|
4
|
-
* destination (an `Anchor` elsewhere in the document) - exactly one is set. Layout-transparent
|
|
5
|
-
*
|
|
6
|
-
* a
|
|
7
|
-
*
|
|
4
|
+
* destination (an `Anchor` elsewhere in the document) - exactly one is set. Layout-transparent (a
|
|
5
|
+
* `ProxyElement`); the renderer turns the child's box into a `Link` IR node (and the page renderer into
|
|
6
|
+
* a /Link annotation). The link draws nothing itself - style the child (e.g. a blue Text) if you want it
|
|
7
|
+
* to look like a link. Split across pages, every piece stays clickable.
|
|
8
8
|
*/
|
|
9
|
-
export class LinkElement extends
|
|
9
|
+
export class LinkElement extends ProxyElement {
|
|
10
10
|
constructor({ href, dest, child }) {
|
|
11
|
-
super();
|
|
12
|
-
this.x = 0;
|
|
13
|
-
this.y = 0;
|
|
14
|
-
this.width = 0;
|
|
15
|
-
this.height = 0;
|
|
11
|
+
super(child);
|
|
16
12
|
this.href = href;
|
|
17
13
|
this.dest = dest;
|
|
18
|
-
this.child = child;
|
|
19
14
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.x = offset.x;
|
|
23
|
-
this.y = offset.y;
|
|
24
|
-
this.width = size.width;
|
|
25
|
-
this.height = size.height;
|
|
26
|
-
return size;
|
|
15
|
+
rewrap(child) {
|
|
16
|
+
return new LinkElement({ href: this.href, dest: this.dest, child });
|
|
27
17
|
}
|
|
28
18
|
getProps() {
|
|
29
19
|
return {
|
|
@@ -5,11 +5,19 @@ import { type EdgeSpecs } from "../../layout/insets.js";
|
|
|
5
5
|
interface PaddingElementParams extends WithChild {
|
|
6
6
|
/** Still unresolved: a side may be a percentage of the offered WIDTH (see `Insets`). */
|
|
7
7
|
margin: EdgeSpecs;
|
|
8
|
+
/** This is a `Box`'s own padding: a percentage resolves against what the Box was offered
|
|
9
|
+
* (`ctx.boxPaddingBase`), as CSS resolves it against the containing block. */
|
|
10
|
+
ofBox?: boolean;
|
|
8
11
|
}
|
|
9
12
|
export declare class PaddingElement extends SizedPDFElement implements Fragmentable {
|
|
10
13
|
private child;
|
|
11
14
|
private margin;
|
|
12
|
-
|
|
15
|
+
readonly ofBox: boolean;
|
|
16
|
+
constructor({ margin, child, ofBox }: PaddingElementParams);
|
|
17
|
+
/** The width a percentage side resolves against, and the context the child sees: a Box's base is
|
|
18
|
+
* for this padding alone, so it does not travel further down. */
|
|
19
|
+
private percentBase;
|
|
20
|
+
private childContext;
|
|
13
21
|
/**
|
|
14
22
|
* Splits the padded box across pages (box-decoration-break: clone - every fragment
|
|
15
23
|
* keeps its full top/bottom inset). The child is fragmented into the space left after
|
|
@@ -17,6 +25,8 @@ export declare class PaddingElement extends SizedPDFElement implements Fragmenta
|
|
|
17
25
|
* child can't be split, the whole padding moves on as the remainder.
|
|
18
26
|
*/
|
|
19
27
|
fragment(maxHeight: number, width: number, ctx: LayoutContext): FragmentResult;
|
|
28
|
+
/** A wrapper: it needs a bound exactly when its child does, and passes the bound on. */
|
|
29
|
+
needsBoundedMain(horizontal: boolean): boolean;
|
|
20
30
|
hasForcedBreak(): boolean;
|
|
21
31
|
breaksBefore(): boolean;
|
|
22
32
|
breaksAfter(): boolean;
|
|
@@ -27,6 +37,10 @@ export declare class PaddingElement extends SizedPDFElement implements Fragmenta
|
|
|
27
37
|
*/
|
|
28
38
|
minIntrinsicMain(horizontal: boolean, ctx: LayoutContext): number;
|
|
29
39
|
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
40
|
+
protected computeSize(constraints: BoxConstraints, ctx: LayoutContext): Size;
|
|
41
|
+
/** The one sizing path: `layout` places the child (relative to this box), `measure` only sizes it. */
|
|
42
|
+
private sizeWith;
|
|
43
|
+
layoutChildren(): readonly PDFElement[];
|
|
30
44
|
getProps(): {
|
|
31
45
|
x: number;
|
|
32
46
|
y: number;
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { Validator } from "../../validators/element-validator.js";
|
|
2
2
|
import { SizedPDFElement } from "../pdf-element.js";
|
|
3
3
|
import { BoxConstraints } from "../../layout/box-constraints.js";
|
|
4
|
-
import { isFragmentable } from "../../layout/fragmentation.js";
|
|
4
|
+
import { insetContext, isFragmentable, } from "../../layout/fragmentation.js";
|
|
5
5
|
import { resolveEdges } from "../../layout/insets.js";
|
|
6
6
|
export class PaddingElement extends SizedPDFElement {
|
|
7
|
-
constructor({ margin, child }) {
|
|
7
|
+
constructor({ margin, child, ofBox = false }) {
|
|
8
8
|
super({ x: 0, y: 0 });
|
|
9
9
|
this.child = child;
|
|
10
10
|
this.margin = margin;
|
|
11
|
+
this.ofBox = ofBox;
|
|
12
|
+
}
|
|
13
|
+
/** The width a percentage side resolves against, and the context the child sees: a Box's base is
|
|
14
|
+
* for this padding alone, so it does not travel further down. */
|
|
15
|
+
percentBase(width, ctx) {
|
|
16
|
+
return this.ofBox && ctx.boxPaddingBase !== undefined ? ctx.boxPaddingBase : width;
|
|
17
|
+
}
|
|
18
|
+
childContext(ctx) {
|
|
19
|
+
return ctx.boxPaddingBase === undefined ? ctx : { ...ctx, boxPaddingBase: undefined };
|
|
11
20
|
}
|
|
12
21
|
/**
|
|
13
22
|
* Splits the padded box across pages (box-decoration-break: clone - every fragment
|
|
@@ -19,16 +28,20 @@ export class PaddingElement extends SizedPDFElement {
|
|
|
19
28
|
if (!isFragmentable(this.child)) {
|
|
20
29
|
return { fitted: null, remainder: this };
|
|
21
30
|
}
|
|
22
|
-
const [marginTop, marginRight, marginBottom, marginLeft] = resolveEdges(this.margin, width);
|
|
31
|
+
const [marginTop, marginRight, marginBottom, marginLeft] = resolveEdges(this.margin, this.percentBase(width, ctx));
|
|
23
32
|
const childWidth = width - marginLeft - marginRight;
|
|
24
33
|
const childMaxHeight = maxHeight - marginTop - marginBottom;
|
|
25
|
-
const split = this.child.fragment(childMaxHeight, childWidth, ctx);
|
|
34
|
+
const split = this.child.fragment(childMaxHeight, childWidth, insetContext(this.childContext(ctx), marginTop + marginBottom));
|
|
26
35
|
return {
|
|
27
36
|
fitted: split.fitted ? this.cloneWithChild(split.fitted) : null,
|
|
28
37
|
remainder: split.remainder ? this.cloneWithChild(split.remainder) : null,
|
|
29
38
|
forceBreak: split.forceBreak,
|
|
30
39
|
};
|
|
31
40
|
}
|
|
41
|
+
/** A wrapper: it needs a bound exactly when its child does, and passes the bound on. */
|
|
42
|
+
needsBoundedMain(horizontal) {
|
|
43
|
+
return this.child.needsBoundedMain(horizontal);
|
|
44
|
+
}
|
|
32
45
|
hasForcedBreak() {
|
|
33
46
|
return this.child.hasForcedBreak();
|
|
34
47
|
}
|
|
@@ -41,7 +54,7 @@ export class PaddingElement extends SizedPDFElement {
|
|
|
41
54
|
return this.child.breaksAfter();
|
|
42
55
|
}
|
|
43
56
|
cloneWithChild(child) {
|
|
44
|
-
return new PaddingElement({ margin: this.margin, child });
|
|
57
|
+
return new PaddingElement({ margin: this.margin, child, ofBox: this.ofBox }).asPieceOf(this);
|
|
45
58
|
}
|
|
46
59
|
/**
|
|
47
60
|
* The child plus our own insets. A PERCENTAGE inset counts as zero here: it resolves against a width
|
|
@@ -52,33 +65,48 @@ export class PaddingElement extends SizedPDFElement {
|
|
|
52
65
|
return (this.child.minIntrinsicMain(horizontal, ctx) + (horizontal ? left + right : top + bottom));
|
|
53
66
|
}
|
|
54
67
|
calculateLayout(constraints, offset, ctx) {
|
|
55
|
-
|
|
56
|
-
if (constraints.hasBoundedWidth)
|
|
57
|
-
this.width = constraints.maxWidth;
|
|
68
|
+
const size = this.sizeWith(constraints, ctx, "layout");
|
|
58
69
|
this.x = offset.x;
|
|
59
70
|
this.y = offset.y;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
this.width = size.width;
|
|
72
|
+
this.height = size.height;
|
|
73
|
+
Validator.validateSizedElement(this);
|
|
74
|
+
return size;
|
|
75
|
+
}
|
|
76
|
+
computeSize(constraints, ctx) {
|
|
77
|
+
return this.sizeWith(constraints, ctx, "measure");
|
|
78
|
+
}
|
|
79
|
+
/** The one sizing path: `layout` places the child (relative to this box), `measure` only sizes it. */
|
|
80
|
+
sizeWith(constraints, ctx, mode) {
|
|
81
|
+
// Percentages resolve against the width we were OFFERED (a Box's: what the Box was offered), so
|
|
82
|
+
// every pass gets the same answer.
|
|
83
|
+
const [marginTop, marginRight, marginBottom, marginLeft] = resolveEdges(this.margin, this.percentBase(constraints.maxWidth, ctx));
|
|
84
|
+
// The child is inset by the margins: shifted down/right, narrowed by the horizontal margins, and
|
|
85
|
+
// left height-unbounded so it sizes to its own content - unless it cannot lay itself out without a
|
|
86
|
+
// bound (a stack holding a Spacer): that one gets the height inside the margins, as it would without
|
|
87
|
+
// the padding.
|
|
68
88
|
const childWidth = constraints.hasBoundedWidth
|
|
69
89
|
? Math.max(0, constraints.maxWidth - marginLeft - marginRight)
|
|
70
90
|
: Infinity;
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
//
|
|
81
|
-
return {
|
|
91
|
+
const childHeight = constraints.hasBoundedHeight && this.child.needsBoundedMain(false)
|
|
92
|
+
? Math.max(0, constraints.maxHeight - marginTop - marginBottom)
|
|
93
|
+
: Infinity;
|
|
94
|
+
const childConstraints = BoxConstraints.loose(childWidth, childHeight);
|
|
95
|
+
const childCtx = this.childContext(ctx);
|
|
96
|
+
const childSize = mode === "layout"
|
|
97
|
+
? this.child.calculateLayout(childConstraints, { x: marginLeft, y: marginTop }, childCtx)
|
|
98
|
+
: this.child.measure(childConstraints, childCtx);
|
|
99
|
+
// Padding takes the width it is offered; its height shrink-wraps the child. Unbounded width (a
|
|
100
|
+
// fixed child in a Row) shrink-wraps to the child + insets, as Container/Row do.
|
|
101
|
+
return {
|
|
102
|
+
width: constraints.hasBoundedWidth
|
|
103
|
+
? constraints.maxWidth
|
|
104
|
+
: childSize.width + marginLeft + marginRight,
|
|
105
|
+
height: childSize.height + marginTop + marginBottom,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
layoutChildren() {
|
|
109
|
+
return [this.child];
|
|
82
110
|
}
|
|
83
111
|
getProps() {
|
|
84
112
|
return {
|
|
@@ -10,7 +10,10 @@ import { LayoutContext, PDFElement } from "../pdf-element.js";
|
|
|
10
10
|
* too. A break wins over a `keepTogether` (a forced break cannot be avoided) - CSS behaves the same.
|
|
11
11
|
*/
|
|
12
12
|
export declare class PageBreakElement extends PDFElement {
|
|
13
|
-
|
|
13
|
+
/** The page it was last laid out on - only so an ineffective break can name it. */
|
|
14
|
+
page?: number;
|
|
15
|
+
calculateLayout(_constraints: BoxConstraints, _offset: Offset, ctx: LayoutContext): Size;
|
|
16
|
+
protected computeSize(): Size;
|
|
14
17
|
isPageBreak(): boolean;
|
|
15
18
|
hasForcedBreak(): boolean;
|
|
16
19
|
getProps(): Record<string, never>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PDFElement } from "../pdf-element.js";
|
|
2
|
+
import { pageOf } from "../../common/diagnostics.js";
|
|
2
3
|
/**
|
|
3
4
|
* A forced page break. Placed in a flow (a `Column`/`Row`/`Box`), it makes everything AFTER it start
|
|
4
5
|
* on a fresh page, no matter how much space is left. It takes zero space and draws nothing - the
|
|
@@ -9,7 +10,11 @@ import { PDFElement } from "../pdf-element.js";
|
|
|
9
10
|
* too. A break wins over a `keepTogether` (a forced break cannot be avoided) - CSS behaves the same.
|
|
10
11
|
*/
|
|
11
12
|
export class PageBreakElement extends PDFElement {
|
|
12
|
-
calculateLayout(_constraints, _offset,
|
|
13
|
+
calculateLayout(_constraints, _offset, ctx) {
|
|
14
|
+
this.page = pageOf(ctx);
|
|
15
|
+
return { width: 0, height: 0 };
|
|
16
|
+
}
|
|
17
|
+
computeSize() {
|
|
13
18
|
return { width: 0, height: 0 };
|
|
14
19
|
}
|
|
15
20
|
isPageBreak() {
|
|
@@ -26,6 +26,11 @@ export declare class PageBuilderElement extends PDFElement {
|
|
|
26
26
|
/** The real page info during the render pass; a provisional "1 of 1" while paginating. */
|
|
27
27
|
private infoFrom;
|
|
28
28
|
calculateLayout(constraints: BoxConstraints, offset: Offset, ctx: LayoutContext): Size;
|
|
29
|
+
/** It is built from the page it lands on. */
|
|
30
|
+
dependsOnPage(): boolean;
|
|
31
|
+
/** Builds a throwaway subtree to size it; only a real layout keeps what it built. */
|
|
32
|
+
protected computeSize(constraints: BoxConstraints, ctx: LayoutContext): Size;
|
|
33
|
+
layoutChildren(): readonly PDFElement[];
|
|
29
34
|
getProps(): {
|
|
30
35
|
composed: PDFElement | undefined;
|
|
31
36
|
};
|
|
@@ -36,9 +36,20 @@ export class PageBuilderElement extends PDFElement {
|
|
|
36
36
|
this.composed = this.build(this.infoFrom(ctx));
|
|
37
37
|
return this.composed.calculateLayout(constraints, offset, ctx);
|
|
38
38
|
}
|
|
39
|
+
/** It is built from the page it lands on. */
|
|
40
|
+
dependsOnPage() {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
/** Builds a throwaway subtree to size it; only a real layout keeps what it built. */
|
|
44
|
+
computeSize(constraints, ctx) {
|
|
45
|
+
return this.build(this.infoFrom(ctx)).measure(constraints, ctx);
|
|
46
|
+
}
|
|
39
47
|
// Named `composed` (not `child`) like DeferredElement: the pre-layout image walk keys on `child`, and
|
|
40
48
|
// this subtree does not exist yet when it runs. So an Image inside a PageBuilder skips aspect-ratio
|
|
41
49
|
// pre-resolution - give it both width and height, exactly as inside a Deferred/Table subtree.
|
|
50
|
+
layoutChildren() {
|
|
51
|
+
return this.composed ? [this.composed] : [];
|
|
52
|
+
}
|
|
42
53
|
getProps() {
|
|
43
54
|
return { composed: this.composed };
|
|
44
55
|
}
|
|
@@ -38,10 +38,22 @@ interface PositionedElementParams extends WithChild, PositionedInsets {
|
|
|
38
38
|
export declare class PositionedElement extends PDFElement {
|
|
39
39
|
private child;
|
|
40
40
|
private insets;
|
|
41
|
+
private placeCtx?;
|
|
41
42
|
constructor({ child, top, right, bottom, left, h, v, x, y }: PositionedElementParams);
|
|
42
43
|
calculateLayout(_constraints: BoxConstraints, _offset: Offset, ctx: LayoutContext): Size;
|
|
43
|
-
/**
|
|
44
|
-
|
|
44
|
+
/** Out of flow: it takes no room, and measuring registers nothing with the frame. */
|
|
45
|
+
protected computeSize(): Size;
|
|
46
|
+
layoutChildren(): readonly PDFElement[];
|
|
47
|
+
/**
|
|
48
|
+
* Lays the child out at the resolved position inside (or overflowing) a frame of `frameSize`. The
|
|
49
|
+
* offset is relative to the frame's top-left; its owner draws the child from there.
|
|
50
|
+
*/
|
|
51
|
+
placeIn(frameSize: Size, frameCtx: LayoutContext): void;
|
|
45
52
|
getProps(): WithChild;
|
|
46
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* The `Positioned` elements a frame owns, in tree order: every one below `roots`, including those
|
|
56
|
+
* inside another `Positioned`, but none below a nested frame - that one places its own.
|
|
57
|
+
*/
|
|
58
|
+
export declare function positionedIn(roots: readonly (PDFElement | undefined)[]): PositionedElement[];
|
|
47
59
|
export {};
|
|
@@ -24,12 +24,24 @@ export class PositionedElement extends PDFElement {
|
|
|
24
24
|
throw new Error("Positioned found no positioning frame. It must sit inside a Page (header, footer or body) " +
|
|
25
25
|
"or inside a Box({ relative: true }).");
|
|
26
26
|
}
|
|
27
|
-
//
|
|
28
|
-
|
|
27
|
+
// Out of flow: it takes no room here. The frame's owner places it once it knows its own size.
|
|
28
|
+
this.placeCtx = ctx;
|
|
29
29
|
return { width: 0, height: 0 };
|
|
30
30
|
}
|
|
31
|
-
/**
|
|
32
|
-
|
|
31
|
+
/** Out of flow: it takes no room, and measuring registers nothing with the frame. */
|
|
32
|
+
computeSize() {
|
|
33
|
+
return { width: 0, height: 0 };
|
|
34
|
+
}
|
|
35
|
+
layoutChildren() {
|
|
36
|
+
return [this.child];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Lays the child out at the resolved position inside (or overflowing) a frame of `frameSize`. The
|
|
40
|
+
* offset is relative to the frame's top-left; its owner draws the child from there.
|
|
41
|
+
*/
|
|
42
|
+
placeIn(frameSize, frameCtx) {
|
|
43
|
+
const ctx = this.placeCtx ?? frameCtx;
|
|
44
|
+
const frame = { origin: { x: 0, y: 0 }, size: frameSize };
|
|
33
45
|
const { top, right, bottom, left, h, v, x: nudgeX, y: nudgeY } = this.insets;
|
|
34
46
|
// An axis is PINNED (stretched) only when BOTH of its EDGES are given; otherwise the child
|
|
35
47
|
// shrink-wraps its content (unbounded), the CSS rule for an absolutely-positioned element. An
|
|
@@ -42,12 +54,7 @@ export class PositionedElement extends PDFElement {
|
|
|
42
54
|
: Infinity;
|
|
43
55
|
const constraints = BoxConstraints.loose(width, height);
|
|
44
56
|
// Measure first (so end/center anchors and right/bottom edges resolve against the child's size).
|
|
45
|
-
|
|
46
|
-
// out-of-flow child would otherwise register its placement on both passes.
|
|
47
|
-
const measureCtx = ctx.frame
|
|
48
|
-
? { ...ctx, frame: { ...ctx.frame, place: [] } }
|
|
49
|
-
: ctx;
|
|
50
|
-
const measured = this.child.calculateLayout(constraints, { x: 0, y: 0 }, measureCtx);
|
|
57
|
+
const measured = this.child.measure(constraints, ctx);
|
|
51
58
|
// Resolve one axis: a near-edge pins to origin, a far-edge pins to the far side; otherwise the
|
|
52
59
|
// anchor (default `start`) positions the child and the nudge shifts it from there.
|
|
53
60
|
const place = (origin, frameExtent, childExtent, nearEdge, farEdge, anchor, nudge) => {
|
|
@@ -71,3 +78,22 @@ export class PositionedElement extends PDFElement {
|
|
|
71
78
|
return { child: this.child };
|
|
72
79
|
}
|
|
73
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* The `Positioned` elements a frame owns, in tree order: every one below `roots`, including those
|
|
83
|
+
* inside another `Positioned`, but none below a nested frame - that one places its own.
|
|
84
|
+
*/
|
|
85
|
+
export function positionedIn(roots) {
|
|
86
|
+
const found = [];
|
|
87
|
+
const walk = (el) => {
|
|
88
|
+
if (el instanceof PositionedElement)
|
|
89
|
+
found.push(el);
|
|
90
|
+
if (el.isPositioningFrame())
|
|
91
|
+
return;
|
|
92
|
+
for (const child of el.layoutChildren())
|
|
93
|
+
walk(child);
|
|
94
|
+
};
|
|
95
|
+
for (const root of roots)
|
|
96
|
+
if (root)
|
|
97
|
+
walk(root);
|
|
98
|
+
return found;
|
|
99
|
+
}
|