@json-to-office/core-docx 1.0.0 → 1.1.0
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/components/visual.d.ts +6 -6
- package/dist/components/visual.d.ts.map +1 -1
- package/dist/core/desugarExternals.d.ts.map +1 -1
- package/dist/core/flattenVisuals.d.ts.map +1 -1
- package/dist/core/imageResources.d.ts.map +1 -1
- package/dist/core/prerasterizeVisuals.d.ts +10 -4
- package/dist/core/prerasterizeVisuals.d.ts.map +1 -1
- package/dist/index.js +963 -94
- package/dist/index.js.map +1 -1
- package/dist/ir/compiler.d.ts.map +1 -1
- package/dist/ir/features.d.ts +1 -1
- package/dist/ir/features.d.ts.map +1 -1
- package/dist/ir/nativeVisual.d.ts +79 -0
- package/dist/ir/nativeVisual.d.ts.map +1 -0
- package/dist/ir/types.d.ts +110 -1
- package/dist/ir/types.d.ts.map +1 -1
- package/dist/ir/units.d.ts +12 -0
- package/dist/ir/units.d.ts.map +1 -1
- package/dist/ir/validation.d.ts.map +1 -1
- package/dist/plugin/example/index.js +956 -92
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/renderers/docxjs/emit.d.ts.map +1 -1
- package/dist/renderers/docxjs/index.d.ts.map +1 -1
- package/dist/renderers/office-open/emit.d.ts +38 -6
- package/dist/renderers/office-open/emit.d.ts.map +1 -1
- package/dist/renderers/office-open/index.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -1977,6 +1977,12 @@ function pointsToEighthPoints(points) {
|
|
|
1977
1977
|
function inchesToTwips(inches) {
|
|
1978
1978
|
return Math.round(inches * TWIPS_PER_INCH);
|
|
1979
1979
|
}
|
|
1980
|
+
function inchesToEmu(inches) {
|
|
1981
|
+
return Math.round(inches * EMU_PER_INCH);
|
|
1982
|
+
}
|
|
1983
|
+
function pointsToEmu(points) {
|
|
1984
|
+
return Math.round(points * EMU_PER_INCH / 72);
|
|
1985
|
+
}
|
|
1980
1986
|
function twipsToEmu(twips) {
|
|
1981
1987
|
return Math.round(twips * EMU_PER_TWIP);
|
|
1982
1988
|
}
|
|
@@ -2179,6 +2185,10 @@ function inlineChildren(children, resources = /* @__PURE__ */ new Map()) {
|
|
|
2179
2185
|
case "shape":
|
|
2180
2186
|
out.push(emitShape(child, resources));
|
|
2181
2187
|
break;
|
|
2188
|
+
case "drawingGroup":
|
|
2189
|
+
throw new Error(
|
|
2190
|
+
"the docxjs renderer has no emitter for a drawing group; this document should have been refused by the capability check"
|
|
2191
|
+
);
|
|
2182
2192
|
case "noteReference":
|
|
2183
2193
|
out.push(
|
|
2184
2194
|
child.noteKind === "endnote" ? new EndnoteReferenceRun(child.id) : new FootnoteReferenceRun(child.id)
|
|
@@ -2280,7 +2290,7 @@ function paragraphOptions(formatting) {
|
|
|
2280
2290
|
const options = {};
|
|
2281
2291
|
if (!formatting) return options;
|
|
2282
2292
|
if (formatting.alignment) {
|
|
2283
|
-
options.alignment =
|
|
2293
|
+
options.alignment = ALIGNMENT2[formatting.alignment];
|
|
2284
2294
|
}
|
|
2285
2295
|
if (formatting.spacing) {
|
|
2286
2296
|
const spacing = {};
|
|
@@ -2514,11 +2524,11 @@ function emitBorder(border3) {
|
|
|
2514
2524
|
color: border3.color?.hex ?? "000000"
|
|
2515
2525
|
};
|
|
2516
2526
|
}
|
|
2517
|
-
var
|
|
2527
|
+
var ALIGNMENT2, PAGE_FIELD, WRAP_TYPE, VERTICAL_ALIGN, TABLE_ANCHOR, HORIZONTAL_POSITION, VERTICAL_POSITION, BORDER_STYLE;
|
|
2518
2528
|
var init_emit = __esm({
|
|
2519
2529
|
"src/renderers/docxjs/emit.ts"() {
|
|
2520
2530
|
"use strict";
|
|
2521
|
-
|
|
2531
|
+
ALIGNMENT2 = {
|
|
2522
2532
|
left: AlignmentType.LEFT,
|
|
2523
2533
|
center: AlignmentType.CENTER,
|
|
2524
2534
|
right: AlignmentType.RIGHT,
|
|
@@ -2641,7 +2651,7 @@ function paragraphProperties(formatting) {
|
|
|
2641
2651
|
out.spacing = spacing;
|
|
2642
2652
|
}
|
|
2643
2653
|
if (formatting.alignment !== void 0) {
|
|
2644
|
-
out.alignment =
|
|
2654
|
+
out.alignment = ALIGNMENT2[formatting.alignment] ?? formatting.alignment;
|
|
2645
2655
|
}
|
|
2646
2656
|
if (formatting.keepNext !== void 0) out.keepNext = formatting.keepNext;
|
|
2647
2657
|
if (formatting.keepLines !== void 0) out.keepLines = formatting.keepLines;
|
|
@@ -2770,6 +2780,15 @@ var init_features = __esm({
|
|
|
2770
2780
|
"text-frames",
|
|
2771
2781
|
/** Native shape text boxes. */
|
|
2772
2782
|
"text-boxes",
|
|
2783
|
+
/**
|
|
2784
|
+
* A DrawingML group: shapes, text boxes and pictures sharing one child
|
|
2785
|
+
* coordinate space, drawn as a single anchored or inline object.
|
|
2786
|
+
*
|
|
2787
|
+
* Separate from `text-boxes` because a lone `wps:wsp` run is a far smaller
|
|
2788
|
+
* ask than `wpg:wgp` with child transforms, preset geometry and grouped
|
|
2789
|
+
* pictures — a backend can plausibly have the first and not the second.
|
|
2790
|
+
*/
|
|
2791
|
+
"drawing-groups",
|
|
2773
2792
|
/** A table-of-contents field. */
|
|
2774
2793
|
"toc",
|
|
2775
2794
|
/** TOC entries baked in so an unrefreshed reader still shows them. */
|
|
@@ -3016,7 +3035,7 @@ function numberingConfig(numbering) {
|
|
|
3016
3035
|
level: level.level,
|
|
3017
3036
|
format: level.format,
|
|
3018
3037
|
text: level.text,
|
|
3019
|
-
alignment: level.alignment ?
|
|
3038
|
+
alignment: level.alignment ? ALIGNMENT2[level.alignment] : void 0,
|
|
3020
3039
|
...level.suffix ? { suffix: level.suffix } : {},
|
|
3021
3040
|
style: {
|
|
3022
3041
|
...level.indent ? {
|
|
@@ -3234,7 +3253,12 @@ var init_docxjs = __esm({
|
|
|
3234
3253
|
"cached-fields",
|
|
3235
3254
|
"shading",
|
|
3236
3255
|
"borders",
|
|
3237
|
-
"rtl"
|
|
3256
|
+
"rtl",
|
|
3257
|
+
// `drawing-groups` is the one exclusion that is a real backend gap rather
|
|
3258
|
+
// than a slice boundary: docx.js has no `wpg:wgp`. Leaving it out is what
|
|
3259
|
+
// turns a native `visual` sent to this backend into a named capability
|
|
3260
|
+
// error instead of a document with the graphic missing.
|
|
3261
|
+
"drawing-groups"
|
|
3238
3262
|
]);
|
|
3239
3263
|
DOCXJS_CAPABILITIES = new Set(
|
|
3240
3264
|
[...ALL_DOCX_FEATURES].filter((feature) => !NOT_YET_EMITTED.has(feature))
|
|
@@ -3345,15 +3369,15 @@ function inlineChildren2(children, ctx = emptyContext()) {
|
|
|
3345
3369
|
out.push({ bookmarkEnd: { id: child.id } });
|
|
3346
3370
|
break;
|
|
3347
3371
|
case "image": {
|
|
3348
|
-
const build = ctx.pictures.get(child.resourceId);
|
|
3349
|
-
if (!build) {
|
|
3350
|
-
throw new Error(
|
|
3351
|
-
`no image was prepared for resource "${child.resourceId}"`
|
|
3352
|
-
);
|
|
3353
|
-
}
|
|
3354
3372
|
const pending = breakOption();
|
|
3355
3373
|
if (pending.break) out.push(pending);
|
|
3356
|
-
out.push({ picture:
|
|
3374
|
+
out.push({ picture: pictureOptions(child, ctx) });
|
|
3375
|
+
break;
|
|
3376
|
+
}
|
|
3377
|
+
case "drawingGroup": {
|
|
3378
|
+
const pending = breakOption();
|
|
3379
|
+
if (pending.break) out.push(pending);
|
|
3380
|
+
out.push({ wpgGroup: drawingGroupOptions(child, ctx) });
|
|
3357
3381
|
break;
|
|
3358
3382
|
}
|
|
3359
3383
|
case "hyperlink":
|
|
@@ -3448,6 +3472,166 @@ function floatingOptions2(floating) {
|
|
|
3448
3472
|
zIndex: floating.zIndex
|
|
3449
3473
|
};
|
|
3450
3474
|
}
|
|
3475
|
+
function imageMedia(ctx, resourceId, placement) {
|
|
3476
|
+
const build = ctx.pictures.get(resourceId);
|
|
3477
|
+
if (!build) {
|
|
3478
|
+
throw new Error(`no image was prepared for resource "${resourceId}"`);
|
|
3479
|
+
}
|
|
3480
|
+
return build(placement);
|
|
3481
|
+
}
|
|
3482
|
+
function pictureOptions(image, ctx) {
|
|
3483
|
+
const media = imageMedia(ctx, image.resourceId, image);
|
|
3484
|
+
return {
|
|
3485
|
+
type: media.type,
|
|
3486
|
+
data: media.data,
|
|
3487
|
+
// No `fileName`: at run level the backend allocates one, and stating our
|
|
3488
|
+
// own would only fight it.
|
|
3489
|
+
...media.fallback ? { fallback: media.fallback } : {},
|
|
3490
|
+
// Raw numbers are EMUs in @office-open/docx. Passing pixels here makes a
|
|
3491
|
+
// normal image only a few hundred EMUs wide, effectively a dot.
|
|
3492
|
+
transformation: { width: image.widthEmu, height: image.heightEmu },
|
|
3493
|
+
// The id is stated rather than left to the backend's process-global
|
|
3494
|
+
// counter. `name` stays empty, which is what it was before and what the
|
|
3495
|
+
// backend falls back to.
|
|
3496
|
+
altText: { id: String(ctx.nextDrawingId()) },
|
|
3497
|
+
...image.floating ? { floating: floatingOptions2(image.floating) } : {}
|
|
3498
|
+
// No `description` or `title`: no DOCX this pipeline has produced carries
|
|
3499
|
+
// `wp:docPr` alt text, and the compiler warns so the gap is visible rather
|
|
3500
|
+
// than silent.
|
|
3501
|
+
};
|
|
3502
|
+
}
|
|
3503
|
+
function drawingGroupOptions(group, ctx) {
|
|
3504
|
+
const id = ctx.nextDrawingId();
|
|
3505
|
+
return {
|
|
3506
|
+
altText: {
|
|
3507
|
+
id: String(id),
|
|
3508
|
+
...group.altText ? { description: group.altText } : {}
|
|
3509
|
+
},
|
|
3510
|
+
transformation: { width: group.widthEmu, height: group.heightEmu },
|
|
3511
|
+
childOffset: { x: 0, y: 0 },
|
|
3512
|
+
childExtent: { cx: group.canvasWidthEmu, cy: group.canvasHeightEmu },
|
|
3513
|
+
children: group.children.map((child) => groupChild(child, ctx)),
|
|
3514
|
+
...group.floating ? { floating: floatingOptions2(group.floating) } : {}
|
|
3515
|
+
};
|
|
3516
|
+
}
|
|
3517
|
+
function groupChild(child, ctx) {
|
|
3518
|
+
return child.kind === "shape" ? groupShape(child, ctx) : groupPicture(child, ctx);
|
|
3519
|
+
}
|
|
3520
|
+
function groupShape(shape, ctx) {
|
|
3521
|
+
const id = ctx.nextDrawingId();
|
|
3522
|
+
return {
|
|
3523
|
+
type: "wps",
|
|
3524
|
+
transformation: childTransformation(shape.frame),
|
|
3525
|
+
data: {
|
|
3526
|
+
nonVisualProperties: {
|
|
3527
|
+
id,
|
|
3528
|
+
...shape.name ? { name: shape.name } : {},
|
|
3529
|
+
// `txBox="1"` is how Word tells a text box from a shape that happens
|
|
3530
|
+
// to hold text, and it changes how the object behaves on selection.
|
|
3531
|
+
...shape.isTextBox ? { textBox: "1" } : {}
|
|
3532
|
+
},
|
|
3533
|
+
presetGeometry: { preset: shape.geometry },
|
|
3534
|
+
...shape.fill ? { fill: drawingFill(shape.fill) } : {},
|
|
3535
|
+
...shape.outline ? { outline: drawingOutline(shape.outline) } : {},
|
|
3536
|
+
children: (shape.text?.paragraphs ?? []).map(
|
|
3537
|
+
(child) => paragraph(child, ctx)
|
|
3538
|
+
),
|
|
3539
|
+
...shape.text ? { bodyProperties: bodyProperties(shape.text) } : {}
|
|
3540
|
+
}
|
|
3541
|
+
};
|
|
3542
|
+
}
|
|
3543
|
+
function groupPicture(picture2, ctx) {
|
|
3544
|
+
const id = ctx.nextDrawingId();
|
|
3545
|
+
const media = imageMedia(ctx, picture2.resourceId, {
|
|
3546
|
+
widthEmu: picture2.frame.widthEmu,
|
|
3547
|
+
heightEmu: picture2.frame.heightEmu
|
|
3548
|
+
});
|
|
3549
|
+
return {
|
|
3550
|
+
type: media.type,
|
|
3551
|
+
data: media.data,
|
|
3552
|
+
fileName: media.fileName,
|
|
3553
|
+
...media.fallback ? {
|
|
3554
|
+
fallback: {
|
|
3555
|
+
...media.fallback,
|
|
3556
|
+
fileName: media.fallbackFileName
|
|
3557
|
+
}
|
|
3558
|
+
} : {},
|
|
3559
|
+
transformation: childTransformation(picture2.frame),
|
|
3560
|
+
nonVisualProperties: {
|
|
3561
|
+
id,
|
|
3562
|
+
...picture2.name ? { name: picture2.name } : {},
|
|
3563
|
+
...picture2.altText ? { description: picture2.altText } : {}
|
|
3564
|
+
},
|
|
3565
|
+
...picture2.crop ? { sourceRectangle: sourceRectangle(picture2.crop) } : {}
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
function childTransformation(frame) {
|
|
3569
|
+
const flip = {
|
|
3570
|
+
...frame.flipHorizontal ? { horizontal: true } : {},
|
|
3571
|
+
...frame.flipVertical ? { vertical: true } : {}
|
|
3572
|
+
};
|
|
3573
|
+
return {
|
|
3574
|
+
offset: {
|
|
3575
|
+
emus: { x: frame.xEmu, y: frame.yEmu },
|
|
3576
|
+
pixels: {
|
|
3577
|
+
x: Math.round(emuToPixels(frame.xEmu)),
|
|
3578
|
+
y: Math.round(emuToPixels(frame.yEmu))
|
|
3579
|
+
}
|
|
3580
|
+
},
|
|
3581
|
+
emus: { x: frame.widthEmu, y: frame.heightEmu },
|
|
3582
|
+
pixels: {
|
|
3583
|
+
x: Math.round(emuToPixels(frame.widthEmu)),
|
|
3584
|
+
y: Math.round(emuToPixels(frame.heightEmu))
|
|
3585
|
+
},
|
|
3586
|
+
// Degrees: the backend multiplies by 60000 on the way into `@rot`.
|
|
3587
|
+
...frame.rotationDegrees !== void 0 ? { rotation: frame.rotationDegrees } : {},
|
|
3588
|
+
...Object.keys(flip).length > 0 ? { flip } : {}
|
|
3589
|
+
};
|
|
3590
|
+
}
|
|
3591
|
+
function drawingFill(fill) {
|
|
3592
|
+
if (fill.kind === "none") return { type: "none" };
|
|
3593
|
+
return {
|
|
3594
|
+
type: "solid",
|
|
3595
|
+
color: {
|
|
3596
|
+
type: "rgb",
|
|
3597
|
+
value: fill.color.hex,
|
|
3598
|
+
// Transparency becomes an alpha transform on the colour. DrawingML
|
|
3599
|
+
// states *opacity*, so the value is the complement of what the author
|
|
3600
|
+
// wrote; the backend scales the percentage into `a:alpha`'s thousandths
|
|
3601
|
+
// itself, so it must be handed a plain percentage here.
|
|
3602
|
+
...fill.transparencyPercent !== void 0 ? { transforms: { alpha: 100 - fill.transparencyPercent } } : {}
|
|
3603
|
+
}
|
|
3604
|
+
};
|
|
3605
|
+
}
|
|
3606
|
+
function drawingOutline(outline) {
|
|
3607
|
+
return {
|
|
3608
|
+
...outline.widthEmu !== void 0 ? { width: outline.widthEmu } : {},
|
|
3609
|
+
...outline.dash ? { dash: outline.dash } : {},
|
|
3610
|
+
...outline.color ? { type: "solidFill", color: { value: outline.color.hex } } : {}
|
|
3611
|
+
};
|
|
3612
|
+
}
|
|
3613
|
+
function bodyProperties(text) {
|
|
3614
|
+
const insets = text.insetsEmu;
|
|
3615
|
+
return {
|
|
3616
|
+
...text.anchor ? { anchor: BODY_ANCHOR[text.anchor] } : {},
|
|
3617
|
+
// `lIns`/`tIns`/`rIns`/`bIns` is the vocabulary `a:bodyPr` actually has;
|
|
3618
|
+
// the backend also accepts a `margins` object and folds it into the same
|
|
3619
|
+
// attributes.
|
|
3620
|
+
...insets?.left !== void 0 ? { lIns: insets.left } : {},
|
|
3621
|
+
...insets?.top !== void 0 ? { tIns: insets.top } : {},
|
|
3622
|
+
...insets?.right !== void 0 ? { rIns: insets.right } : {},
|
|
3623
|
+
...insets?.bottom !== void 0 ? { bIns: insets.bottom } : {}
|
|
3624
|
+
};
|
|
3625
|
+
}
|
|
3626
|
+
function sourceRectangle(crop) {
|
|
3627
|
+
const thousandths = (fraction) => Math.round(fraction * 1e5);
|
|
3628
|
+
return {
|
|
3629
|
+
...crop.left !== void 0 ? { left: thousandths(crop.left) } : {},
|
|
3630
|
+
...crop.top !== void 0 ? { top: thousandths(crop.top) } : {},
|
|
3631
|
+
...crop.right !== void 0 ? { right: thousandths(crop.right) } : {},
|
|
3632
|
+
...crop.bottom !== void 0 ? { bottom: thousandths(crop.bottom) } : {}
|
|
3633
|
+
};
|
|
3634
|
+
}
|
|
3451
3635
|
function shapeOptions(shape, ctx) {
|
|
3452
3636
|
const id = String(ctx.nextDrawingId());
|
|
3453
3637
|
return {
|
|
@@ -3465,23 +3649,8 @@ function shapeOptions(shape, ctx) {
|
|
|
3465
3649
|
color: { type: "rgb", value: shape.fill.hex }
|
|
3466
3650
|
}
|
|
3467
3651
|
} : {},
|
|
3468
|
-
...shape.outline ? {
|
|
3469
|
-
|
|
3470
|
-
...shape.outline.widthEmu !== void 0 ? { width: shape.outline.widthEmu } : {},
|
|
3471
|
-
fill: {
|
|
3472
|
-
type: "solid",
|
|
3473
|
-
color: { type: "rgb", value: shape.outline.color.hex }
|
|
3474
|
-
}
|
|
3475
|
-
}
|
|
3476
|
-
} : {},
|
|
3477
|
-
...shape.insetsEmu ? {
|
|
3478
|
-
bodyProperties: {
|
|
3479
|
-
...shape.insetsEmu.top !== void 0 ? { topInset: shape.insetsEmu.top } : {},
|
|
3480
|
-
...shape.insetsEmu.bottom !== void 0 ? { bottomInset: shape.insetsEmu.bottom } : {},
|
|
3481
|
-
...shape.insetsEmu.left !== void 0 ? { leftInset: shape.insetsEmu.left } : {},
|
|
3482
|
-
...shape.insetsEmu.right !== void 0 ? { rightInset: shape.insetsEmu.right } : {}
|
|
3483
|
-
}
|
|
3484
|
-
} : {},
|
|
3652
|
+
...shape.outline ? { outline: drawingOutline(shape.outline) } : {},
|
|
3653
|
+
...shape.insetsEmu ? { bodyProperties: bodyProperties({ insetsEmu: shape.insetsEmu }) } : {},
|
|
3485
3654
|
...shape.floating ? { floating: floatingOptions2(shape.floating) } : {}
|
|
3486
3655
|
};
|
|
3487
3656
|
}
|
|
@@ -3838,7 +4007,7 @@ function numberingConfig2(numbering) {
|
|
|
3838
4007
|
}))
|
|
3839
4008
|
};
|
|
3840
4009
|
}
|
|
3841
|
-
var WRAP_TYPE2, TOC_PAGE_TAB_TWIPS;
|
|
4010
|
+
var WRAP_TYPE2, BODY_ANCHOR, TOC_PAGE_TAB_TWIPS;
|
|
3842
4011
|
var init_emit2 = __esm({
|
|
3843
4012
|
"src/renderers/office-open/emit.ts"() {
|
|
3844
4013
|
"use strict";
|
|
@@ -3849,6 +4018,11 @@ var init_emit2 = __esm({
|
|
|
3849
4018
|
tight: 2,
|
|
3850
4019
|
topAndBottom: 3
|
|
3851
4020
|
};
|
|
4021
|
+
BODY_ANCHOR = {
|
|
4022
|
+
top: "t",
|
|
4023
|
+
middle: "ctr",
|
|
4024
|
+
bottom: "b"
|
|
4025
|
+
};
|
|
3852
4026
|
TOC_PAGE_TAB_TWIPS = 9025;
|
|
3853
4027
|
}
|
|
3854
4028
|
});
|
|
@@ -4026,18 +4200,9 @@ async function prepareImages2(ir) {
|
|
|
4026
4200
|
index === 0 ? data : distinguishImageBytes(data, type, size)
|
|
4027
4201
|
);
|
|
4028
4202
|
});
|
|
4029
|
-
resources.set(resource.id, (
|
|
4030
|
-
const
|
|
4031
|
-
|
|
4032
|
-
height: emuToPixels(image.heightEmu)
|
|
4033
|
-
};
|
|
4034
|
-
const sizeKey = `${rasterSize.width}x${rasterSize.height}`;
|
|
4035
|
-
const transformation = {
|
|
4036
|
-
// Raw numbers are EMUs in @office-open/docx. Passing pixels here makes
|
|
4037
|
-
// a normal image only a few hundred EMUs wide, effectively a dot.
|
|
4038
|
-
width: image.widthEmu,
|
|
4039
|
-
height: image.heightEmu
|
|
4040
|
-
};
|
|
4203
|
+
resources.set(resource.id, (placement) => {
|
|
4204
|
+
const sizeKey = placementKey(placement);
|
|
4205
|
+
const stem = `${resource.id}-${sizeKey}`;
|
|
4041
4206
|
return {
|
|
4042
4207
|
type,
|
|
4043
4208
|
// @office-open/docx stores a drawing transformation on its deduplicated
|
|
@@ -4045,29 +4210,28 @@ async function prepareImages2(ir) {
|
|
|
4045
4210
|
// reuse the first size, so each distinct placement size gets equivalent
|
|
4046
4211
|
// image bytes carrying a harmless format-native marker.
|
|
4047
4212
|
data: placementData.get(sizeKey) ?? data,
|
|
4048
|
-
|
|
4049
|
-
//
|
|
4050
|
-
//
|
|
4051
|
-
|
|
4052
|
-
altText: { id: String(drawingId) },
|
|
4213
|
+
// Named after the resource and the size it is drawn at, so two
|
|
4214
|
+
// placements of one image at one size share a single part and a third
|
|
4215
|
+
// at another size gets its own.
|
|
4216
|
+
fileName: `${stem}.${type}`,
|
|
4053
4217
|
...type === "svg" ? {
|
|
4054
4218
|
// Word before 2016 draws the fallback rather than the vector. A
|
|
4055
4219
|
// raster that could not be produced falls back to the SVG bytes,
|
|
4056
4220
|
// which is what this pipeline has always shipped.
|
|
4057
4221
|
fallback: {
|
|
4058
4222
|
type: "png",
|
|
4059
|
-
data: rasters.get(`${
|
|
4060
|
-
}
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
// No `description` or `title`: no DOCX this pipeline has produced
|
|
4064
|
-
// carries `wp:docPr` alt text, and the compiler warns so the gap is
|
|
4065
|
-
// visible rather than silent.
|
|
4223
|
+
data: rasters.get(`${resource.id}:${sizeKey}`) ?? data
|
|
4224
|
+
},
|
|
4225
|
+
fallbackFileName: `${stem}-fallback.png`
|
|
4226
|
+
} : {}
|
|
4066
4227
|
};
|
|
4067
4228
|
});
|
|
4068
4229
|
}
|
|
4069
4230
|
return resources;
|
|
4070
4231
|
}
|
|
4232
|
+
function placementKey(placement) {
|
|
4233
|
+
return `${emuToPixels(placement.widthEmu)}x${emuToPixels(placement.heightEmu)}`;
|
|
4234
|
+
}
|
|
4071
4235
|
function distinguishImageBytes(data, mediaType, placement) {
|
|
4072
4236
|
const marker = Buffer.from(`json-to-office:${placement}`, "utf8");
|
|
4073
4237
|
switch (mediaType) {
|
|
@@ -4166,12 +4330,27 @@ function crc32(data) {
|
|
|
4166
4330
|
}
|
|
4167
4331
|
function collectImagePlacements2(ir) {
|
|
4168
4332
|
const placements = /* @__PURE__ */ new Map();
|
|
4333
|
+
const record = (resourceId, placement) => {
|
|
4334
|
+
const sizes = placements.get(resourceId) ?? /* @__PURE__ */ new Set();
|
|
4335
|
+
sizes.add(placementKey(placement));
|
|
4336
|
+
placements.set(resourceId, sizes);
|
|
4337
|
+
};
|
|
4169
4338
|
const visitInline = (inline) => {
|
|
4170
4339
|
if (inline.kind === "image") {
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4340
|
+
record(inline.resourceId, inline);
|
|
4341
|
+
return;
|
|
4342
|
+
}
|
|
4343
|
+
if (inline.kind === "drawingGroup") {
|
|
4344
|
+
for (const child of inline.children) {
|
|
4345
|
+
if (child.kind === "picture") {
|
|
4346
|
+
record(child.resourceId, {
|
|
4347
|
+
widthEmu: child.frame.widthEmu,
|
|
4348
|
+
heightEmu: child.frame.heightEmu
|
|
4349
|
+
});
|
|
4350
|
+
continue;
|
|
4351
|
+
}
|
|
4352
|
+
child.text?.paragraphs.forEach(visitBlock);
|
|
4353
|
+
}
|
|
4175
4354
|
return;
|
|
4176
4355
|
}
|
|
4177
4356
|
if (inline.kind === "hyperlink" || inline.kind === "revision") {
|
|
@@ -4556,6 +4735,9 @@ import {
|
|
|
4556
4735
|
DEFAULT_VISUAL_DPI,
|
|
4557
4736
|
MAX_RASTERIZE_BATCH_SLIDES
|
|
4558
4737
|
} from "@json-to-office/shared";
|
|
4738
|
+
import {
|
|
4739
|
+
isNativeVisualProps
|
|
4740
|
+
} from "@json-to-office/shared-docx";
|
|
4559
4741
|
|
|
4560
4742
|
// src/components/visual.ts
|
|
4561
4743
|
import { createHash } from "crypto";
|
|
@@ -4753,7 +4935,9 @@ function collectVisualProps(root) {
|
|
|
4753
4935
|
const obj = node;
|
|
4754
4936
|
if (typeof obj.name === "string" && obj.enabled === false) return;
|
|
4755
4937
|
if (obj.name === "visual" && obj.props && typeof obj.props === "object") {
|
|
4756
|
-
|
|
4938
|
+
if (!isNativeVisualProps(obj.props)) {
|
|
4939
|
+
found.push(obj.props);
|
|
4940
|
+
}
|
|
4757
4941
|
return;
|
|
4758
4942
|
}
|
|
4759
4943
|
for (const value of Object.values(obj)) visit(value);
|
|
@@ -5033,6 +5217,9 @@ import {
|
|
|
5033
5217
|
clampVisualDpi as clampVisualDpi2,
|
|
5034
5218
|
DEFAULT_VISUAL_DPI as DEFAULT_VISUAL_DPI2
|
|
5035
5219
|
} from "@json-to-office/shared";
|
|
5220
|
+
import {
|
|
5221
|
+
isNativeVisualProps as isNativeVisualProps2
|
|
5222
|
+
} from "@json-to-office/shared-docx";
|
|
5036
5223
|
|
|
5037
5224
|
// src/components/highcharts.ts
|
|
5038
5225
|
init_colorUtils();
|
|
@@ -5194,6 +5381,7 @@ async function desugarExternals(document, options) {
|
|
|
5194
5381
|
return transformComponents(document, async (node) => {
|
|
5195
5382
|
if (node.enabled === false) return void 0;
|
|
5196
5383
|
if (node.name === "visual") {
|
|
5384
|
+
if (isNativeVisualProps2(node.props)) return void 0;
|
|
5197
5385
|
return withNodeIdentity(node, {
|
|
5198
5386
|
name: "image",
|
|
5199
5387
|
props: await visualImageProps(
|
|
@@ -5246,6 +5434,9 @@ async function visualImageProps(props, prerastered, options) {
|
|
|
5246
5434
|
|
|
5247
5435
|
// src/core/imageResources.ts
|
|
5248
5436
|
init_imageUtils();
|
|
5437
|
+
import {
|
|
5438
|
+
isNativeVisualProps as isNativeVisualProps3
|
|
5439
|
+
} from "@json-to-office/shared-docx";
|
|
5249
5440
|
async function loadImageResources(components) {
|
|
5250
5441
|
const sources = /* @__PURE__ */ new Set();
|
|
5251
5442
|
for (const component of components) collectSources(component, sources);
|
|
@@ -5284,6 +5475,9 @@ function collectSources(component, out) {
|
|
|
5284
5475
|
const children = component.children;
|
|
5285
5476
|
for (const child of children ?? []) collectSources(child, out);
|
|
5286
5477
|
const props = component.props ?? {};
|
|
5478
|
+
if (component.name === "visual" && isNativeVisualProps3(props)) {
|
|
5479
|
+
collectNativeVisualSources(props, out);
|
|
5480
|
+
}
|
|
5287
5481
|
for (const key of ["header", "footer"]) {
|
|
5288
5482
|
const part = props[key];
|
|
5289
5483
|
if (Array.isArray(part)) {
|
|
@@ -5305,6 +5499,23 @@ function collectSources(component, out) {
|
|
|
5305
5499
|
}
|
|
5306
5500
|
}
|
|
5307
5501
|
}
|
|
5502
|
+
function collectNativeVisualSources(props, out) {
|
|
5503
|
+
const canvas = props.canvas;
|
|
5504
|
+
const background = canvas?.background?.image;
|
|
5505
|
+
if (background) {
|
|
5506
|
+
const source = resolveImageSource(background);
|
|
5507
|
+
if (source) out.add(source);
|
|
5508
|
+
}
|
|
5509
|
+
const elements = props.elements;
|
|
5510
|
+
if (!Array.isArray(elements)) return;
|
|
5511
|
+
for (const element of elements) {
|
|
5512
|
+
if (!element || element.name !== "image") continue;
|
|
5513
|
+
const source = resolveImageSource(
|
|
5514
|
+
element.props ?? {}
|
|
5515
|
+
);
|
|
5516
|
+
if (source) out.add(source);
|
|
5517
|
+
}
|
|
5518
|
+
}
|
|
5308
5519
|
function collectCellSource(content, out) {
|
|
5309
5520
|
if (content && typeof content === "object") {
|
|
5310
5521
|
collectSources(content, out);
|
|
@@ -5317,6 +5528,516 @@ import {
|
|
|
5317
5528
|
FeatureRequirementCollector
|
|
5318
5529
|
} from "@json-to-office/shared/rendering";
|
|
5319
5530
|
import { synthesizeFamilyName } from "@json-to-office/shared";
|
|
5531
|
+
import {
|
|
5532
|
+
isNativeVisualProps as isNativeVisualProps4
|
|
5533
|
+
} from "@json-to-office/shared-docx";
|
|
5534
|
+
|
|
5535
|
+
// src/ir/nativeVisual.ts
|
|
5536
|
+
init_units();
|
|
5537
|
+
init_imageUtils();
|
|
5538
|
+
var PIXELS_PER_INCH2 = 96;
|
|
5539
|
+
var DEFAULT_WIDTH_FRACTION = 0.75;
|
|
5540
|
+
var ASSUMED_FONT_SIZE_POINTS = 18;
|
|
5541
|
+
var MIN_DERIVED_TEXT_HEIGHT_INCHES = 0.5;
|
|
5542
|
+
var DERIVED_LINE_HEIGHT_RATIO = 1.6;
|
|
5543
|
+
var GEOMETRY_ALIASES = {
|
|
5544
|
+
arrow: "rightArrow",
|
|
5545
|
+
lightning: "lightningBolt"
|
|
5546
|
+
};
|
|
5547
|
+
var DASH_VALUES = /* @__PURE__ */ new Set([
|
|
5548
|
+
"solid",
|
|
5549
|
+
"dash",
|
|
5550
|
+
"dot",
|
|
5551
|
+
"dashDot"
|
|
5552
|
+
]);
|
|
5553
|
+
var ANCHOR = {
|
|
5554
|
+
top: "top",
|
|
5555
|
+
middle: "middle",
|
|
5556
|
+
bottom: "bottom"
|
|
5557
|
+
};
|
|
5558
|
+
var ALIGNMENT = {
|
|
5559
|
+
left: "left",
|
|
5560
|
+
center: "center",
|
|
5561
|
+
right: "right",
|
|
5562
|
+
justify: "justified"
|
|
5563
|
+
};
|
|
5564
|
+
function compileNativeVisualGroup(props, outer) {
|
|
5565
|
+
const canvas = {
|
|
5566
|
+
widthEmu: inchesToEmu(props.canvas.width),
|
|
5567
|
+
heightEmu: inchesToEmu(props.canvas.height)
|
|
5568
|
+
};
|
|
5569
|
+
const children = [];
|
|
5570
|
+
let refused = false;
|
|
5571
|
+
const deps = {
|
|
5572
|
+
...outer,
|
|
5573
|
+
reject: (detail) => {
|
|
5574
|
+
refused = true;
|
|
5575
|
+
outer.reject(detail);
|
|
5576
|
+
}
|
|
5577
|
+
};
|
|
5578
|
+
const background = props.canvas.background;
|
|
5579
|
+
if (background?.color) {
|
|
5580
|
+
const color = deps.color(background.color);
|
|
5581
|
+
if (!color) {
|
|
5582
|
+
deps.reject(`canvas.background.color "${background.color}"`);
|
|
5583
|
+
} else {
|
|
5584
|
+
children.push({
|
|
5585
|
+
kind: "shape",
|
|
5586
|
+
frame: fullBleed(canvas),
|
|
5587
|
+
geometry: "rect",
|
|
5588
|
+
fill: { kind: "solid", color },
|
|
5589
|
+
name: "Canvas background"
|
|
5590
|
+
});
|
|
5591
|
+
}
|
|
5592
|
+
}
|
|
5593
|
+
if (background?.image) {
|
|
5594
|
+
const source = resolveImageSource(background.image);
|
|
5595
|
+
const resource = source ? deps.picture(source) : void 0;
|
|
5596
|
+
if (!resource) {
|
|
5597
|
+
deps.reject("canvas.background.image could not be loaded");
|
|
5598
|
+
} else {
|
|
5599
|
+
children.push({
|
|
5600
|
+
kind: "picture",
|
|
5601
|
+
frame: fullBleed(canvas),
|
|
5602
|
+
resourceId: resource.resourceId,
|
|
5603
|
+
name: "Canvas background"
|
|
5604
|
+
});
|
|
5605
|
+
}
|
|
5606
|
+
}
|
|
5607
|
+
for (const [index, element] of (props.elements ?? []).entries()) {
|
|
5608
|
+
if (element.enabled === false) continue;
|
|
5609
|
+
const child = compileElement(element, index, canvas, deps);
|
|
5610
|
+
if (child) children.push(child);
|
|
5611
|
+
}
|
|
5612
|
+
return refused ? void 0 : { canvas, children };
|
|
5613
|
+
}
|
|
5614
|
+
function compileElement(element, index, canvas, deps) {
|
|
5615
|
+
const at = `elements[${index}]`;
|
|
5616
|
+
switch (element.name) {
|
|
5617
|
+
case "text":
|
|
5618
|
+
return compileText(element.props, at, canvas, deps);
|
|
5619
|
+
case "shape":
|
|
5620
|
+
return compileShape(element.props, at, canvas, deps);
|
|
5621
|
+
case "image":
|
|
5622
|
+
return compileImage(element.props, at, canvas, deps);
|
|
5623
|
+
default:
|
|
5624
|
+
deps.reject(`${at} is a "${element.name}"`);
|
|
5625
|
+
return void 0;
|
|
5626
|
+
}
|
|
5627
|
+
}
|
|
5628
|
+
function compileText(props, at, canvas, deps) {
|
|
5629
|
+
const runs = textRuns(props);
|
|
5630
|
+
if (!runs) {
|
|
5631
|
+
deps.warn(
|
|
5632
|
+
`[core-docx] native visual ${at} has neither "text" nor "runs"; nothing was drawn for it.`
|
|
5633
|
+
);
|
|
5634
|
+
return void 0;
|
|
5635
|
+
}
|
|
5636
|
+
const colors = resolveColors(
|
|
5637
|
+
[
|
|
5638
|
+
["color", props.color],
|
|
5639
|
+
["fill.color", props.fill?.color],
|
|
5640
|
+
...runs.map((run, i) => [`runs[${i}].color`, run.color]),
|
|
5641
|
+
...runs.map(
|
|
5642
|
+
(run, i) => [
|
|
5643
|
+
`runs[${i}].underline.color`,
|
|
5644
|
+
underlineColor(run.underline)
|
|
5645
|
+
]
|
|
5646
|
+
),
|
|
5647
|
+
["underline.color", underlineColor(props.underline)]
|
|
5648
|
+
],
|
|
5649
|
+
at,
|
|
5650
|
+
deps
|
|
5651
|
+
);
|
|
5652
|
+
if (!colors) return void 0;
|
|
5653
|
+
const frame = resolveFrame(props, canvas, {
|
|
5654
|
+
defaultHeightInches: derivedTextHeightInches(props, runs)
|
|
5655
|
+
});
|
|
5656
|
+
const paragraphs = textParagraphs(runs, props, colors, at);
|
|
5657
|
+
return {
|
|
5658
|
+
kind: "shape",
|
|
5659
|
+
frame,
|
|
5660
|
+
geometry: "rect",
|
|
5661
|
+
isTextBox: true,
|
|
5662
|
+
// A text box with no fill is transparent, which is what the rasterized
|
|
5663
|
+
// path draws; saying so explicitly stops Word applying its own default.
|
|
5664
|
+
fill: props.fill?.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" },
|
|
5665
|
+
text: {
|
|
5666
|
+
paragraphs,
|
|
5667
|
+
// pptx anchors a text box at the top unless told otherwise, and a
|
|
5668
|
+
// drawing that changes anchor between render modes moves its text.
|
|
5669
|
+
anchor: ANCHOR[props.valign ?? "top"] ?? "top",
|
|
5670
|
+
// A text box's insets default to nothing, again matching pptx. A shape
|
|
5671
|
+
// deliberately leaves them unstated so OOXML's own defaults apply.
|
|
5672
|
+
insetsEmu: marginInsets(props.margin) ?? ZERO_INSETS
|
|
5673
|
+
},
|
|
5674
|
+
name: `Text ${at}`
|
|
5675
|
+
};
|
|
5676
|
+
}
|
|
5677
|
+
var ZERO_INSETS = { top: 0, bottom: 0, left: 0, right: 0 };
|
|
5678
|
+
function textRuns(props) {
|
|
5679
|
+
if (props.runs?.length) return props.runs;
|
|
5680
|
+
if (props.text === void 0) return void 0;
|
|
5681
|
+
return [{ text: props.text }];
|
|
5682
|
+
}
|
|
5683
|
+
function textParagraphs(runs, props, colors, at) {
|
|
5684
|
+
const paragraphs = [];
|
|
5685
|
+
let current = [];
|
|
5686
|
+
const flush = () => {
|
|
5687
|
+
paragraphs.push({
|
|
5688
|
+
kind: "paragraph",
|
|
5689
|
+
id: `${at}.p${paragraphs.length}`,
|
|
5690
|
+
path: `${at}.paragraphs[${paragraphs.length}]`,
|
|
5691
|
+
children: current,
|
|
5692
|
+
formatting: {
|
|
5693
|
+
...props.align ? { alignment: ALIGNMENT[props.align] } : {},
|
|
5694
|
+
// A drawing's text is set flush against the shape; the document's
|
|
5695
|
+
// paragraph spacing would push it away from the top edge, which is not
|
|
5696
|
+
// what an absolutely-placed box means.
|
|
5697
|
+
spacing: { beforeTwips: 0, afterTwips: 0 }
|
|
5698
|
+
}
|
|
5699
|
+
});
|
|
5700
|
+
current = [];
|
|
5701
|
+
};
|
|
5702
|
+
runs.forEach((run, index) => {
|
|
5703
|
+
const formatting = runFormatting(run, props, colors, index);
|
|
5704
|
+
const lines = run.text.split("\n");
|
|
5705
|
+
lines.forEach((line, lineIndex) => {
|
|
5706
|
+
if (lineIndex > 0) current.push({ kind: "lineBreak" });
|
|
5707
|
+
if (line) {
|
|
5708
|
+
current.push({ kind: "text", text: line, ...formatting });
|
|
5709
|
+
}
|
|
5710
|
+
});
|
|
5711
|
+
if (run.breakLine && index < runs.length - 1) flush();
|
|
5712
|
+
});
|
|
5713
|
+
flush();
|
|
5714
|
+
return paragraphs;
|
|
5715
|
+
}
|
|
5716
|
+
function runFormatting(run, props, colors, index) {
|
|
5717
|
+
const fontFamily = run.fontFace ?? props.fontFace;
|
|
5718
|
+
const sizePoints = run.fontSize ?? props.fontSize;
|
|
5719
|
+
const color = colors.get(`runs[${index}].color`) ?? (run.color === void 0 ? colors.get("color") : void 0);
|
|
5720
|
+
const bold = run.bold ?? props.bold;
|
|
5721
|
+
const italic = run.italic ?? props.italic;
|
|
5722
|
+
const strike = run.strike ?? props.strike;
|
|
5723
|
+
const underline = compileUnderline(
|
|
5724
|
+
run.underline ?? props.underline,
|
|
5725
|
+
colors.get(
|
|
5726
|
+
run.underline !== void 0 ? `runs[${index}].underline.color` : "underline.color"
|
|
5727
|
+
)
|
|
5728
|
+
);
|
|
5729
|
+
const formatting = {
|
|
5730
|
+
...fontFamily ? { fontFamily } : {},
|
|
5731
|
+
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
5732
|
+
...color ? { color } : {},
|
|
5733
|
+
...bold !== void 0 ? { bold } : {},
|
|
5734
|
+
...italic !== void 0 ? { italic } : {},
|
|
5735
|
+
...strike !== void 0 ? { strike } : {},
|
|
5736
|
+
...underline ? { underline } : {}
|
|
5737
|
+
};
|
|
5738
|
+
return Object.keys(formatting).length > 0 ? { formatting } : {};
|
|
5739
|
+
}
|
|
5740
|
+
var UNDERLINE_TYPES = {
|
|
5741
|
+
sng: "single",
|
|
5742
|
+
dbl: "double",
|
|
5743
|
+
dash: "dash",
|
|
5744
|
+
dotted: "dotted"
|
|
5745
|
+
};
|
|
5746
|
+
function compileUnderline(value, color) {
|
|
5747
|
+
if (value === void 0 || value === false) return void 0;
|
|
5748
|
+
const style = value === true ? "sng" : value.style ?? "sng";
|
|
5749
|
+
return {
|
|
5750
|
+
type: UNDERLINE_TYPES[style] ?? "single",
|
|
5751
|
+
...color ? { color } : {}
|
|
5752
|
+
};
|
|
5753
|
+
}
|
|
5754
|
+
function underlineColor(value) {
|
|
5755
|
+
return typeof value === "object" ? value.color : void 0;
|
|
5756
|
+
}
|
|
5757
|
+
function derivedTextHeightInches(props, runs) {
|
|
5758
|
+
const fontSize = props.fontSize ?? ASSUMED_FONT_SIZE_POINTS;
|
|
5759
|
+
const lineCount = runs.reduce(
|
|
5760
|
+
(total, run) => total + (run.breakLine ? 1 : 0) + (run.text.match(/\n/g)?.length ?? 0),
|
|
5761
|
+
1
|
|
5762
|
+
);
|
|
5763
|
+
return Math.max(
|
|
5764
|
+
MIN_DERIVED_TEXT_HEIGHT_INCHES,
|
|
5765
|
+
fontSize / 72 * DERIVED_LINE_HEIGHT_RATIO * lineCount
|
|
5766
|
+
);
|
|
5767
|
+
}
|
|
5768
|
+
function compileShape(props, at, canvas, deps) {
|
|
5769
|
+
const segments = shapeSegments(props);
|
|
5770
|
+
const colors = resolveColors(
|
|
5771
|
+
[
|
|
5772
|
+
["fill.color", props.fill?.color],
|
|
5773
|
+
["line.color", props.line?.color],
|
|
5774
|
+
["fontColor", props.fontColor],
|
|
5775
|
+
...segments.map(
|
|
5776
|
+
(segment, i) => [`text[${i}].color`, segment.color]
|
|
5777
|
+
)
|
|
5778
|
+
],
|
|
5779
|
+
at,
|
|
5780
|
+
deps
|
|
5781
|
+
);
|
|
5782
|
+
if (!colors) return void 0;
|
|
5783
|
+
const frame = resolveFrame(props, canvas, { defaultHeightInches: 0 });
|
|
5784
|
+
if (props.flipH) frame.flipHorizontal = true;
|
|
5785
|
+
if (props.flipV) frame.flipVertical = true;
|
|
5786
|
+
const dash = props.line?.dashType;
|
|
5787
|
+
if (dash !== void 0 && !DASH_VALUES.has(dash)) {
|
|
5788
|
+
deps.reject(`${at}.line.dashType "${dash}"`);
|
|
5789
|
+
return void 0;
|
|
5790
|
+
}
|
|
5791
|
+
const outline = props.line ? {
|
|
5792
|
+
...colors.get("line.color") ? { color: colors.get("line.color") } : {},
|
|
5793
|
+
...props.line.width !== void 0 ? { widthEmu: pointsToEmu(props.line.width) } : {},
|
|
5794
|
+
...dash && dash !== "solid" ? { dash } : {}
|
|
5795
|
+
} : void 0;
|
|
5796
|
+
const text = segments.length ? {
|
|
5797
|
+
paragraphs: shapeParagraphs(segments, props, colors, at),
|
|
5798
|
+
anchor: ANCHOR[props.valign ?? "middle"] ?? "middle",
|
|
5799
|
+
// Unstated insets are left unstated so OOXML's own shape defaults
|
|
5800
|
+
// apply, which is what the raster path draws.
|
|
5801
|
+
...marginInsets(props.margin) ? { insetsEmu: marginInsets(props.margin) } : {}
|
|
5802
|
+
} : void 0;
|
|
5803
|
+
return {
|
|
5804
|
+
kind: "shape",
|
|
5805
|
+
frame,
|
|
5806
|
+
geometry: GEOMETRY_ALIASES[props.type] ?? props.type,
|
|
5807
|
+
...props.fill ? {
|
|
5808
|
+
fill: props.fill.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" }
|
|
5809
|
+
} : {},
|
|
5810
|
+
...outline && Object.keys(outline).length > 0 ? { outline } : {},
|
|
5811
|
+
...text ? { text } : {},
|
|
5812
|
+
name: `Shape ${at}`
|
|
5813
|
+
};
|
|
5814
|
+
}
|
|
5815
|
+
function shapeSegments(props) {
|
|
5816
|
+
if (props.text === void 0) return [];
|
|
5817
|
+
if (typeof props.text === "string") {
|
|
5818
|
+
return props.text ? [{ text: props.text }] : [];
|
|
5819
|
+
}
|
|
5820
|
+
return props.text;
|
|
5821
|
+
}
|
|
5822
|
+
function shapeParagraphs(segments, props, colors, at) {
|
|
5823
|
+
const paragraphs = [];
|
|
5824
|
+
let current = [];
|
|
5825
|
+
const flush = () => {
|
|
5826
|
+
paragraphs.push({
|
|
5827
|
+
kind: "paragraph",
|
|
5828
|
+
id: `${at}.p${paragraphs.length}`,
|
|
5829
|
+
path: `${at}.paragraphs[${paragraphs.length}]`,
|
|
5830
|
+
children: current,
|
|
5831
|
+
formatting: {
|
|
5832
|
+
// A shape centres its text unless told otherwise, which is what the
|
|
5833
|
+
// rasterized shape draws.
|
|
5834
|
+
alignment: props.align ? ALIGNMENT[props.align] : "center",
|
|
5835
|
+
spacing: { beforeTwips: 0, afterTwips: 0 }
|
|
5836
|
+
}
|
|
5837
|
+
});
|
|
5838
|
+
current = [];
|
|
5839
|
+
};
|
|
5840
|
+
segments.forEach((segment, index) => {
|
|
5841
|
+
const fontFamily = segment.fontFace ?? props.fontFace;
|
|
5842
|
+
const sizePoints = segment.fontSize ?? props.fontSize;
|
|
5843
|
+
const color = colors.get(`text[${index}].color`) ?? (segment.color === void 0 ? colors.get("fontColor") : void 0);
|
|
5844
|
+
const bold = segment.bold ?? props.bold;
|
|
5845
|
+
const italic = segment.italic ?? props.italic;
|
|
5846
|
+
const formatting = {
|
|
5847
|
+
...fontFamily ? { fontFamily } : {},
|
|
5848
|
+
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
5849
|
+
...color ? { color } : {},
|
|
5850
|
+
...bold !== void 0 ? { bold } : {},
|
|
5851
|
+
...italic !== void 0 ? { italic } : {}
|
|
5852
|
+
};
|
|
5853
|
+
const wrapped = Object.keys(formatting).length > 0 ? { formatting } : void 0;
|
|
5854
|
+
segment.text.split("\n").forEach((line, lineIndex) => {
|
|
5855
|
+
if (lineIndex > 0) current.push({ kind: "lineBreak" });
|
|
5856
|
+
if (line) current.push({ kind: "text", text: line, ...wrapped });
|
|
5857
|
+
});
|
|
5858
|
+
if (segment.breakLine && index < segments.length - 1) flush();
|
|
5859
|
+
});
|
|
5860
|
+
flush();
|
|
5861
|
+
return paragraphs;
|
|
5862
|
+
}
|
|
5863
|
+
function compileImage(props, at, canvas, deps) {
|
|
5864
|
+
const source = resolveImageSource(props);
|
|
5865
|
+
if (!source) {
|
|
5866
|
+
deps.reject(`${at} has none of "path", "base64" or "svg"`);
|
|
5867
|
+
return void 0;
|
|
5868
|
+
}
|
|
5869
|
+
const resource = deps.picture(source);
|
|
5870
|
+
if (!resource) {
|
|
5871
|
+
deps.reject(`${at} image could not be loaded`);
|
|
5872
|
+
return void 0;
|
|
5873
|
+
}
|
|
5874
|
+
const aspect = resource.intrinsic ? resource.intrinsic.width / resource.intrinsic.height : void 0;
|
|
5875
|
+
const intrinsicInches = resource.intrinsic ? {
|
|
5876
|
+
width: resource.intrinsic.width / PIXELS_PER_INCH2,
|
|
5877
|
+
height: resource.intrinsic.height / PIXELS_PER_INCH2
|
|
5878
|
+
} : void 0;
|
|
5879
|
+
const box = resolveImageBox(props, canvas, aspect, intrinsicInches);
|
|
5880
|
+
const sizing = props.sizing;
|
|
5881
|
+
if (!sizing || !aspect) {
|
|
5882
|
+
if (sizing && !aspect) {
|
|
5883
|
+
deps.warn(
|
|
5884
|
+
`[core-docx] native visual ${at} asks for "${sizing.type}" sizing, but the image's stored size could not be read; it was stretched to its box instead.`
|
|
5885
|
+
);
|
|
5886
|
+
}
|
|
5887
|
+
return picture(box, props, resource, at);
|
|
5888
|
+
}
|
|
5889
|
+
const boxAspect = box.widthEmu / box.heightEmu;
|
|
5890
|
+
if (sizing.type === "contain") {
|
|
5891
|
+
const fitted = boxAspect > aspect ? {
|
|
5892
|
+
widthEmu: Math.round(box.heightEmu * aspect),
|
|
5893
|
+
heightEmu: box.heightEmu
|
|
5894
|
+
} : {
|
|
5895
|
+
widthEmu: box.widthEmu,
|
|
5896
|
+
heightEmu: Math.round(box.widthEmu / aspect)
|
|
5897
|
+
};
|
|
5898
|
+
return picture(
|
|
5899
|
+
{
|
|
5900
|
+
...box,
|
|
5901
|
+
xEmu: box.xEmu + Math.round((box.widthEmu - fitted.widthEmu) / 2),
|
|
5902
|
+
yEmu: box.yEmu + Math.round((box.heightEmu - fitted.heightEmu) / 2),
|
|
5903
|
+
...fitted
|
|
5904
|
+
},
|
|
5905
|
+
props,
|
|
5906
|
+
resource,
|
|
5907
|
+
at
|
|
5908
|
+
);
|
|
5909
|
+
}
|
|
5910
|
+
const visible = boxAspect > aspect ? { widthFraction: 1, heightFraction: aspect / boxAspect } : { widthFraction: boxAspect / aspect, heightFraction: 1 };
|
|
5911
|
+
const crop = sizing.type === "cover" ? {
|
|
5912
|
+
...visible.widthFraction < 1 ? {
|
|
5913
|
+
left: (1 - visible.widthFraction) / 2,
|
|
5914
|
+
right: (1 - visible.widthFraction) / 2
|
|
5915
|
+
} : {},
|
|
5916
|
+
...visible.heightFraction < 1 ? {
|
|
5917
|
+
top: (1 - visible.heightFraction) / 2,
|
|
5918
|
+
bottom: (1 - visible.heightFraction) / 2
|
|
5919
|
+
} : {}
|
|
5920
|
+
} : {
|
|
5921
|
+
...visible.widthFraction < 1 ? { right: 1 - visible.widthFraction } : {},
|
|
5922
|
+
...visible.heightFraction < 1 ? { bottom: 1 - visible.heightFraction } : {}
|
|
5923
|
+
};
|
|
5924
|
+
return picture(box, props, resource, at, crop);
|
|
5925
|
+
}
|
|
5926
|
+
function picture(frame, props, resource, at, crop) {
|
|
5927
|
+
return {
|
|
5928
|
+
kind: "picture",
|
|
5929
|
+
frame,
|
|
5930
|
+
resourceId: resource.resourceId,
|
|
5931
|
+
...props.alt ? { altText: props.alt } : {},
|
|
5932
|
+
...crop && Object.keys(crop).length > 0 ? { crop } : {},
|
|
5933
|
+
name: `Image ${at}`
|
|
5934
|
+
};
|
|
5935
|
+
}
|
|
5936
|
+
function resolveImageBox(props, canvas, aspect, intrinsicInches) {
|
|
5937
|
+
const width = props.sizing?.w ?? props.w;
|
|
5938
|
+
const height = props.sizing?.h ?? props.h;
|
|
5939
|
+
const widthEmu = width !== void 0 ? resolveExtent(width, canvas.widthEmu) : void 0;
|
|
5940
|
+
const heightEmu = height !== void 0 ? resolveExtent(height, canvas.heightEmu) : void 0;
|
|
5941
|
+
const resolved = (() => {
|
|
5942
|
+
if (widthEmu !== void 0 && heightEmu !== void 0) {
|
|
5943
|
+
return { widthEmu, heightEmu };
|
|
5944
|
+
}
|
|
5945
|
+
if (widthEmu !== void 0) {
|
|
5946
|
+
return {
|
|
5947
|
+
widthEmu,
|
|
5948
|
+
heightEmu: aspect ? Math.round(widthEmu / aspect) : Math.round(widthEmu * (3 / 4))
|
|
5949
|
+
};
|
|
5950
|
+
}
|
|
5951
|
+
if (heightEmu !== void 0) {
|
|
5952
|
+
return {
|
|
5953
|
+
widthEmu: aspect ? Math.round(heightEmu * aspect) : Math.round(heightEmu * (4 / 3)),
|
|
5954
|
+
heightEmu
|
|
5955
|
+
};
|
|
5956
|
+
}
|
|
5957
|
+
if (intrinsicInches) {
|
|
5958
|
+
return {
|
|
5959
|
+
widthEmu: inchesToEmu(intrinsicInches.width),
|
|
5960
|
+
heightEmu: inchesToEmu(intrinsicInches.height)
|
|
5961
|
+
};
|
|
5962
|
+
}
|
|
5963
|
+
const fallbackWidth = Math.round(canvas.widthEmu * DEFAULT_WIDTH_FRACTION);
|
|
5964
|
+
return {
|
|
5965
|
+
widthEmu: fallbackWidth,
|
|
5966
|
+
heightEmu: Math.round(fallbackWidth * (3 / 4))
|
|
5967
|
+
};
|
|
5968
|
+
})();
|
|
5969
|
+
return {
|
|
5970
|
+
xEmu: props.x !== void 0 ? resolveOffset(props.x, canvas.widthEmu) : 0,
|
|
5971
|
+
yEmu: props.y !== void 0 ? resolveOffset(props.y, canvas.heightEmu) : 0,
|
|
5972
|
+
...resolved,
|
|
5973
|
+
...rotation(props.rotate)
|
|
5974
|
+
};
|
|
5975
|
+
}
|
|
5976
|
+
function fullBleed(canvas) {
|
|
5977
|
+
return {
|
|
5978
|
+
xEmu: 0,
|
|
5979
|
+
yEmu: 0,
|
|
5980
|
+
widthEmu: canvas.widthEmu,
|
|
5981
|
+
heightEmu: canvas.heightEmu
|
|
5982
|
+
};
|
|
5983
|
+
}
|
|
5984
|
+
function resolveFrame(props, canvas, options) {
|
|
5985
|
+
return {
|
|
5986
|
+
xEmu: props.x !== void 0 ? resolveOffset(props.x, canvas.widthEmu) : 0,
|
|
5987
|
+
yEmu: props.y !== void 0 ? resolveOffset(props.y, canvas.heightEmu) : 0,
|
|
5988
|
+
widthEmu: props.w !== void 0 ? resolveExtent(props.w, canvas.widthEmu) : Math.round(canvas.widthEmu * DEFAULT_WIDTH_FRACTION),
|
|
5989
|
+
heightEmu: props.h !== void 0 ? resolveExtent(props.h, canvas.heightEmu) : inchesToEmu(options.defaultHeightInches),
|
|
5990
|
+
...rotation(props.rotate)
|
|
5991
|
+
};
|
|
5992
|
+
}
|
|
5993
|
+
function rotation(degrees) {
|
|
5994
|
+
if (degrees === void 0 || degrees % 360 === 0) return {};
|
|
5995
|
+
return { rotationDegrees: degrees };
|
|
5996
|
+
}
|
|
5997
|
+
function resolveOffset(value, axisEmu) {
|
|
5998
|
+
return resolveLength(value, axisEmu);
|
|
5999
|
+
}
|
|
6000
|
+
function resolveExtent(value, axisEmu) {
|
|
6001
|
+
return Math.max(0, resolveLength(value, axisEmu));
|
|
6002
|
+
}
|
|
6003
|
+
function resolveLength(value, axisEmu) {
|
|
6004
|
+
if (typeof value === "number") return inchesToEmu(value);
|
|
6005
|
+
const percent = Number.parseFloat(value);
|
|
6006
|
+
if (!Number.isFinite(percent)) return 0;
|
|
6007
|
+
return Math.round(percent / 100 * axisEmu);
|
|
6008
|
+
}
|
|
6009
|
+
function marginInsets(margin) {
|
|
6010
|
+
if (margin === void 0) return void 0;
|
|
6011
|
+
const [top, right, bottom, left] = Array.isArray(margin) ? margin : [margin, margin, margin, margin];
|
|
6012
|
+
return {
|
|
6013
|
+
top: pointsToEmu(top ?? 0),
|
|
6014
|
+
right: pointsToEmu(right ?? 0),
|
|
6015
|
+
bottom: pointsToEmu(bottom ?? 0),
|
|
6016
|
+
left: pointsToEmu(left ?? 0)
|
|
6017
|
+
};
|
|
6018
|
+
}
|
|
6019
|
+
function solidFill(color, transparency) {
|
|
6020
|
+
return {
|
|
6021
|
+
kind: "solid",
|
|
6022
|
+
color,
|
|
6023
|
+
...transparency !== void 0 && transparency > 0 ? { transparencyPercent: transparency } : {}
|
|
6024
|
+
};
|
|
6025
|
+
}
|
|
6026
|
+
function resolveColors(entries, at, deps) {
|
|
6027
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
6028
|
+
let failed = false;
|
|
6029
|
+
for (const [key, value] of entries) {
|
|
6030
|
+
if (value === void 0) continue;
|
|
6031
|
+
const color = deps.color(value);
|
|
6032
|
+
if (!color) {
|
|
6033
|
+
deps.reject(`${at}.${key} "${value}"`);
|
|
6034
|
+
failed = true;
|
|
6035
|
+
continue;
|
|
6036
|
+
}
|
|
6037
|
+
resolved.set(key, color);
|
|
6038
|
+
}
|
|
6039
|
+
return failed ? void 0 : resolved;
|
|
6040
|
+
}
|
|
5320
6041
|
|
|
5321
6042
|
// src/styles/themeToStyles.ts
|
|
5322
6043
|
init_themes();
|
|
@@ -7159,7 +7880,7 @@ function decoratedStyle(match, base) {
|
|
|
7159
7880
|
function pushSegment(out, text, options, override = {}) {
|
|
7160
7881
|
const bold = override.bold ?? options.base.bold;
|
|
7161
7882
|
const italic = override.italic ?? options.base.italic;
|
|
7162
|
-
const formatting =
|
|
7883
|
+
const formatting = runFormatting2(options, { bold, italic });
|
|
7163
7884
|
const lines = text.split("\n");
|
|
7164
7885
|
for (const [lineIndex, line] of lines.entries()) {
|
|
7165
7886
|
if (!line && lineIndex === 0) continue;
|
|
@@ -7237,7 +7958,7 @@ function pushNoProofWords(out, text, formatting, options) {
|
|
|
7237
7958
|
out.push({ kind: "text", text: text.slice(lastIndex), formatting });
|
|
7238
7959
|
}
|
|
7239
7960
|
}
|
|
7240
|
-
function
|
|
7961
|
+
function runFormatting2(options, state) {
|
|
7241
7962
|
const formatting = { ...options.base };
|
|
7242
7963
|
if (state.bold !== void 0) formatting.bold = state.bold;
|
|
7243
7964
|
if (state.italic !== void 0) formatting.italic = state.italic;
|
|
@@ -7609,7 +8330,9 @@ function compileComponent(component, scope) {
|
|
|
7609
8330
|
case "columns":
|
|
7610
8331
|
return compileColumns(component, scope);
|
|
7611
8332
|
case "image":
|
|
7612
|
-
return
|
|
8333
|
+
return compileImage2(component, scope);
|
|
8334
|
+
case "visual":
|
|
8335
|
+
return compileVisual(component, scope);
|
|
7613
8336
|
case "table":
|
|
7614
8337
|
return compileTable(component, scope);
|
|
7615
8338
|
default:
|
|
@@ -7853,7 +8576,7 @@ function compileTextBox(component, scope) {
|
|
|
7853
8576
|
const style = props.style;
|
|
7854
8577
|
const padding = style?.padding;
|
|
7855
8578
|
if (props.renderAs === "shape") {
|
|
7856
|
-
const shape =
|
|
8579
|
+
const shape = compileShape2(props, children, scope);
|
|
7857
8580
|
if (shape) return shape;
|
|
7858
8581
|
}
|
|
7859
8582
|
ctx.features.require("tables", path3);
|
|
@@ -7907,7 +8630,7 @@ function compileTextBox(component, scope) {
|
|
|
7907
8630
|
];
|
|
7908
8631
|
}
|
|
7909
8632
|
var EMU_PER_PIXEL = 9525;
|
|
7910
|
-
function
|
|
8633
|
+
function compileShape2(props, children, scope) {
|
|
7911
8634
|
const { ctx, path: path3 } = scope;
|
|
7912
8635
|
const width = shapeSize(props.width, "width", ctx);
|
|
7913
8636
|
const height = shapeSize(props.height, "height", ctx);
|
|
@@ -8401,7 +9124,7 @@ function reportUnlowered(component, props, text, scope) {
|
|
|
8401
9124
|
}
|
|
8402
9125
|
function compileRuns(props, text, ctx, path3, mode = "inline") {
|
|
8403
9126
|
const font = props.font ?? {};
|
|
8404
|
-
const base =
|
|
9127
|
+
const base = runFormatting3(font, props, ctx);
|
|
8405
9128
|
if (base.language) ctx.features.require("proofing-language", path3);
|
|
8406
9129
|
if (base.noProof) ctx.features.require("proofing-language", path3);
|
|
8407
9130
|
const words = mergeNoProofWords(noProofWords(ctx.theme), props.noProofWords);
|
|
@@ -8671,7 +9394,7 @@ function isoDate(date) {
|
|
|
8671
9394
|
function isoDateTime(date) {
|
|
8672
9395
|
return date.toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "Z");
|
|
8673
9396
|
}
|
|
8674
|
-
function
|
|
9397
|
+
function runFormatting3(font, props, ctx) {
|
|
8675
9398
|
const hasWeightRequest = font.fontWeight != null || font.bold === true;
|
|
8676
9399
|
const effectiveFamily = font.family ?? (hasWeightRequest ? resolveBodyFamily(ctx.theme) : void 0);
|
|
8677
9400
|
const weighted = applyFontWeightAlias({
|
|
@@ -8834,8 +9557,107 @@ function headingLevel(level) {
|
|
|
8834
9557
|
const value = typeof level === "number" ? level : 1;
|
|
8835
9558
|
return value >= 1 && value <= 6 ? value : 1;
|
|
8836
9559
|
}
|
|
9560
|
+
function compileVisual(component, scope) {
|
|
9561
|
+
const { ctx, path: path3 } = scope;
|
|
9562
|
+
const props = component.props ?? {};
|
|
9563
|
+
if (!isNativeVisualProps4(props)) {
|
|
9564
|
+
ctx.unsupported.push({
|
|
9565
|
+
name: "visual",
|
|
9566
|
+
path: path3,
|
|
9567
|
+
detail: "a raster visual reached the compiler; it should have been rasterized during desugaring"
|
|
9568
|
+
});
|
|
9569
|
+
return [];
|
|
9570
|
+
}
|
|
9571
|
+
const group = compileNativeVisualGroup(
|
|
9572
|
+
props,
|
|
9573
|
+
nativeVisualDeps(ctx, path3)
|
|
9574
|
+
);
|
|
9575
|
+
if (!group) return [];
|
|
9576
|
+
const size = visualPlacementPixels(props, group.canvas, {
|
|
9577
|
+
widthPx: Math.round(twipsToPixels(getAvailableWidthTwips(ctx.theme))),
|
|
9578
|
+
heightPx: Math.round(twipsToPixels(getAvailableHeightTwips(ctx.theme)))
|
|
9579
|
+
});
|
|
9580
|
+
const drawing = {
|
|
9581
|
+
kind: "drawingGroup",
|
|
9582
|
+
widthEmu: pixelsToEmu(size.width),
|
|
9583
|
+
heightEmu: pixelsToEmu(size.height),
|
|
9584
|
+
canvasWidthEmu: group.canvas.widthEmu,
|
|
9585
|
+
canvasHeightEmu: group.canvas.heightEmu,
|
|
9586
|
+
children: group.children,
|
|
9587
|
+
...typeof props.alt === "string" && props.alt ? { altText: props.alt } : {},
|
|
9588
|
+
...props.floating ? { floating: compileFloating(props.floating, ctx, path3) } : {}
|
|
9589
|
+
};
|
|
9590
|
+
ctx.features.require("drawing-groups", path3);
|
|
9591
|
+
if (props.floating) ctx.features.require("floating-images", path3);
|
|
9592
|
+
const spacing = {};
|
|
9593
|
+
if (props.spacing?.before !== void 0) {
|
|
9594
|
+
spacing.beforeTwips = pointsToTwips2(props.spacing.before);
|
|
9595
|
+
}
|
|
9596
|
+
if (props.spacing?.after !== void 0) {
|
|
9597
|
+
spacing.afterTwips = pointsToTwips2(props.spacing.after);
|
|
9598
|
+
}
|
|
9599
|
+
const blocks = [
|
|
9600
|
+
{
|
|
9601
|
+
kind: "paragraph",
|
|
9602
|
+
id: scope.id,
|
|
9603
|
+
path: path3,
|
|
9604
|
+
children: [drawing],
|
|
9605
|
+
formatting: {
|
|
9606
|
+
// A floating drawing is anchored, so aligning its paragraph would move
|
|
9607
|
+
// the anchor rather than the graphic — the same rule an image follows.
|
|
9608
|
+
...props.floating ? {} : { alignment: compileAlignment(props.alignment) ?? "center" },
|
|
9609
|
+
...Object.keys(spacing).length > 0 ? { spacing } : {},
|
|
9610
|
+
...props.keepNext !== void 0 ? { keepNext: props.keepNext } : {},
|
|
9611
|
+
...props.keepLines !== void 0 ? { keepLines: props.keepLines } : {}
|
|
9612
|
+
}
|
|
9613
|
+
}
|
|
9614
|
+
];
|
|
9615
|
+
const caption = captionBlock(props.caption, scope, "visual");
|
|
9616
|
+
if (caption === void 0) return [];
|
|
9617
|
+
if (caption) blocks.push(caption);
|
|
9618
|
+
return blocks;
|
|
9619
|
+
}
|
|
9620
|
+
function nativeVisualDeps(ctx, path3) {
|
|
9621
|
+
return {
|
|
9622
|
+
color: (value) => {
|
|
9623
|
+
try {
|
|
9624
|
+
return irColor(resolveColor(value, ctx.theme));
|
|
9625
|
+
} catch {
|
|
9626
|
+
return void 0;
|
|
9627
|
+
}
|
|
9628
|
+
},
|
|
9629
|
+
picture: (source) => {
|
|
9630
|
+
const loaded = ctx.images.get(source);
|
|
9631
|
+
if (!loaded) return void 0;
|
|
9632
|
+
const mediaType = detectImageType(source, loaded.contentType);
|
|
9633
|
+
if (mediaType === "svg") ctx.features.require("svg-images", path3);
|
|
9634
|
+
return {
|
|
9635
|
+
resourceId: declareResource(loaded, mediaType, ctx),
|
|
9636
|
+
mediaType,
|
|
9637
|
+
...loaded.intrinsic ? { intrinsic: loaded.intrinsic } : {}
|
|
9638
|
+
};
|
|
9639
|
+
},
|
|
9640
|
+
reject: (detail) => ctx.unsupported.push({ name: "visual", path: path3, detail }),
|
|
9641
|
+
warn: (message) => warnOnce(ctx, `visual:${message}`, message)
|
|
9642
|
+
};
|
|
9643
|
+
}
|
|
9644
|
+
function visualPlacementPixels(props, canvas, reference) {
|
|
9645
|
+
const canvasWidthPx = Math.round(emuToPixels(canvas.widthEmu));
|
|
9646
|
+
const canvasHeightPx = Math.round(emuToPixels(canvas.heightEmu));
|
|
9647
|
+
const targetWidth = props.width !== void 0 ? parseWidthValue(props.width, reference.widthPx) : void 0;
|
|
9648
|
+
const targetHeight = props.height !== void 0 ? parseDimensionValue(props.height, reference.heightPx) : void 0;
|
|
9649
|
+
if (targetWidth === void 0 && targetHeight === void 0) {
|
|
9650
|
+
return { width: canvasWidthPx, height: canvasHeightPx };
|
|
9651
|
+
}
|
|
9652
|
+
return calculateMissingDimension(
|
|
9653
|
+
canvasWidthPx,
|
|
9654
|
+
canvasHeightPx,
|
|
9655
|
+
targetWidth,
|
|
9656
|
+
targetHeight
|
|
9657
|
+
);
|
|
9658
|
+
}
|
|
8837
9659
|
var UNLOWERED_IMAGE_PROPS = ["comment"];
|
|
8838
|
-
function
|
|
9660
|
+
function compileImage2(component, scope) {
|
|
8839
9661
|
const { ctx, path: path3 } = scope;
|
|
8840
9662
|
const props = component.props ?? {};
|
|
8841
9663
|
for (const prop of UNLOWERED_IMAGE_PROPS) {
|
|
@@ -8896,32 +9718,37 @@ function compileImage(component, scope) {
|
|
|
8896
9718
|
}
|
|
8897
9719
|
}
|
|
8898
9720
|
];
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
8902
|
-
if (syntax) {
|
|
8903
|
-
ctx.unsupported.push({ name: "image", path: path3, detail: syntax });
|
|
8904
|
-
return [];
|
|
8905
|
-
}
|
|
8906
|
-
blocks.push({
|
|
8907
|
-
kind: "paragraph",
|
|
8908
|
-
id: `${scope.id}:caption`,
|
|
8909
|
-
path: `${path3}.caption`,
|
|
8910
|
-
styleId: "Normal",
|
|
8911
|
-
// Captions default to left alignment, whatever the figure did.
|
|
8912
|
-
formatting: { alignment: "left" },
|
|
8913
|
-
// A caption reaches the parser only when it carries a decorator, which
|
|
8914
|
-
// is why a link in an otherwise plain caption stays literal.
|
|
8915
|
-
children: DECORATED.test(caption) ? parseInline(caption, {
|
|
8916
|
-
base: {},
|
|
8917
|
-
hyperlinks: true,
|
|
8918
|
-
resolvePlaceholder: placeholderResolver(ctx),
|
|
8919
|
-
resolveCrossReference: crossReferenceResolver(ctx, path3)
|
|
8920
|
-
}) : parseLiteral(caption, { base: {} })
|
|
8921
|
-
});
|
|
8922
|
-
}
|
|
9721
|
+
const caption = captionBlock(props.caption, scope, "image");
|
|
9722
|
+
if (caption === void 0) return [];
|
|
9723
|
+
if (caption) blocks.push(caption);
|
|
8923
9724
|
return blocks;
|
|
8924
9725
|
}
|
|
9726
|
+
function captionBlock(value, scope, componentName) {
|
|
9727
|
+
if (!value) return null;
|
|
9728
|
+
const { ctx, path: path3 } = scope;
|
|
9729
|
+
const caption = String(value);
|
|
9730
|
+
const syntax = containsUnsupportedSyntax(caption);
|
|
9731
|
+
if (syntax) {
|
|
9732
|
+
ctx.unsupported.push({ name: componentName, path: path3, detail: syntax });
|
|
9733
|
+
return void 0;
|
|
9734
|
+
}
|
|
9735
|
+
return {
|
|
9736
|
+
kind: "paragraph",
|
|
9737
|
+
id: `${scope.id}:caption`,
|
|
9738
|
+
path: `${path3}.caption`,
|
|
9739
|
+
styleId: "Normal",
|
|
9740
|
+
// Captions default to left alignment, whatever the figure did.
|
|
9741
|
+
formatting: { alignment: "left" },
|
|
9742
|
+
// A caption reaches the parser only when it carries a decorator, which
|
|
9743
|
+
// is why a link in an otherwise plain caption stays literal.
|
|
9744
|
+
children: DECORATED.test(caption) ? parseInline(caption, {
|
|
9745
|
+
base: {},
|
|
9746
|
+
hyperlinks: true,
|
|
9747
|
+
resolvePlaceholder: placeholderResolver(ctx),
|
|
9748
|
+
resolveCrossReference: crossReferenceResolver(ctx, path3)
|
|
9749
|
+
}) : parseLiteral(caption, { base: {} })
|
|
9750
|
+
};
|
|
9751
|
+
}
|
|
8925
9752
|
function relativeFrom(value, axis) {
|
|
8926
9753
|
const allowed = axis === "horizontal" ? ["character", "column", "margin", "page"] : ["margin", "page", "paragraph", "line"];
|
|
8927
9754
|
return typeof value === "string" && allowed.includes(value) ? value : void 0;
|
|
@@ -9345,6 +10172,9 @@ function cellChildren(cell, baseStyle, scope, rowRevision) {
|
|
|
9345
10172
|
if (content.name === "image") {
|
|
9346
10173
|
return wrap(cellImage(content, base, ctx));
|
|
9347
10174
|
}
|
|
10175
|
+
if (content.name === "visual") {
|
|
10176
|
+
return wrap(cellVisual(content, scope));
|
|
10177
|
+
}
|
|
9348
10178
|
if (content.name !== "paragraph") {
|
|
9349
10179
|
return wrap([
|
|
9350
10180
|
{
|
|
@@ -9384,6 +10214,40 @@ function cellChildren(cell, baseStyle, scope, rowRevision) {
|
|
|
9384
10214
|
})
|
|
9385
10215
|
);
|
|
9386
10216
|
}
|
|
10217
|
+
function cellVisual(component, scope) {
|
|
10218
|
+
const { ctx, path: path3 } = scope;
|
|
10219
|
+
const props = component.props ?? {};
|
|
10220
|
+
if (!isNativeVisualProps4(props)) {
|
|
10221
|
+
ctx.unsupported.push({
|
|
10222
|
+
name: "visual",
|
|
10223
|
+
path: path3,
|
|
10224
|
+
detail: "a raster visual reached the compiler; it should have been rasterized during desugaring"
|
|
10225
|
+
});
|
|
10226
|
+
return [];
|
|
10227
|
+
}
|
|
10228
|
+
const group = compileNativeVisualGroup(
|
|
10229
|
+
props,
|
|
10230
|
+
nativeVisualDeps(ctx, path3)
|
|
10231
|
+
);
|
|
10232
|
+
if (!group) return [];
|
|
10233
|
+
const size = visualPlacementPixels(props, group.canvas, {
|
|
10234
|
+
widthPx: CELL_DRAWING_REFERENCE.width,
|
|
10235
|
+
heightPx: CELL_DRAWING_REFERENCE.height
|
|
10236
|
+
});
|
|
10237
|
+
ctx.features.require("drawing-groups", path3);
|
|
10238
|
+
return [
|
|
10239
|
+
{
|
|
10240
|
+
kind: "drawingGroup",
|
|
10241
|
+
widthEmu: pixelsToEmu(size.width),
|
|
10242
|
+
heightEmu: pixelsToEmu(size.height),
|
|
10243
|
+
canvasWidthEmu: group.canvas.widthEmu,
|
|
10244
|
+
canvasHeightEmu: group.canvas.heightEmu,
|
|
10245
|
+
children: group.children,
|
|
10246
|
+
...typeof props.alt === "string" && props.alt ? { altText: props.alt } : {}
|
|
10247
|
+
}
|
|
10248
|
+
];
|
|
10249
|
+
}
|
|
10250
|
+
var CELL_DRAWING_REFERENCE = { width: 300, height: 200 };
|
|
9387
10251
|
function cellImage(component, base, ctx) {
|
|
9388
10252
|
const props = component.props ?? {};
|
|
9389
10253
|
const source = resolveImageSource(props);
|