deckjsx 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as Text, c as isAuthorNode, i as Slide, l as isContentNode, n as Image, o as View, r as Shape, s as createElement, t as Fragment, u as isSlideNode } from "./jsx-lqMAdW2X.mjs";
1
+ import { a as isContentNode, c as toLegacyJsxNode, d as Slide, f as Text, i as isAuthorNode, l as Image, m as isAuthorTreeNode, n as createElement, o as isSlideNode, p as View, s as isLegacyAuthorNode, t as Fragment, u as Shape } from "./jsx-Crlbye9V.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { mkdir, writeFile } from "node:fs/promises";
4
4
  import { dirname } from "node:path";
@@ -3863,24 +3863,15 @@ function compileGroupNode(node, parentFrame, idGenerator, placement, clipRect, c
3863
3863
  }, childClipRect, context)
3864
3864
  };
3865
3865
  }
3866
- function compileTextNode(node, parentFrame, idGenerator, placement, clipRect, context) {
3867
- const { props } = node;
3868
- const textLengthContext = getTextLengthContext(props, context);
3869
- const resolved = frameFromProps(props, parentFrame, placement, textLengthContext);
3870
- const strokes = resolveNodeStrokes(props, textLengthContext);
3871
- const shadow = parseShadowShorthand(props.textShadow ?? props.boxShadow);
3866
+ function textStyleFromProps(props, textLengthContext) {
3872
3867
  const list = resolveListStyle(props, textLengthContext);
3873
3868
  const lineHeight = resolveLineHeight(props.lineHeight, textLengthContext);
3874
3869
  const underlineStyle = resolveUnderlineStyle(props.textDecorationStyle);
3875
3870
  const underlineColor = normalizeColor(props.textDecorationColor);
3876
3871
  const textDirection = resolveTextDirection(props.writingMode);
3877
3872
  const tabStops = resolveTabStops(props.tabStops, textLengthContext);
3878
- const hyperlink = props.href ? {
3879
- url: props.href,
3880
- ...props.tooltip ? { tooltip: props.tooltip } : {}
3881
- } : void 0;
3882
3873
  const fontSizePt = props.fontSize === void 0 ? void 0 : parsePointValue(props.fontSize, 0, textLengthContext);
3883
- const style = {
3874
+ return {
3884
3875
  fontFamily: props.fontFamily,
3885
3876
  fontSizePt,
3886
3877
  fontWeight: props.fontWeight,
@@ -3908,6 +3899,48 @@ function compileTextNode(node, parentFrame, idGenerator, placement, clipRect, co
3908
3899
  ...props.superscript ? { superscript: true } : {},
3909
3900
  ...props.subscript ? { subscript: true } : {}
3910
3901
  };
3902
+ }
3903
+ function isEmptyRunStyle(style) {
3904
+ return Object.values(style).every((value) => value === void 0);
3905
+ }
3906
+ function flattenUnknownChildren(children) {
3907
+ return children.flatMap((child) => Array.isArray(child) ? flattenUnknownChildren(child) : [child]);
3908
+ }
3909
+ function extractRichTextRuns(children, textTransform, textLengthContext) {
3910
+ const runs = [];
3911
+ for (const child of flattenUnknownChildren(children)) {
3912
+ if (child === null || child === void 0 || child === false || child === true) continue;
3913
+ if (typeof child === "string" || typeof child === "number") {
3914
+ runs.push({ text: extractText([child], textTransform) });
3915
+ continue;
3916
+ }
3917
+ if (typeof child === "object" && child !== null && "kind" in child) {
3918
+ const authorNode = child;
3919
+ if (authorNode.kind !== "text") throw new Error("Text nodes can only contain primitive text or inline text runs.");
3920
+ const props = normalizeTextProps(authorNode.props);
3921
+ const childLengthContext = getTextLengthContext(props, textLengthContext);
3922
+ const style = textStyleFromProps(props, childLengthContext);
3923
+ const text = extractRichTextRuns(authorNode.children, props.textTransform ?? textTransform, childLengthContext).map((run) => run.text).join("");
3924
+ runs.push({
3925
+ text,
3926
+ ...!isEmptyRunStyle(style) ? { style } : {}
3927
+ });
3928
+ }
3929
+ }
3930
+ return runs;
3931
+ }
3932
+ function compileTextNode(node, parentFrame, idGenerator, placement, clipRect, context) {
3933
+ const { props } = node;
3934
+ const textLengthContext = getTextLengthContext(props, context);
3935
+ const resolved = frameFromProps(props, parentFrame, placement, textLengthContext);
3936
+ const strokes = resolveNodeStrokes(props, textLengthContext);
3937
+ const shadow = parseShadowShorthand(props.textShadow ?? props.boxShadow);
3938
+ const hyperlink = props.href ? {
3939
+ url: props.href,
3940
+ ...props.tooltip ? { tooltip: props.tooltip } : {}
3941
+ } : void 0;
3942
+ const style = textStyleFromProps(props, textLengthContext);
3943
+ const runs = extractRichTextRuns(node.source.children, props.textTransform, textLengthContext);
3911
3944
  const visibleFrame = intersectClipRect({
3912
3945
  xEmu: resolved.xEmu,
3913
3946
  yEmu: resolved.yEmu,
@@ -3930,7 +3963,10 @@ function compileTextNode(node, parentFrame, idGenerator, placement, clipRect, co
3930
3963
  ...props.visibility !== void 0 ? { visibility: props.visibility } : {},
3931
3964
  flipH: resolved.flipH,
3932
3965
  flipV: resolved.flipV,
3933
- content: { text: extractText(node.source.children, props.textTransform) },
3966
+ content: {
3967
+ text: runs.map((run) => run.text).join(""),
3968
+ ...runs.length > 1 || runs.some((run) => run.style) ? { runs } : {}
3969
+ },
3934
3970
  style,
3935
3971
  fill: backgroundFill.fill,
3936
3972
  ...backgroundFill.backgroundLayers ? { backgroundLayers: backgroundFill.backgroundLayers } : {},
@@ -4102,13 +4138,442 @@ function renderPresentation(options, slides) {
4102
4138
  version: "0.1",
4103
4139
  meta: options.meta,
4104
4140
  size: slideSize,
4105
- slides: slides.map((factory, slideIndex) => compileSlide(factory({
4106
- slideIndex,
4107
- totalSlides: slides.length
4108
- }), {
4109
- slideIndex,
4110
- totalSlides: slides.length
4111
- }, slideFrame, idGenerator, lengthContext))
4141
+ slides: slides.map((factory, slideIndex) => {
4142
+ return compileSlide(toLegacyJsxNode(factory({
4143
+ slideIndex,
4144
+ totalSlides: slides.length,
4145
+ context: {
4146
+ slideIndex,
4147
+ totalSlides: slides.length
4148
+ }
4149
+ })), {
4150
+ slideIndex,
4151
+ totalSlides: slides.length
4152
+ }, slideFrame, idGenerator, lengthContext);
4153
+ })
4154
+ };
4155
+ }
4156
+ //#endregion
4157
+ //#region src/diagnostics/format.ts
4158
+ function formatSpan(path) {
4159
+ return ` at ${path}`;
4160
+ }
4161
+ function formatDiagnostic(diagnostic) {
4162
+ const lines = [`${diagnostic.severity}[${diagnostic.code}]: ${diagnostic.title}`];
4163
+ if (diagnostic.message) lines.push(` ${diagnostic.message}`);
4164
+ for (const label of diagnostic.labels) {
4165
+ lines.push(formatSpan(label.path));
4166
+ lines.push(` = ${label.message}`);
4167
+ }
4168
+ for (const note of diagnostic.notes ?? []) lines.push(`note: ${note}`);
4169
+ for (const help of diagnostic.help ?? []) lines.push(`help: ${help}`);
4170
+ return lines.join("\n");
4171
+ }
4172
+ function formatDiagnostics(diagnostics) {
4173
+ return diagnostics.items.map((item) => formatDiagnostic(item)).join("\n\n");
4174
+ }
4175
+ //#endregion
4176
+ //#region src/diagnostics/errors.ts
4177
+ var DeckDiagnosticError = class extends Error {
4178
+ diagnostics;
4179
+ constructor(message, diagnostics) {
4180
+ super(message);
4181
+ this.name = "DeckDiagnosticError";
4182
+ this.diagnostics = diagnostics;
4183
+ }
4184
+ };
4185
+ var SemanticGraphDiagnosticError = class extends DeckDiagnosticError {
4186
+ constructor(diagnostics) {
4187
+ super(formatDiagnostics(diagnostics), diagnostics);
4188
+ this.name = "SemanticGraphDiagnosticError";
4189
+ }
4190
+ };
4191
+ //#endregion
4192
+ //#region src/diagnostics/index.ts
4193
+ function createDiagnostics(items = []) {
4194
+ return {
4195
+ items,
4196
+ hasErrors: items.some((item) => item.severity === "error"),
4197
+ hasWarnings: items.some((item) => item.severity === "warning")
4198
+ };
4199
+ }
4200
+ function diagnostic(input) {
4201
+ return input;
4202
+ }
4203
+ //#endregion
4204
+ //#region src/graph/identity.ts
4205
+ function slug(value) {
4206
+ return value.replace(/[^a-zA-Z0-9:_-]+/g, "_");
4207
+ }
4208
+ function graphNodeId(material) {
4209
+ return slug(material.join("/"));
4210
+ }
4211
+ function styleEntityId(material) {
4212
+ return slug(`style/${material.join("/")}`);
4213
+ }
4214
+ function assetEntityId(material) {
4215
+ return slug(`asset/${material.join("/")}`);
4216
+ }
4217
+ //#endregion
4218
+ //#region src/graph/roles.ts
4219
+ function semanticKindForTag(tag) {
4220
+ if (tag === "img") return "image";
4221
+ if (tag === "p" || tag.startsWith("h") || tag === "span") return tag === "span" ? "textRun" : "text";
4222
+ return "container";
4223
+ }
4224
+ function semanticKindForComponent(component) {
4225
+ switch (component) {
4226
+ case "Slide": return "slide";
4227
+ case "View": return "container";
4228
+ case "Text": return "text";
4229
+ case "Image": return "image";
4230
+ case "Shape": return "shape";
4231
+ }
4232
+ }
4233
+ function semanticRoleForTag(tag) {
4234
+ switch (tag) {
4235
+ case "article":
4236
+ case "aside":
4237
+ case "footer":
4238
+ case "header":
4239
+ case "main":
4240
+ case "nav":
4241
+ case "section": return {
4242
+ kind: "sectioning",
4243
+ tag
4244
+ };
4245
+ case "div": return { kind: "genericContainer" };
4246
+ case "figure": return { kind: "figure" };
4247
+ case "p": return { kind: "paragraph" };
4248
+ case "h1":
4249
+ case "h2":
4250
+ case "h3":
4251
+ case "h4":
4252
+ case "h5":
4253
+ case "h6": return {
4254
+ kind: "heading",
4255
+ level: Number(tag.slice(1))
4256
+ };
4257
+ case "img": return { kind: "image" };
4258
+ case "span": return;
4259
+ }
4260
+ }
4261
+ function semanticRoleForComponent(component) {
4262
+ switch (component) {
4263
+ case "Slide": return { kind: "slide" };
4264
+ case "Image": return { kind: "image" };
4265
+ case "Shape": return { kind: "shape" };
4266
+ case "Text":
4267
+ case "View": return;
4268
+ }
4269
+ }
4270
+ //#endregion
4271
+ //#region src/graph/build.ts
4272
+ function keySegment(key, index) {
4273
+ return key === void 0 ? `index:${index}` : `key:${String(key)}`;
4274
+ }
4275
+ function sourceName(node) {
4276
+ return node.source.kind === "tag" ? node.source.tag : node.source.component;
4277
+ }
4278
+ function nodeSemanticKind(node) {
4279
+ return node.source.kind === "tag" ? semanticKindForTag(node.source.tag) : semanticKindForComponent(node.source.component);
4280
+ }
4281
+ function nodeRole(node) {
4282
+ return node.source.kind === "tag" ? semanticRoleForTag(node.source.tag) : semanticRoleForComponent(node.source.component);
4283
+ }
4284
+ function originFor(node, path) {
4285
+ return {
4286
+ kind: "authored",
4287
+ path,
4288
+ ...node.sourceSpan ? { sourceSpan: node.sourceSpan } : {}
4289
+ };
4290
+ }
4291
+ function textOriginFor(node, path) {
4292
+ return {
4293
+ kind: "authored",
4294
+ path,
4295
+ ...node.sourceSpan ? { sourceSpan: node.sourceSpan } : {}
4296
+ };
4297
+ }
4298
+ function propsWithoutStyle(props) {
4299
+ const { style: _style, children: _children, ...direct } = props;
4300
+ return Object.keys(direct).length === 0 ? void 0 : direct;
4301
+ }
4302
+ function styleRefFor(state, idMaterial, target, props) {
4303
+ const style = props.style;
4304
+ const direct = propsWithoutStyle(props);
4305
+ if (style === void 0 && direct === void 0) return;
4306
+ const id = styleEntityId(idMaterial);
4307
+ state.styles.set(id, {
4308
+ id,
4309
+ target,
4310
+ authored: {
4311
+ ...style !== void 0 ? { style } : {},
4312
+ ...direct !== void 0 ? { direct } : {}
4313
+ }
4314
+ });
4315
+ return id;
4316
+ }
4317
+ function addDiagnostic(state, item) {
4318
+ state.diagnostics.push(item);
4319
+ }
4320
+ function invalidStructure(path, title, message, help) {
4321
+ return diagnostic({
4322
+ severity: "error",
4323
+ code: "E_SEMANTIC_STRUCTURE",
4324
+ title,
4325
+ labels: [{
4326
+ path,
4327
+ message
4328
+ }],
4329
+ ...message ? { message } : {},
4330
+ ...help ? { help } : {}
4331
+ });
4332
+ }
4333
+ function assetForImage(state, idMaterial, props, path) {
4334
+ if (typeof props.src !== "string" && typeof props.data !== "string") {
4335
+ addDiagnostic(state, invalidStructure(path, "image source is missing", "Image nodes require either src or data.", ["Add a src path or data URL to the image."]));
4336
+ return;
4337
+ }
4338
+ const id = assetEntityId(idMaterial);
4339
+ const entity = {
4340
+ id,
4341
+ kind: "image",
4342
+ source: typeof props.src === "string" ? {
4343
+ kind: "path",
4344
+ path: props.src
4345
+ } : {
4346
+ kind: "data",
4347
+ data: props.data
4348
+ },
4349
+ metadata: typeof props.data === "string" && props.data.startsWith("data:") ? { mediaType: props.data.slice(5, props.data.indexOf(";")) || void 0 } : {},
4350
+ resolution: "unresolved"
4351
+ };
4352
+ state.assets.set(id, entity);
4353
+ return id;
4354
+ }
4355
+ function semanticBase(state, node, id, kind, path, material) {
4356
+ const styleRef = styleRefFor(state, material, kind, node.props);
4357
+ return {
4358
+ id,
4359
+ kind,
4360
+ origin: originFor(node, path),
4361
+ ...node.source.kind === "tag" ? { authoredTag: node.source.tag } : {},
4362
+ ...node.source.kind === "component" ? { authoredComponent: node.source.component } : {},
4363
+ ...node.key !== void 0 ? { key: node.key } : {},
4364
+ ...nodeRole(node) ? { role: nodeRole(node) } : {},
4365
+ ...styleRef ? { styleRef } : {}
4366
+ };
4367
+ }
4368
+ function buildTextRunFromLeaf(state, leaf, context, index) {
4369
+ const text = typeof leaf.value === "string" ? leaf.value : String(leaf.value);
4370
+ if (text.trim().length === 0) return;
4371
+ const segment = `text:${index}`;
4372
+ const id = graphNodeId([...context.parentMaterial, segment]);
4373
+ const path = `${context.path} > text[${index}]`;
4374
+ state.nodes.set(id, {
4375
+ id,
4376
+ kind: "textRun",
4377
+ origin: textOriginFor(leaf, path),
4378
+ text
4379
+ });
4380
+ return {
4381
+ id,
4382
+ kind: "textRun"
4383
+ };
4384
+ }
4385
+ function buildImplicitTextNode(state, leaf, context, index) {
4386
+ const run = buildTextRunFromLeaf(state, leaf, {
4387
+ ...context,
4388
+ parentMaterial: [...context.parentMaterial, `implicit-text:${index}`],
4389
+ path: `${context.path} > implicitText[${index}]`
4390
+ }, 0);
4391
+ if (!run) return;
4392
+ const id = graphNodeId([...context.parentMaterial, `implicit-text:${index}`]);
4393
+ state.nodes.set(id, {
4394
+ id,
4395
+ kind: "text",
4396
+ origin: {
4397
+ kind: "implicit",
4398
+ path: `${context.path} > implicitText[${index}]`,
4399
+ ...leaf.sourceSpan ? { sourceSpan: leaf.sourceSpan } : {},
4400
+ reason: "primitive-text-in-container"
4401
+ },
4402
+ implicit: true,
4403
+ inlineChildren: [run.id]
4404
+ });
4405
+ return {
4406
+ id,
4407
+ kind: "text"
4408
+ };
4409
+ }
4410
+ function buildChildren(state, children, context) {
4411
+ const ids = [];
4412
+ children.forEach((child, index) => {
4413
+ if (child.kind === "fragment") {
4414
+ const segment = `fragment:${keySegment(child.key, index)}`;
4415
+ ids.push(...buildChildren(state, child.children, {
4416
+ ...context,
4417
+ parentMaterial: [...context.parentMaterial, segment],
4418
+ path: `${context.path} > fragment[${keySegment(child.key, index)}]`
4419
+ }));
4420
+ return;
4421
+ }
4422
+ const built = buildNode(state, child, context, index);
4423
+ if (built) ids.push(built.id);
4424
+ });
4425
+ return ids;
4426
+ }
4427
+ function buildTextLikeNode(state, node, id, path, material) {
4428
+ const inlineChildren = [];
4429
+ node.children.forEach((child, index) => {
4430
+ if (child.kind === "text") {
4431
+ const run = buildTextRunFromLeaf(state, child, {
4432
+ parentId: id,
4433
+ parentMaterial: material,
4434
+ path,
4435
+ inline: true
4436
+ }, index);
4437
+ if (run) inlineChildren.push(run.id);
4438
+ return;
4439
+ }
4440
+ if (child.kind === "fragment") {
4441
+ inlineChildren.push(...buildChildren(state, child.children, {
4442
+ parentId: id,
4443
+ parentMaterial: [...material, `fragment:${keySegment(child.key, index)}`],
4444
+ path: `${path} > fragment[${keySegment(child.key, index)}]`,
4445
+ inline: true
4446
+ }));
4447
+ return;
4448
+ }
4449
+ if (child.source.kind === "tag" && child.source.tag === "span") {
4450
+ const built = buildNode(state, child, {
4451
+ parentId: id,
4452
+ parentMaterial: material,
4453
+ path,
4454
+ inline: true
4455
+ }, index);
4456
+ if (built) inlineChildren.push(built.id);
4457
+ return;
4458
+ }
4459
+ addDiagnostic(state, invalidStructure(`${path} > ${sourceName(child)}[${index}]`, "block content cannot appear inside text", "Text-like elements accept primitive text and inline spans only."));
4460
+ });
4461
+ state.nodes.set(id, {
4462
+ ...semanticBase(state, node, id, "text", path, material),
4463
+ kind: "text",
4464
+ inlineChildren
4465
+ });
4466
+ return {
4467
+ id,
4468
+ kind: "text"
4469
+ };
4470
+ }
4471
+ function collectInlineText(state, children, path) {
4472
+ let text = "";
4473
+ children.forEach((child, index) => {
4474
+ if (child.kind === "text") {
4475
+ text += typeof child.value === "string" ? child.value : String(child.value);
4476
+ return;
4477
+ }
4478
+ if (child.kind === "fragment") {
4479
+ text += collectInlineText(state, child.children, `${path} > fragment[${keySegment(child.key, index)}]`);
4480
+ return;
4481
+ }
4482
+ if (child.source.kind === "tag" && child.source.tag === "span") {
4483
+ text += collectInlineText(state, child.children, `${path} > span[${keySegment(child.key, index)}]`);
4484
+ return;
4485
+ }
4486
+ addDiagnostic(state, invalidStructure(`${path} > ${sourceName(child)}[${index}]`, "block content cannot appear inside span", "span accepts primitive text or nested inline spans only."));
4487
+ });
4488
+ return text;
4489
+ }
4490
+ function buildNode(state, node, context, index) {
4491
+ if (node.kind === "fragment") return;
4492
+ if (node.kind === "text") return context.inline ? buildTextRunFromLeaf(state, node, context, index) : buildImplicitTextNode(state, node, context, index);
4493
+ const kind = nodeSemanticKind(node);
4494
+ const segment = `${sourceName(node)}:${keySegment(node.key, index)}`;
4495
+ const material = [...context.parentMaterial, segment];
4496
+ const id = graphNodeId(material);
4497
+ const path = `${context.path} > ${sourceName(node)}[${keySegment(node.key, index)}]`;
4498
+ if (kind === "textRun") {
4499
+ if (!context.inline) {
4500
+ addDiagnostic(state, invalidStructure(path, "span cannot appear here", "span must be inside a text-like element.", ["Wrap the span in <p>...</p> or move it inside an existing text element."]));
4501
+ return;
4502
+ }
4503
+ const text = collectInlineText(state, node.children, path);
4504
+ state.nodes.set(id, {
4505
+ ...semanticBase(state, node, id, "textRun", path, material),
4506
+ kind: "textRun",
4507
+ text
4508
+ });
4509
+ return {
4510
+ id,
4511
+ kind: "textRun"
4512
+ };
4513
+ }
4514
+ if (kind === "text") return buildTextLikeNode(state, node, id, path, material);
4515
+ if (kind === "image") {
4516
+ if (node.children.length > 0) addDiagnostic(state, invalidStructure(path, "image cannot have children", "Image nodes are leaf nodes."));
4517
+ const assetRef = assetForImage(state, material, node.props, path);
4518
+ state.nodes.set(id, {
4519
+ ...semanticBase(state, node, id, "image", path, material),
4520
+ kind: "image",
4521
+ ...assetRef ? { assetRef } : {}
4522
+ });
4523
+ return {
4524
+ id,
4525
+ kind: "image"
4526
+ };
4527
+ }
4528
+ const childIds = buildChildren(state, node.children, {
4529
+ parentId: id,
4530
+ parentMaterial: material,
4531
+ path,
4532
+ inline: false
4533
+ });
4534
+ state.nodes.set(id, {
4535
+ ...semanticBase(state, node, id, kind, path, material),
4536
+ kind,
4537
+ children: childIds
4538
+ });
4539
+ return {
4540
+ id,
4541
+ kind
4542
+ };
4543
+ }
4544
+ function buildSemanticAuthorGraph(roots) {
4545
+ const documentId = graphNodeId(["document", "root"]);
4546
+ const state = {
4547
+ nodes: /* @__PURE__ */ new Map(),
4548
+ styles: /* @__PURE__ */ new Map(),
4549
+ assets: /* @__PURE__ */ new Map(),
4550
+ diagnostics: []
4551
+ };
4552
+ const documentNode = {
4553
+ id: documentId,
4554
+ kind: "document",
4555
+ origin: {
4556
+ kind: "implicit",
4557
+ path: "document"
4558
+ },
4559
+ role: { kind: "document" },
4560
+ children: buildChildren(state, roots, {
4561
+ parentId: documentId,
4562
+ parentMaterial: ["document", "root"],
4563
+ path: "document",
4564
+ inline: false
4565
+ })
4566
+ };
4567
+ state.nodes.set(documentId, documentNode);
4568
+ const diagnostics = createDiagnostics(state.diagnostics);
4569
+ return {
4570
+ graph: {
4571
+ documentId,
4572
+ nodes: state.nodes,
4573
+ styles: state.styles,
4574
+ assets: state.assets
4575
+ },
4576
+ diagnostics
4112
4577
  };
4113
4578
  }
4114
4579
  //#endregion
@@ -14974,6 +15439,24 @@ function toPptxTabStops(tabStops) {
14974
15439
  ...tabStop.alignment ? { alignment: tabStop.alignment } : {}
14975
15440
  }));
14976
15441
  }
15442
+ function toPptxTextRunOptions(style) {
15443
+ if (!style) return;
15444
+ const options = {
15445
+ fontFace: style.fontFamily,
15446
+ fontSize: style.fontSizePt,
15447
+ color: style.color,
15448
+ bold: style.fontWeight === "bold" || typeof style.fontWeight === "number" && style.fontWeight >= 600,
15449
+ italic: style.italic,
15450
+ underline: toPptxUnderline(style),
15451
+ strike: style.strike,
15452
+ charSpacing: style.charSpacing,
15453
+ superscript: style.superscript,
15454
+ subscript: style.subscript,
15455
+ breakLine: false
15456
+ };
15457
+ if (Object.values(options).every((value) => value === void 0 || value === false)) return;
15458
+ return options;
15459
+ }
14977
15460
  function emitOutlineShape(slide, shapeName, frame, outline, radiusEmu, effectiveOpacity, rotation, flipH, flipV) {
14978
15461
  if (!outline) return;
14979
15462
  const insetEmu = pointsToEmu(outline.widthPt) / 2;
@@ -15048,7 +15531,14 @@ function emitText(slide, node, inheritedOpacity) {
15048
15531
  emitOutlineShape(slide, node.radiusEmu && node.radiusEmu > 0 ? "roundRect" : "rect", node.frame, node.outline, node.radiusEmu, effectiveOpacity, node.rotation, node.flipH, node.flipV);
15049
15532
  emitEdgeStrokes(slide, node.frame, node.edgeStrokes, effectiveOpacity, node.rotation, node.flipH, node.flipV);
15050
15533
  emitBackgroundLayers(slide, node.frame, node.backgroundLayers, node.radiusEmu && node.radiusEmu > 0 ? "roundRect" : "rect", node.radiusEmu, effectiveOpacity, node.rotation, node.flipH, node.flipV);
15051
- slide.addText(node.content.text, {
15534
+ const textContent = node.content.runs ? node.content.runs.map((run) => {
15535
+ const options = toPptxTextRunOptions(run.style);
15536
+ return {
15537
+ text: run.text,
15538
+ ...options ? { options } : {}
15539
+ };
15540
+ }) : node.content.text;
15541
+ slide.addText(textContent, {
15052
15542
  x: emuToInches(node.frame.xEmu),
15053
15543
  y: emuToInches(node.frame.yEmu),
15054
15544
  w: emuToInches(node.frame.widthEmu),
@@ -15212,6 +15702,33 @@ async function outputPresentation(presentation, config) {
15212
15702
  }
15213
15703
  //#endregion
15214
15704
  //#region src/deck.ts
15705
+ function isSlideRoot(value) {
15706
+ return value.kind === "element" && value.source.kind === "component" && value.source.component === "Slide";
15707
+ }
15708
+ function describeInvalidRoot(value) {
15709
+ if (isLegacyAuthorNode(value)) return "Slide factory returned a legacy author node.";
15710
+ if (isAuthorTreeNode(value)) return "Slide factory returned an author tree node that is not a <Slide /> root.";
15711
+ if (value === null) return "Slide factory returned null.";
15712
+ return `Slide factory returned ${typeof value}.`;
15713
+ }
15714
+ function invalidRootSourceSpan(value) {
15715
+ return isAuthorTreeNode(value) ? value.sourceSpan : void 0;
15716
+ }
15717
+ function invalidRootDiagnostic(value, slideIndex) {
15718
+ const path = `document > slideFactory[${slideIndex}]`;
15719
+ return diagnostic({
15720
+ severity: "error",
15721
+ code: "E_COMPILE_ROOT",
15722
+ title: "slide factory must return a <Slide /> root",
15723
+ message: describeInvalidRoot(value),
15724
+ labels: [{
15725
+ path,
15726
+ message: "Expected a deckjsx Author Tree <Slide /> node.",
15727
+ ...invalidRootSourceSpan(value) ? { sourceSpan: invalidRootSourceSpan(value) } : {}
15728
+ }],
15729
+ help: ["Return <Slide>...</Slide> from the slide factory passed to deck.add()."]
15730
+ });
15731
+ }
15215
15732
  var Deck = class {
15216
15733
  #options;
15217
15734
  #slides = [];
@@ -15225,9 +15742,38 @@ var Deck = class {
15225
15742
  render() {
15226
15743
  return renderPresentation(this.#options, this.#slides);
15227
15744
  }
15745
+ compile(config = {}) {
15746
+ const roots = [];
15747
+ const diagnostics = [];
15748
+ this.#slides.forEach((factory, slideIndex) => {
15749
+ const root = factory({
15750
+ slideIndex,
15751
+ totalSlides: this.#slides.length,
15752
+ context: {
15753
+ slideIndex,
15754
+ totalSlides: this.#slides.length
15755
+ }
15756
+ });
15757
+ if (!isAuthorTreeNode(root) || !isSlideRoot(root)) {
15758
+ diagnostics.push(invalidRootDiagnostic(root, slideIndex));
15759
+ return;
15760
+ }
15761
+ roots.push(root);
15762
+ });
15763
+ if (diagnostics.length > 0) {
15764
+ const result = { diagnostics: createDiagnostics(diagnostics) };
15765
+ if (config.mode === "inspect") return result;
15766
+ throw new SemanticGraphDiagnosticError(result.diagnostics);
15767
+ }
15768
+ const result = buildSemanticAuthorGraph(roots);
15769
+ if (config.mode === "inspect") return result;
15770
+ if (result.diagnostics.hasErrors) throw new SemanticGraphDiagnosticError(result.diagnostics);
15771
+ if (!result.graph) throw new SemanticGraphDiagnosticError(result.diagnostics);
15772
+ return result.graph;
15773
+ }
15228
15774
  async output(config) {
15229
15775
  await outputPresentation(this.render(), config);
15230
15776
  }
15231
15777
  };
15232
15778
  //#endregion
15233
- export { Deck, EMU_PER_INCH, Fragment, Image, POINTS_PER_INCH, Shape, Slide, Text, View, createElement, isAuthorNode, isContentNode, isSlideNode, pptxgenjsBackend };
15779
+ export { Deck, DeckDiagnosticError, EMU_PER_INCH, Fragment, Image, POINTS_PER_INCH, SemanticGraphDiagnosticError, Shape, Slide, Text, View, createElement, formatDiagnostic, formatDiagnostics, isAuthorNode, isContentNode, isSlideNode, pptxgenjsBackend };