deckjsx 0.6.0 → 0.7.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/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { a as diagnostic, c as SemanticGraphDiagnosticError, d as formatDiagnostics, i as createDiagnostics, l as StyleDiagnosticError, n as EMU_PER_INCH, o as CompositionDiagnosticError, r as POINTS_PER_INCH, s as DeckDiagnosticError, t as pptxgenjs, u as formatDiagnostic } from "./adapter-BbtteJ7s.mjs";
2
- import { a as isContentNode, c as Shape, d as View, f as isAuthorNodeValue, h as isAuthoredTag, i as isAuthorNode, l as Slide, m as isAuthorTreeNode, n as createElement, o as isSlideNode, p as toAuthorJsxNode, s as Image, t as Fragment, u as Text } from "./jsx-C671yNZa.mjs";
1
+ import { a as diagnostic, c as SemanticGraphDiagnosticError, d as formatDiagnostics, i as createDiagnostics, l as StyleDiagnosticError, n as EMU_PER_INCH, o as CompositionDiagnosticError, r as POINTS_PER_INCH, s as DeckDiagnosticError, t as pptxgenjs, u as formatDiagnostic } from "./adapter-rS3mWdi0.mjs";
2
+ import { a as isContentNode, c as Shape, d as isAuthorNodeValue, f as toAuthorJsxNode, h as isAuthoredTag, i as isAuthorNode, l as Text, m as isAuthorTreeNode, n as createElement, o as isSlideNode, p as createAuthorElement, s as Image, t as Fragment, u as View } from "./jsx-DetoUfLm.mjs";
3
3
  import { mkdir, writeFile } from "node:fs/promises";
4
4
  import { dirname } from "node:path";
5
5
  //#region src/composition/types.ts
@@ -20,6 +20,226 @@ function stageSummary(stage, diagnostics, artifact) {
20
20
  artifact
21
21
  };
22
22
  }
23
+ const DEFAULT_FONT_SIZE_PT = 16 / 96 * 72;
24
+ const CH_WIDTH_RATIO = .5;
25
+ const DECK_LENGTH_PATTERN = /^[-+]?(?:\d+|\d*\.\d+)(?:in|pt|px|%|em|rem|vh|vw|ch)$/i;
26
+ const DECK_POINT_LENGTH_PATTERN = /^[-+]?(?:\d+|\d*\.\d+)(?:pt|in|px|em|rem|vh|vw|ch)$/i;
27
+ function pointsToEmu(value) {
28
+ return value / 72 * EMU_PER_INCH;
29
+ }
30
+ function parsePercentage$1(value) {
31
+ const trimmed = value.trim();
32
+ if (!trimmed.endsWith("%")) return;
33
+ return Number.parseFloat(trimmed.slice(0, -1));
34
+ }
35
+ function resolvePointUnitBase(context) {
36
+ return context?.fontSizePt ?? DEFAULT_FONT_SIZE_PT;
37
+ }
38
+ function isDeckLengthString(value) {
39
+ return DECK_LENGTH_PATTERN.test(value.trim());
40
+ }
41
+ function isDeckPointLengthString(value) {
42
+ return DECK_POINT_LENGTH_PATTERN.test(value.trim());
43
+ }
44
+ function parseLengthToken(value, baseEmu, fallback = 0, context) {
45
+ const trimmed = value.trim();
46
+ if (trimmed === "0") return 0;
47
+ if (!isDeckLengthString(trimmed)) throw new Error(`Unsupported length value: ${value}`);
48
+ return parseLength(trimmed, baseEmu, fallback, context);
49
+ }
50
+ function parsePointToken(value, fallback = 0, context) {
51
+ const trimmed = value.trim();
52
+ if (trimmed === "0") return 0;
53
+ if (!isDeckPointLengthString(trimmed)) throw new Error(`Unsupported point value: ${value}`);
54
+ return parsePointValue(trimmed, fallback, context);
55
+ }
56
+ function parsePointValue(value, fallback = 0, context) {
57
+ if (value === void 0) return fallback;
58
+ if (typeof value === "number") return value;
59
+ if (value.endsWith("pt")) return Number.parseFloat(value.slice(0, -2));
60
+ if (value.endsWith("in")) return Number.parseFloat(value.slice(0, -2)) * 72;
61
+ if (value.endsWith("px")) return Number.parseFloat(value.slice(0, -2)) / 96 * 72;
62
+ if (value.endsWith("rem")) return Number.parseFloat(value.slice(0, -3)) * DEFAULT_FONT_SIZE_PT;
63
+ if (value.endsWith("em")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context);
64
+ if (value.endsWith("ch")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context) * CH_WIDTH_RATIO;
65
+ if (value.endsWith("vw")) {
66
+ const viewportWidthEmu = context?.viewportWidthEmu;
67
+ if (viewportWidthEmu === void 0) throw new Error(`Unsupported viewport point value without viewport context: ${value}`);
68
+ return viewportWidthEmu * Number.parseFloat(value.slice(0, -2)) / 100 / EMU_PER_INCH * 72;
69
+ }
70
+ if (value.endsWith("vh")) {
71
+ const viewportHeightEmu = context?.viewportHeightEmu;
72
+ if (viewportHeightEmu === void 0) throw new Error(`Unsupported viewport point value without viewport context: ${value}`);
73
+ return viewportHeightEmu * Number.parseFloat(value.slice(0, -2)) / 100 / EMU_PER_INCH * 72;
74
+ }
75
+ throw new Error(`Unsupported point value: ${value}`);
76
+ }
77
+ function parseStrokeWidth(value, fallback = 0, context) {
78
+ if (value === void 0) return fallback;
79
+ if (typeof value === "number") return value;
80
+ if (value.endsWith("pt")) return Number.parseFloat(value.slice(0, -2));
81
+ if (value.endsWith("in")) return Number.parseFloat(value.slice(0, -2)) * 72;
82
+ if (value.endsWith("px")) return Number.parseFloat(value.slice(0, -2)) / 96 * 72;
83
+ if (value.endsWith("rem")) return Number.parseFloat(value.slice(0, -3)) * DEFAULT_FONT_SIZE_PT;
84
+ if (value.endsWith("em")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context);
85
+ if (value.endsWith("ch")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context) * CH_WIDTH_RATIO;
86
+ if (value.endsWith("vw")) {
87
+ const viewportWidthEmu = context?.viewportWidthEmu;
88
+ if (viewportWidthEmu === void 0) throw new Error(`Unsupported viewport stroke width without viewport context: ${value}`);
89
+ return viewportWidthEmu * Number.parseFloat(value.slice(0, -2)) / 100 / EMU_PER_INCH * 72;
90
+ }
91
+ if (value.endsWith("vh")) {
92
+ const viewportHeightEmu = context?.viewportHeightEmu;
93
+ if (viewportHeightEmu === void 0) throw new Error(`Unsupported viewport stroke width without viewport context: ${value}`);
94
+ return viewportHeightEmu * Number.parseFloat(value.slice(0, -2)) / 100 / EMU_PER_INCH * 72;
95
+ }
96
+ throw new Error(`Unsupported stroke width: ${value}`);
97
+ }
98
+ function parseLength(value, baseEmu, fallback = 0, context) {
99
+ if (value === void 0) return fallback;
100
+ if (typeof value === "number") return value * EMU_PER_INCH;
101
+ if (value.endsWith("%")) return baseEmu * Number.parseFloat(value.slice(0, -1)) / 100;
102
+ if (value.endsWith("in")) return Number.parseFloat(value.slice(0, -2)) * EMU_PER_INCH;
103
+ if (value.endsWith("pt")) return Number.parseFloat(value.slice(0, -2)) / 72 * EMU_PER_INCH;
104
+ if (value.endsWith("px")) return Number.parseFloat(value.slice(0, -2)) / 96 * EMU_PER_INCH;
105
+ if (value.endsWith("rem")) return Number.parseFloat(value.slice(0, -3)) * DEFAULT_FONT_SIZE_PT * EMU_PER_INCH / 72;
106
+ if (value.endsWith("em")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context) * EMU_PER_INCH / 72;
107
+ if (value.endsWith("ch")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context) * CH_WIDTH_RATIO * EMU_PER_INCH / 72;
108
+ if (value.endsWith("vw")) {
109
+ const viewportWidthEmu = context?.viewportWidthEmu;
110
+ if (viewportWidthEmu === void 0) throw new Error(`Unsupported viewport length without viewport context: ${value}`);
111
+ return viewportWidthEmu * Number.parseFloat(value.slice(0, -2)) / 100;
112
+ }
113
+ if (value.endsWith("vh")) {
114
+ const viewportHeightEmu = context?.viewportHeightEmu;
115
+ if (viewportHeightEmu === void 0) throw new Error(`Unsupported viewport length without viewport context: ${value}`);
116
+ return viewportHeightEmu * Number.parseFloat(value.slice(0, -2)) / 100;
117
+ }
118
+ throw new Error(`Unsupported length value: ${value}`);
119
+ }
120
+ //#endregion
121
+ //#region src/templates.ts
122
+ const TEMPLATE_AREA_REF = Symbol("deckjsx.templateAreaRef");
123
+ /**
124
+ * Create the runtime template handle passed to a templated slide factory.
125
+ *
126
+ * @param templates - Deck-local Slide Template set.
127
+ * @param name - Selected Slide Template name.
128
+ * @returns A handle exposing `$name` and typed Template Area References for the selected template.
129
+ */
130
+ function createTemplateHandle(templates, name) {
131
+ const template = templates[name];
132
+ const handle = { $name: name };
133
+ if (template && isRecord$2(template.areas)) Object.keys(template.areas).forEach((area) => {
134
+ handle[area] = createTemplateAreaRef(name, area);
135
+ });
136
+ return handle;
137
+ }
138
+ /**
139
+ * Create an internal Template Area Reference object for a template handle property.
140
+ *
141
+ * @param template - Slide Template name that owns the area.
142
+ * @param area - Template Area name within the template.
143
+ * @returns A branded Template Area Reference accepted by the `area` JSX prop.
144
+ */
145
+ function createTemplateAreaRef(template, area) {
146
+ return {
147
+ type: "deckjsx.templateAreaRef",
148
+ template,
149
+ area,
150
+ [TEMPLATE_AREA_REF]: true
151
+ };
152
+ }
153
+ /**
154
+ * Return whether a value is a deckjsx-created Template Area Reference.
155
+ *
156
+ * @param value - Unknown runtime value to test.
157
+ * @returns `true` when the value carries deckjsx's Template Area Reference runtime brand.
158
+ */
159
+ function isTemplateAreaRef(value) {
160
+ return isRecord$2(value) && value.type === "deckjsx.templateAreaRef" && value[TEMPLATE_AREA_REF] === true && typeof value.template === "string" && typeof value.area === "string";
161
+ }
162
+ /**
163
+ * Extract the serializable template and area names from a Template Area Reference.
164
+ *
165
+ * @param value - Template Area Reference produced by a template handle.
166
+ * @returns The template and area names used by graph construction and diagnostics.
167
+ */
168
+ function templateRefValue(value) {
169
+ return {
170
+ template: value.template,
171
+ area: value.area
172
+ };
173
+ }
174
+ /**
175
+ * Validate a Deck-local Slide Template set and return author-facing diagnostics.
176
+ *
177
+ * @param templates - Deck-local Slide Template set to validate.
178
+ * @param path - Diagnostic path prefix used in labels.
179
+ * @returns Diagnostics for malformed templates, areas, frames, or reserved names.
180
+ */
181
+ function validateSlideTemplates(templates, path = "templates") {
182
+ if (templates === void 0) return [];
183
+ if (!isRecord$2(templates)) return [templateDiagnostic("E_TEMPLATE_SET_INVALID", "invalid slide templates", path)];
184
+ const diagnostics = [];
185
+ Object.entries(templates).forEach(([templateName, template]) => {
186
+ const templatePath = `${path}.${templateName}`;
187
+ if (invalidName(templateName)) diagnostics.push(templateDiagnostic("E_TEMPLATE_RESERVED_NAME", "reserved slide template name", templatePath, `Slide Template name "${templateName}" is invalid.`, ["Template names must not be empty or start with deckjsx-reserved \"$\"."]));
188
+ if (!isRecord$2(template)) {
189
+ diagnostics.push(templateDiagnostic("E_TEMPLATE_INVALID", "invalid slide template", templatePath));
190
+ return;
191
+ }
192
+ if (!isRecord$2(template.areas)) {
193
+ diagnostics.push(templateDiagnostic("E_TEMPLATE_AREAS_INVALID", "invalid template areas", `${templatePath}.areas`));
194
+ return;
195
+ }
196
+ Object.entries(template.areas).forEach(([areaName, area]) => {
197
+ const areaPath = `${templatePath}.areas.${areaName}`;
198
+ if (invalidName(areaName)) diagnostics.push(templateDiagnostic("E_TEMPLATE_AREA_RESERVED_NAME", "reserved template area name", areaPath, `Template Area name "${areaName}" is invalid.`, ["Template Area names must not be empty or start with deckjsx-reserved \"$\"."]));
199
+ if (!isRecord$2(area)) {
200
+ diagnostics.push(templateDiagnostic("E_TEMPLATE_AREA_INVALID", "invalid area", areaPath));
201
+ return;
202
+ }
203
+ diagnostics.push(...validateFrame(area.frame, `${areaPath}.frame`));
204
+ });
205
+ });
206
+ return diagnostics;
207
+ }
208
+ function validateFrame(value, path) {
209
+ if (!isRecord$2(value)) return [templateDiagnostic("E_TEMPLATE_AREA_FRAME_INVALID", "invalid area frame", path)];
210
+ const diagnostics = [];
211
+ [
212
+ "x",
213
+ "y",
214
+ "width",
215
+ "height"
216
+ ].forEach((key) => {
217
+ if (!validLength(value[key])) diagnostics.push(templateDiagnostic("E_TEMPLATE_AREA_FRAME_INCOMPLETE", "template area frame is incomplete", `${path}.${key}`, `Template Area frame must define a valid ${key} value.`));
218
+ });
219
+ return diagnostics;
220
+ }
221
+ function invalidName(value) {
222
+ return value.trim().length === 0 || value.startsWith("$");
223
+ }
224
+ function validLength(value) {
225
+ return typeof value === "number" && Number.isFinite(value) || typeof value === "string" && isDeckLengthString(value);
226
+ }
227
+ function isRecord$2(value) {
228
+ return typeof value === "object" && value !== null && !Array.isArray(value);
229
+ }
230
+ function templateDiagnostic(code, title, path, message = "Slide Template definitions must be an object keyed by template and area names.", help) {
231
+ return diagnostic({
232
+ severity: "error",
233
+ code,
234
+ title,
235
+ message,
236
+ labels: [{
237
+ path,
238
+ message
239
+ }],
240
+ ...help ? { help } : {}
241
+ });
242
+ }
23
243
  //#endregion
24
244
  //#region src/composition/resolve.ts
25
245
  const MAX_COMPOSITION_DEPTH = 64;
@@ -60,13 +280,10 @@ function validateSourceKey(sourceKey) {
60
280
  }
61
281
  function describeInvalidRoot(value) {
62
282
  if (isAuthorNodeValue(value)) return "Slide factory returned an AuthorNode value instead of an Author Tree node.";
63
- if (isAuthorTreeNode(value)) return "Slide factory returned an author tree node that is not a <Slide /> root.";
283
+ if (isAuthorTreeNode(value)) return "Slide factory returned an Author Tree node that cannot be used as slide content.";
64
284
  if (value === null) return "Slide factory returned null.";
65
285
  return `Slide factory returned ${typeof value}.`;
66
286
  }
67
- function isSlideRoot(value) {
68
- return value.kind === "element" && value.source.kind === "component" && value.source.component === "Slide";
69
- }
70
287
  function isPromiseLike(value) {
71
288
  return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
72
289
  }
@@ -158,6 +375,7 @@ function resolveSource(source, context) {
158
375
  let slideCount = 0;
159
376
  const sourceKeys = /* @__PURE__ */ new Set();
160
377
  const slotOrigins = collectSourceSlots(effectiveContext, context);
378
+ validateSlideTemplates(sourceState.templates, `${context.sourcePath} > templates`).forEach((item) => addDiagnostic$1(context, item));
161
379
  const nextContextBase = {
162
380
  diagnostics: context.diagnostics,
163
381
  stack: [...context.stack, sourceState.cycleId],
@@ -168,6 +386,7 @@ function resolveSource(source, context) {
168
386
  entries.push({
169
387
  kind: "slide",
170
388
  factory: entry.factory,
389
+ ...entry.options ? { options: entry.options } : {},
171
390
  path: `${context.sourcePath} > slideFactory[${index}]`
172
391
  });
173
392
  slideCount += 1;
@@ -219,6 +438,7 @@ function resolveSource(source, context) {
219
438
  sourceIdentityMaterial: context.sourceIdentityMaterial,
220
439
  stylesheets: sourceState.stylesheets,
221
440
  ...activeTheme ? { theme: activeTheme } : {},
441
+ ...sourceState.templates ? { templates: sourceState.templates } : {},
222
442
  context: effectiveContext,
223
443
  entries,
224
444
  slideCount,
@@ -245,13 +465,26 @@ function flattenPlan(plan, deckTotalSlides, deckSlideIndex, roots, diagnostics)
245
465
  context: plan.context.value,
246
466
  composition
247
467
  } : { composition };
248
- const root = entry.factory(input);
249
- if (!isAuthorTreeNode(root) || !isSlideRoot(root)) diagnostics.push(compositionDiagnostic({
468
+ const slideTemplate = entry.options?.template;
469
+ const factoryInput = typeof slideTemplate === "string" && plan.templates ? {
470
+ ...input,
471
+ template: createTemplateHandle(plan.templates, slideTemplate)
472
+ } : input;
473
+ const content = entry.factory(factoryInput);
474
+ const root = content === null || content === void 0 || typeof content === "boolean" || isAuthorTreeNode(content) || Array.isArray(content) || typeof content !== "object" ? createAuthorElement({
475
+ source: {
476
+ kind: "component",
477
+ component: "Slide"
478
+ },
479
+ props: entry.options ?? {},
480
+ children: [content]
481
+ }) : content;
482
+ if (!isAuthorTreeNode(root) || root.kind !== "element") diagnostics.push(compositionDiagnostic({
250
483
  code: "E_COMPOSITION_INVALID_ROOT",
251
- title: "slide factory must return a <Slide /> root",
484
+ title: "slide factory must return slide content",
252
485
  path: entry.path,
253
486
  message: describeInvalidRoot(root),
254
- help: ["Return <Slide>...</Slide> from the slide factory passed to deck.add()."]
487
+ help: ["Return JSX content from the factory passed to deck.slide()."]
255
488
  }));
256
489
  else roots.push({
257
490
  root,
@@ -259,6 +492,7 @@ function flattenPlan(plan, deckTotalSlides, deckSlideIndex, roots, diagnostics)
259
492
  sourceIdentityMaterial: plan.sourceIdentityMaterial,
260
493
  stylesheets: plan.stylesheets,
261
494
  ...plan.theme ? { theme: plan.theme } : {},
495
+ ...plan.templates ? { templates: plan.templates } : {},
262
496
  path: entry.path,
263
497
  composition,
264
498
  slotOrigins: plan.slotOrigins
@@ -299,7 +533,7 @@ function appendIndexValue(index, key, value) {
299
533
  values.push(value);
300
534
  index.set(key, values);
301
535
  }
302
- function sourceKeyFor$2(source) {
536
+ function sourceKeyFor$3(source) {
303
537
  return !source || source.kind === "root" ? ROOT_SOURCE_ARTIFACT_KEY$1 : source.sourceIdentity;
304
538
  }
305
539
  function projectionShapeDiagnostics(projection) {
@@ -377,7 +611,7 @@ function safeProjectionParts(projection) {
377
611
  function partsBySourceKey(parts) {
378
612
  const index = /* @__PURE__ */ new Map();
379
613
  parts.forEach((part) => {
380
- appendIndexValue(index, sourceKeyFor$2(part.origin?.source), part.id);
614
+ appendIndexValue(index, sourceKeyFor$3(part.origin?.source), part.id);
381
615
  });
382
616
  return index;
383
617
  }
@@ -1307,13 +1541,13 @@ function themeDiagnostics(theme) {
1307
1541
  }
1308
1542
  //#endregion
1309
1543
  //#region src/style/resolve.ts
1310
- function sourceKeyFor$1(source) {
1544
+ function sourceKeyFor$2(source) {
1311
1545
  return !source || source.kind === "root" ? "root" : source.sourceIdentity;
1312
1546
  }
1313
1547
  function classesBySource(roots) {
1314
1548
  const stylesheets = /* @__PURE__ */ new Map();
1315
1549
  roots.forEach((root) => {
1316
- const key = sourceKeyFor$1(root.source);
1550
+ const key = sourceKeyFor$2(root.source);
1317
1551
  if (!stylesheets.has(key)) stylesheets.set(key, root.stylesheets);
1318
1552
  });
1319
1553
  return stylesheets;
@@ -1322,7 +1556,7 @@ function themesBySource(roots) {
1322
1556
  const themes = /* @__PURE__ */ new Map();
1323
1557
  roots.forEach((root) => {
1324
1558
  if (!root.theme) return;
1325
- themes.set(sourceKeyFor$1(root.source), root.theme);
1559
+ themes.set(sourceKeyFor$2(root.source), root.theme);
1326
1560
  });
1327
1561
  return themes;
1328
1562
  }
@@ -1411,7 +1645,7 @@ function resolveStyles(graph, roots) {
1411
1645
  });
1412
1646
  graph.nodes.forEach((node) => {
1413
1647
  if (!isStyleCapableNode(node)) return;
1414
- const sourceKey = sourceKeyFor$1(node.origin.source);
1648
+ const sourceKey = sourceKeyFor$2(node.origin.source);
1415
1649
  const entity = node.styleRef ? graph.styles.get(node.styleRef) : void 0;
1416
1650
  let registry = registries.get(sourceKey);
1417
1651
  if (!registry) {
@@ -1431,7 +1665,7 @@ const ROOT_SOURCE_ARTIFACT_KEY = "deck:root";
1431
1665
  function combineDiagnostics$1(...diagnostics) {
1432
1666
  return createDiagnostics(diagnostics.flatMap((item) => item.items));
1433
1667
  }
1434
- function sourceKeyFor(source) {
1668
+ function sourceKeyFor$1(source) {
1435
1669
  return !source || source.kind === "root" ? ROOT_SOURCE_ARTIFACT_KEY : source.sourceIdentity;
1436
1670
  }
1437
1671
  var PipelineArtifactCollection = class {
@@ -1476,7 +1710,7 @@ var PipelineArtifactCollection = class {
1476
1710
  }
1477
1711
  const rootsBySourceKey = /* @__PURE__ */ new Map();
1478
1712
  roots.forEach((root) => {
1479
- const sourceKey = sourceKeyFor(root.source);
1713
+ const sourceKey = sourceKeyFor$1(root.source);
1480
1714
  const current = rootsBySourceKey.get(sourceKey);
1481
1715
  if (current) {
1482
1716
  current.rootCount += 1;
@@ -1537,13 +1771,13 @@ var PipelineArtifactCollection = class {
1537
1771
  const sourceByKey = /* @__PURE__ */ new Map();
1538
1772
  sourceByKey.set(ROOT_SOURCE_ARTIFACT_KEY, { kind: "root" });
1539
1773
  input.roots.forEach((root) => {
1540
- sourceByKey.set(sourceKeyFor(root.source), root.source);
1774
+ sourceByKey.set(sourceKeyFor$1(root.source), root.source);
1541
1775
  });
1542
1776
  const nodesBySourceKey = /* @__PURE__ */ new Map();
1543
1777
  const stylesBySourceKey = /* @__PURE__ */ new Map();
1544
1778
  const assetsBySourceKey = /* @__PURE__ */ new Map();
1545
1779
  input.graph.nodes.forEach((node) => {
1546
- const sourceKey = sourceKeyFor(node.origin.source);
1780
+ const sourceKey = sourceKeyFor$1(node.origin.source);
1547
1781
  sourceByKey.set(sourceKey, node.origin.source ?? { kind: "root" });
1548
1782
  const nodeIds = nodesBySourceKey.get(sourceKey) ?? [];
1549
1783
  nodeIds.push(node.id);
@@ -1772,9 +2006,12 @@ function classRefsFor(value) {
1772
2006
  }));
1773
2007
  }
1774
2008
  function directStyleProps(props) {
1775
- const { children: _children, className: _className, data: _data, name: _name, shape: _shape, src: _src, style: _style, ...directStyle } = props;
2009
+ const { children: _children, className: _className, data: _data, area: _area, name: _name, shape: _shape, src: _src, style: _style, template: _template, ...directStyle } = props;
1776
2010
  return Object.keys(directStyle).length === 0 ? void 0 : directStyle;
1777
2011
  }
2012
+ function sourceKeyFor(source) {
2013
+ return !source || source.kind === "root" ? "root" : source.sourceIdentity;
2014
+ }
1778
2015
  function mergedAuthoredStyle(props) {
1779
2016
  const directStyle = directStyleProps(props);
1780
2017
  const inlineStyle = props.style;
@@ -1840,6 +2077,7 @@ function assetForImage(state, idMaterial, props, path) {
1840
2077
  }
1841
2078
  function semanticBase(state, node, id, kind, path, material, context) {
1842
2079
  const styleRef = styleRefFor(state, material, kind, node.props);
2080
+ const templateAreaRef = templateAreaRefFor(state, node.props.area, path, context);
1843
2081
  return {
1844
2082
  id,
1845
2083
  kind,
@@ -1848,9 +2086,88 @@ function semanticBase(state, node, id, kind, path, material, context) {
1848
2086
  ...node.source.kind === "component" ? { authoredComponent: node.source.component } : {},
1849
2087
  ...node.key !== void 0 ? { key: node.key } : {},
1850
2088
  ...nodeRole(node) ? { role: nodeRole(node) } : {},
1851
- ...styleRef ? { styleRef } : {}
2089
+ ...styleRef ? { styleRef } : {},
2090
+ ...templateAreaRef ? { templateAreaRef } : {}
1852
2091
  };
1853
2092
  }
2093
+ function templateAreaDiagnostic(input) {
2094
+ return diagnostic({
2095
+ severity: "error",
2096
+ code: input.code,
2097
+ title: input.title,
2098
+ message: input.message,
2099
+ labels: [{
2100
+ path: input.path,
2101
+ message: input.message
2102
+ }],
2103
+ ...input.help ? { help: input.help } : {}
2104
+ });
2105
+ }
2106
+ function templateAreaRefFor(state, value, path, context) {
2107
+ if (value === void 0) return;
2108
+ if (!isTemplateAreaRef(value)) {
2109
+ addDiagnostic(state, templateAreaDiagnostic({
2110
+ code: "E_TEMPLATE_AREA_REF_INVALID",
2111
+ title: "template area reference is invalid",
2112
+ path,
2113
+ message: "The area prop must receive a Template Area Reference from the slide factory.",
2114
+ help: ["Use area={template.areaName} inside deck.slide({ template }, ...)."]
2115
+ }));
2116
+ return;
2117
+ }
2118
+ const ref = templateRefValue(value);
2119
+ if (!context.activeSlideTemplate) {
2120
+ addDiagnostic(state, templateAreaDiagnostic({
2121
+ code: "E_TEMPLATE_AREA_WITHOUT_TEMPLATE",
2122
+ title: "template area used without active template",
2123
+ path,
2124
+ message: `Template area "${ref.area}" was used on a slide without an active Slide Template.`
2125
+ }));
2126
+ return;
2127
+ }
2128
+ if (ref.template !== context.activeSlideTemplate) {
2129
+ addDiagnostic(state, templateAreaDiagnostic({
2130
+ code: "E_TEMPLATE_AREA_REF_MISMATCH",
2131
+ title: "template area belongs to another template",
2132
+ path,
2133
+ message: `Template area "${ref.area}" belongs to Slide Template "${ref.template}", but the active Slide Template is "${context.activeSlideTemplate}".`,
2134
+ help: ["Use the template handle passed to this slide factory."]
2135
+ }));
2136
+ return;
2137
+ }
2138
+ if (!context.directSlideChild) {
2139
+ addDiagnostic(state, templateAreaDiagnostic({
2140
+ code: "E_TEMPLATE_AREA_NESTED",
2141
+ title: "template area is nested",
2142
+ path,
2143
+ message: `Template area "${ref.area}" must be attached to a direct slide child.`,
2144
+ help: ["Place the area prop on a slide direct child, or wrap nested content in a container."]
2145
+ }));
2146
+ return;
2147
+ }
2148
+ if (!(context.activeSlideTemplates?.[ref.template])?.areas?.[ref.area]) {
2149
+ addDiagnostic(state, templateAreaDiagnostic({
2150
+ code: "E_TEMPLATE_AREA_NOT_FOUND",
2151
+ title: "template area was not found",
2152
+ path,
2153
+ message: `Template area "${ref.area}" does not exist in Slide Template "${ref.template}".`
2154
+ }));
2155
+ return;
2156
+ }
2157
+ const existing = context.usedTemplateAreas?.get(ref.area);
2158
+ if (existing) {
2159
+ addDiagnostic(state, templateAreaDiagnostic({
2160
+ code: "E_TEMPLATE_AREA_DUPLICATE",
2161
+ title: "template area is used more than once",
2162
+ path,
2163
+ message: `Template area "${ref.area}" is already used by ${existing}.`,
2164
+ help: ["Wrap multiple elements in a single container that carries the area prop."]
2165
+ }));
2166
+ return;
2167
+ }
2168
+ context.usedTemplateAreas?.set(ref.area, path);
2169
+ return ref;
2170
+ }
1854
2171
  function buildTextRunFromLeaf(state, leaf, context, index) {
1855
2172
  const text = typeof leaf.value === "string" ? leaf.value : String(leaf.value);
1856
2173
  if (text.trim().length === 0) return;
@@ -1921,7 +2238,8 @@ function buildTextLikeNode(state, node, id, path, material, context) {
1921
2238
  parentId: id,
1922
2239
  parentMaterial: material,
1923
2240
  path,
1924
- inline: true
2241
+ inline: true,
2242
+ directSlideChild: false
1925
2243
  }, index);
1926
2244
  if (run) inlineChildren.push(run.id);
1927
2245
  return;
@@ -1932,7 +2250,8 @@ function buildTextLikeNode(state, node, id, path, material, context) {
1932
2250
  parentId: id,
1933
2251
  parentMaterial: material,
1934
2252
  path,
1935
- inline: true
2253
+ inline: true,
2254
+ directSlideChild: false
1936
2255
  });
1937
2256
  const segment = `fragment:${keySegment(child.key, index)}`;
1938
2257
  inlineChildren.push(...buildChildren(state, child.children, {
@@ -1948,7 +2267,8 @@ function buildTextLikeNode(state, node, id, path, material, context) {
1948
2267
  parentId: id,
1949
2268
  parentMaterial: material,
1950
2269
  path,
1951
- inline: true
2270
+ inline: true,
2271
+ directSlideChild: false
1952
2272
  }, index);
1953
2273
  if (built) inlineChildren.push(built.id);
1954
2274
  return;
@@ -2034,6 +2354,14 @@ function buildNode(state, node, context, index) {
2034
2354
  kind: "shape"
2035
2355
  };
2036
2356
  }
2357
+ const slideTemplateName = kind === "slide" && typeof node.props.template === "string" ? node.props.template : void 0;
2358
+ const slideTemplates = kind === "slide" ? state.templates.get(sourceKeyFor(sourceFor(nodeContext))) : void 0;
2359
+ if (kind === "slide" && slideTemplateName && !slideTemplates?.[slideTemplateName]) addDiagnostic(state, templateAreaDiagnostic({
2360
+ code: "E_TEMPLATE_NOT_FOUND",
2361
+ title: "slide template was not found",
2362
+ path,
2363
+ message: `Slide Template "${slideTemplateName}" is not defined for this Deck source.`
2364
+ }));
2037
2365
  const childIds = buildChildren(state, node.children, {
2038
2366
  parentId: id,
2039
2367
  parentMaterial: material,
@@ -2041,12 +2369,17 @@ function buildNode(state, node, context, index) {
2041
2369
  inline: false,
2042
2370
  source: sourceFor(nodeContext),
2043
2371
  slotOrigins: nodeContext.slotOrigins,
2044
- activeSlot: nodeContext.activeSlot
2372
+ activeSlot: nodeContext.activeSlot,
2373
+ activeSlideTemplate: slideTemplateName ?? nodeContext.activeSlideTemplate,
2374
+ activeSlideTemplates: kind === "slide" ? slideTemplates : nodeContext.activeSlideTemplates,
2375
+ directSlideChild: kind === "slide",
2376
+ usedTemplateAreas: kind === "slide" ? /* @__PURE__ */ new Map() : nodeContext.usedTemplateAreas
2045
2377
  });
2046
2378
  state.nodes.set(id, {
2047
2379
  ...semanticBase(state, node, id, kind, path, material, nodeContext),
2048
2380
  kind,
2049
2381
  ...kind === "slide" && typeof node.props.name === "string" ? { name: node.props.name } : {},
2382
+ ...kind === "slide" && slideTemplateName ? { templateRef: { name: slideTemplateName } } : {},
2050
2383
  children: childIds
2051
2384
  });
2052
2385
  return {
@@ -2080,11 +2413,13 @@ function buildSemanticAuthorGraph(roots) {
2080
2413
  nodes: /* @__PURE__ */ new Map(),
2081
2414
  styles: /* @__PURE__ */ new Map(),
2082
2415
  assets: /* @__PURE__ */ new Map(),
2416
+ templates: /* @__PURE__ */ new Map(),
2083
2417
  diagnostics: []
2084
2418
  };
2085
2419
  const slideIds = [];
2086
2420
  roots.forEach((root, index) => {
2087
2421
  const composed = "root" in root ? root : asComposedRoot(root, index);
2422
+ if (composed.templates) state.templates.set(sourceKeyFor(composed.source), composed.templates);
2088
2423
  const built = buildNode(state, composed.root, {
2089
2424
  parentId: documentId,
2090
2425
  parentMaterial: [
@@ -2095,7 +2430,10 @@ function buildSemanticAuthorGraph(roots) {
2095
2430
  path: composed.path,
2096
2431
  inline: false,
2097
2432
  source: composed.source,
2098
- slotOrigins: composed.slotOrigins
2433
+ slotOrigins: composed.slotOrigins,
2434
+ activeSlideTemplate: void 0,
2435
+ activeSlideTemplates: void 0,
2436
+ directSlideChild: false
2099
2437
  }, composed.composition.slideIndex);
2100
2438
  if (built) slideIds.push(built.id);
2101
2439
  });
@@ -2117,108 +2455,12 @@ function buildSemanticAuthorGraph(roots) {
2117
2455
  documentId,
2118
2456
  nodes: state.nodes,
2119
2457
  styles: state.styles,
2120
- assets: state.assets
2458
+ assets: state.assets,
2459
+ templates: state.templates
2121
2460
  },
2122
2461
  diagnostics
2123
2462
  };
2124
2463
  }
2125
- const DEFAULT_FONT_SIZE_PT = 16 / 96 * 72;
2126
- const CH_WIDTH_RATIO = .5;
2127
- const DECK_LENGTH_PATTERN = /^[-+]?(?:\d+|\d*\.\d+)(?:in|pt|px|%|em|rem|vh|vw|ch)$/i;
2128
- const DECK_POINT_LENGTH_PATTERN = /^[-+]?(?:\d+|\d*\.\d+)(?:pt|in|px|em|rem|vh|vw|ch)$/i;
2129
- function pointsToEmu(value) {
2130
- return value / 72 * EMU_PER_INCH;
2131
- }
2132
- function parsePercentage$1(value) {
2133
- const trimmed = value.trim();
2134
- if (!trimmed.endsWith("%")) return;
2135
- return Number.parseFloat(trimmed.slice(0, -1));
2136
- }
2137
- function resolvePointUnitBase(context) {
2138
- return context?.fontSizePt ?? DEFAULT_FONT_SIZE_PT;
2139
- }
2140
- function isDeckLengthString(value) {
2141
- return DECK_LENGTH_PATTERN.test(value.trim());
2142
- }
2143
- function isDeckPointLengthString(value) {
2144
- return DECK_POINT_LENGTH_PATTERN.test(value.trim());
2145
- }
2146
- function parseLengthToken(value, baseEmu, fallback = 0, context) {
2147
- const trimmed = value.trim();
2148
- if (trimmed === "0") return 0;
2149
- if (!isDeckLengthString(trimmed)) throw new Error(`Unsupported length value: ${value}`);
2150
- return parseLength(trimmed, baseEmu, fallback, context);
2151
- }
2152
- function parsePointToken(value, fallback = 0, context) {
2153
- const trimmed = value.trim();
2154
- if (trimmed === "0") return 0;
2155
- if (!isDeckPointLengthString(trimmed)) throw new Error(`Unsupported point value: ${value}`);
2156
- return parsePointValue(trimmed, fallback, context);
2157
- }
2158
- function parsePointValue(value, fallback = 0, context) {
2159
- if (value === void 0) return fallback;
2160
- if (typeof value === "number") return value;
2161
- if (value.endsWith("pt")) return Number.parseFloat(value.slice(0, -2));
2162
- if (value.endsWith("in")) return Number.parseFloat(value.slice(0, -2)) * 72;
2163
- if (value.endsWith("px")) return Number.parseFloat(value.slice(0, -2)) / 96 * 72;
2164
- if (value.endsWith("rem")) return Number.parseFloat(value.slice(0, -3)) * DEFAULT_FONT_SIZE_PT;
2165
- if (value.endsWith("em")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context);
2166
- if (value.endsWith("ch")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context) * CH_WIDTH_RATIO;
2167
- if (value.endsWith("vw")) {
2168
- const viewportWidthEmu = context?.viewportWidthEmu;
2169
- if (viewportWidthEmu === void 0) throw new Error(`Unsupported viewport point value without viewport context: ${value}`);
2170
- return viewportWidthEmu * Number.parseFloat(value.slice(0, -2)) / 100 / EMU_PER_INCH * 72;
2171
- }
2172
- if (value.endsWith("vh")) {
2173
- const viewportHeightEmu = context?.viewportHeightEmu;
2174
- if (viewportHeightEmu === void 0) throw new Error(`Unsupported viewport point value without viewport context: ${value}`);
2175
- return viewportHeightEmu * Number.parseFloat(value.slice(0, -2)) / 100 / EMU_PER_INCH * 72;
2176
- }
2177
- throw new Error(`Unsupported point value: ${value}`);
2178
- }
2179
- function parseStrokeWidth(value, fallback = 0, context) {
2180
- if (value === void 0) return fallback;
2181
- if (typeof value === "number") return value;
2182
- if (value.endsWith("pt")) return Number.parseFloat(value.slice(0, -2));
2183
- if (value.endsWith("in")) return Number.parseFloat(value.slice(0, -2)) * 72;
2184
- if (value.endsWith("px")) return Number.parseFloat(value.slice(0, -2)) / 96 * 72;
2185
- if (value.endsWith("rem")) return Number.parseFloat(value.slice(0, -3)) * DEFAULT_FONT_SIZE_PT;
2186
- if (value.endsWith("em")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context);
2187
- if (value.endsWith("ch")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context) * CH_WIDTH_RATIO;
2188
- if (value.endsWith("vw")) {
2189
- const viewportWidthEmu = context?.viewportWidthEmu;
2190
- if (viewportWidthEmu === void 0) throw new Error(`Unsupported viewport stroke width without viewport context: ${value}`);
2191
- return viewportWidthEmu * Number.parseFloat(value.slice(0, -2)) / 100 / EMU_PER_INCH * 72;
2192
- }
2193
- if (value.endsWith("vh")) {
2194
- const viewportHeightEmu = context?.viewportHeightEmu;
2195
- if (viewportHeightEmu === void 0) throw new Error(`Unsupported viewport stroke width without viewport context: ${value}`);
2196
- return viewportHeightEmu * Number.parseFloat(value.slice(0, -2)) / 100 / EMU_PER_INCH * 72;
2197
- }
2198
- throw new Error(`Unsupported stroke width: ${value}`);
2199
- }
2200
- function parseLength(value, baseEmu, fallback = 0, context) {
2201
- if (value === void 0) return fallback;
2202
- if (typeof value === "number") return value * EMU_PER_INCH;
2203
- if (value.endsWith("%")) return baseEmu * Number.parseFloat(value.slice(0, -1)) / 100;
2204
- if (value.endsWith("in")) return Number.parseFloat(value.slice(0, -2)) * EMU_PER_INCH;
2205
- if (value.endsWith("pt")) return Number.parseFloat(value.slice(0, -2)) / 72 * EMU_PER_INCH;
2206
- if (value.endsWith("px")) return Number.parseFloat(value.slice(0, -2)) / 96 * EMU_PER_INCH;
2207
- if (value.endsWith("rem")) return Number.parseFloat(value.slice(0, -3)) * DEFAULT_FONT_SIZE_PT * EMU_PER_INCH / 72;
2208
- if (value.endsWith("em")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context) * EMU_PER_INCH / 72;
2209
- if (value.endsWith("ch")) return Number.parseFloat(value.slice(0, -2)) * resolvePointUnitBase(context) * CH_WIDTH_RATIO * EMU_PER_INCH / 72;
2210
- if (value.endsWith("vw")) {
2211
- const viewportWidthEmu = context?.viewportWidthEmu;
2212
- if (viewportWidthEmu === void 0) throw new Error(`Unsupported viewport length without viewport context: ${value}`);
2213
- return viewportWidthEmu * Number.parseFloat(value.slice(0, -2)) / 100;
2214
- }
2215
- if (value.endsWith("vh")) {
2216
- const viewportHeightEmu = context?.viewportHeightEmu;
2217
- if (viewportHeightEmu === void 0) throw new Error(`Unsupported viewport length without viewport context: ${value}`);
2218
- return viewportHeightEmu * Number.parseFloat(value.slice(0, -2)) / 100;
2219
- }
2220
- throw new Error(`Unsupported length value: ${value}`);
2221
- }
2222
2464
  //#endregion
2223
2465
  //#region src/layout/frame.ts
2224
2466
  function intersectClipRect(frame, clipRect) {
@@ -6182,7 +6424,7 @@ function compileNode(child, parentFrame, idGenerator, placement, clipRect, conte
6182
6424
  }
6183
6425
  }
6184
6426
  function compileSlide(root, context, slideFrame, idGenerator, lengthContext, resolutionOptions) {
6185
- if (!isSlideNode(root)) throw new Error(`Slide factory at index ${context.slideIndex} must return a <Slide /> root.`);
6427
+ if (!isSlideNode(root)) throw new Error(`Slide factory at index ${context.slideIndex} must resolve to a slide node.`);
6186
6428
  const slideProps = normalizeSlideProps(root.props);
6187
6429
  const backgroundBoxFrames = resolveBackgroundBoxFrames(slideFrame);
6188
6430
  const backgroundFill = resolveBackgroundLayers(slideProps.backgroundColor ?? slideProps.backgroundImage ?? slideProps.background, slideProps.backgroundTransparency, {
@@ -6246,6 +6488,28 @@ function resolvedPropsFor(node, resolvedStyles) {
6246
6488
  if (!resolved) return {};
6247
6489
  return Object.fromEntries(Object.entries(resolved.properties).filter(([, property]) => property.source.layer !== "default").map(([key, property]) => [key, property.value]));
6248
6490
  }
6491
+ function sourceKeyForOrigin(source) {
6492
+ return !source || source.kind === "root" ? "root" : source.sourceIdentity;
6493
+ }
6494
+ function propsWithTemplateAreaFrame(resolvedStyles, node, templates) {
6495
+ const props = resolvedPropsFor(node, resolvedStyles);
6496
+ const ref = node.templateAreaRef;
6497
+ if (!ref) return props;
6498
+ const frame = templates?.[ref.template]?.areas?.[ref.area]?.frame;
6499
+ if (!frame) return props;
6500
+ const resolved = resolvedStyles.get(node.id);
6501
+ const merged = { ...props };
6502
+ [
6503
+ "x",
6504
+ "y",
6505
+ "width",
6506
+ "height"
6507
+ ].forEach((key) => {
6508
+ if (resolved?.properties[key]?.source.layer === "style") return;
6509
+ merged[key] = frame[key];
6510
+ });
6511
+ return merged;
6512
+ }
6249
6513
  function pushDefined(values, value) {
6250
6514
  if (value !== void 0) values.push(value);
6251
6515
  }
@@ -6294,22 +6558,25 @@ function textChildrenFromGraph(graph, resolvedStyles, childIds, origins) {
6294
6558
  return [];
6295
6559
  });
6296
6560
  }
6297
- function contentChildrenFromGraph(graph, resolvedStyles, childIds, origins) {
6561
+ function contentChildrenFromGraph(graph, resolvedStyles, childIds, origins, templates) {
6298
6562
  return childIds.flatMap((childId) => {
6299
6563
  const child = graph.nodes.get(childId);
6300
6564
  if (!child) return [];
6301
- const node = layoutAuthorNodeFromGraph(graph, resolvedStyles, child, origins);
6565
+ const node = layoutAuthorNodeFromGraph(graph, resolvedStyles, child, origins, templates);
6302
6566
  return node ? [node] : [];
6303
6567
  });
6304
6568
  }
6305
- function layoutAuthorNodeFromGraph(graph, resolvedStyles, node, origins) {
6306
- const props = resolvedPropsFor(node, resolvedStyles);
6569
+ function layoutAuthorNodeFromGraph(graph, resolvedStyles, node, origins, templates) {
6570
+ const props = propsWithTemplateAreaFrame(resolvedStyles, node, templates);
6307
6571
  switch (node.kind) {
6308
- case "slide": return rememberOrigin(layoutNode("slide", {
6309
- ...props,
6310
- name: node.name
6311
- }, contentChildrenFromGraph(graph, resolvedStyles, node.children, origins)), layoutOriginFor(graph, node), origins);
6312
- case "container": return rememberOrigin(layoutNode("view", props, contentChildrenFromGraph(graph, resolvedStyles, node.children, origins)), layoutOriginFor(graph, node), origins);
6572
+ case "slide": {
6573
+ const slideTemplates = graph.templates.get(sourceKeyForOrigin(node.origin.source));
6574
+ return rememberOrigin(layoutNode("slide", {
6575
+ ...props,
6576
+ name: node.name
6577
+ }, contentChildrenFromGraph(graph, resolvedStyles, node.children, origins, slideTemplates)), layoutOriginFor(graph, node), origins);
6578
+ }
6579
+ case "container": return rememberOrigin(layoutNode("view", props, contentChildrenFromGraph(graph, resolvedStyles, node.children, origins, templates)), layoutOriginFor(graph, node), origins);
6313
6580
  case "text": return rememberOrigin(layoutNode("text", props, textChildrenFromGraph(graph, resolvedStyles, node.inlineChildren, origins)), layoutOriginFor(graph, node), origins);
6314
6581
  case "image": {
6315
6582
  const asset = node.assetRef ? graph.assets.get(node.assetRef) : void 0;
@@ -7793,9 +8060,23 @@ function projectedArtifactStatus(value, diagnostics) {
7793
8060
  if (value === void 0) return "missing";
7794
8061
  return diagnostics.hasErrors ? "partial" : "available";
7795
8062
  }
8063
+ /**
8064
+ * A Deck with Source Context already bound.
8065
+ *
8066
+ * Bound sources can be mounted, compiled, projected, or rendered, but they are not an authoring
8067
+ * registration surface. Use `Deck#withSource(...)` when a child Deck requires Source Context and
8068
+ * should be executed as a standalone source.
8069
+ *
8070
+ * @typeParam TSourceContext - The Source Context type already bound to this source.
8071
+ * @typeParam TTemplates - The Deck-local Slide Template set owned by the source Deck.
8072
+ */
7796
8073
  var BoundSource = class {
7797
8074
  #source;
7798
8075
  #sourceContext;
8076
+ /**
8077
+ * @param source - The Deck whose Source Context should be bound.
8078
+ * @param sourceContext - The Source Context value used whenever this source is composed.
8079
+ */
7799
8080
  constructor(source, sourceContext) {
7800
8081
  this.#source = source;
7801
8082
  this.#sourceContext = sourceContext;
@@ -7806,6 +8087,7 @@ var BoundSource = class {
7806
8087
  entries: source.entries,
7807
8088
  stylesheets: source.stylesheets,
7808
8089
  ...source.theme ? { theme: source.theme } : {},
8090
+ ...source.templates ? { templates: source.templates } : {},
7809
8091
  cycleId: source.cycleId,
7810
8092
  boundContext: {
7811
8093
  present: true,
@@ -7813,15 +8095,31 @@ var BoundSource = class {
7813
8095
  }
7814
8096
  };
7815
8097
  }
8098
+ /**
8099
+ * Compile this bound source into a Semantic Author Graph and resolved style inspection data.
8100
+ *
8101
+ * @returns A compile result with diagnostics, stage summaries, and graph artifacts when available.
8102
+ */
7816
8103
  compile() {
7817
8104
  return compileSource(this);
7818
8105
  }
8106
+ /**
8107
+ * Project this bound source into the configured output document model.
8108
+ *
8109
+ * @returns A project result with diagnostics, stage summaries, and the projected model when valid.
8110
+ */
7819
8111
  project() {
7820
8112
  return projectSource({
7821
8113
  source: this,
7822
8114
  options: this.#source.options
7823
8115
  });
7824
8116
  }
8117
+ /**
8118
+ * Render this bound source with the default writer adapter or an explicit Writer Adapter.
8119
+ *
8120
+ * @param config - Render options for the default adapter, or an explicit Writer Adapter.
8121
+ * @returns A Promise resolving to render diagnostics, stage summaries, and an artifact when render succeeds.
8122
+ */
7825
8123
  render(config) {
7826
8124
  return renderSource({
7827
8125
  source: this,
@@ -7830,12 +8128,26 @@ var BoundSource = class {
7830
8128
  });
7831
8129
  }
7832
8130
  };
8131
+ /**
8132
+ * The main authoring object for a deckjsx document.
8133
+ *
8134
+ * A Deck owns slide declarations, source-local stylesheets, optional Theme configuration, and
8135
+ * Deck-local Slide Templates. It compiles JSX authoring into the Semantic Author Graph, projects
8136
+ * that graph into an output document model, and renders the projected model through a writer.
8137
+ *
8138
+ * @typeParam TSourceContext - Source Context required by this Deck's slide factories.
8139
+ * @typeParam TTemplates - Deck-local Slide Template set inferred from `new Deck({ templates })`.
8140
+ */
7833
8141
  var Deck = class {
7834
8142
  #options;
7835
8143
  #entries = [];
7836
8144
  #stylesheets = [];
7837
8145
  #artifacts = new PipelineArtifactCollection();
8146
+ /** Bind Source Context to this Deck so it can be compiled, projected, rendered, or mounted. */
7838
8147
  withSource;
8148
+ /**
8149
+ * @param options - Deck configuration, including layout, metadata, Theme, output format, and Deck Templates.
8150
+ */
7839
8151
  constructor(options) {
7840
8152
  this.#options = options;
7841
8153
  this.withSource = ((sourceContext) => new BoundSource(this, sourceContext));
@@ -7848,19 +8160,30 @@ var Deck = class {
7848
8160
  entries: this.#entries,
7849
8161
  stylesheets: this.#stylesheets,
7850
8162
  ...this.#options.theme ? { theme: this.#options.theme } : {},
8163
+ ...this.#options.templates ? { templates: this.#options.templates } : {},
7851
8164
  cycleId: this,
7852
8165
  boundContext: { present: false }
7853
8166
  };
7854
8167
  }
8168
+ /**
8169
+ * Register a source-local StyleSheet for CSS-like `className` resolution.
8170
+ *
8171
+ * @param stylesheet - The StyleSheet to apply to slides declared by this Deck source.
8172
+ * @returns This Deck, for fluent authoring.
8173
+ */
7855
8174
  useStyles(stylesheet) {
7856
8175
  this.#stylesheets.push(stylesheet);
7857
8176
  this.#artifacts.invalidateFromSource();
7858
8177
  return this;
7859
8178
  }
7860
- add(slide) {
8179
+ slide(optionsOrFactory, maybeFactory) {
8180
+ const options = typeof optionsOrFactory === "function" ? void 0 : optionsOrFactory;
8181
+ const factory = typeof optionsOrFactory === "function" ? optionsOrFactory : maybeFactory;
8182
+ if (!factory) throw new Error("deck.slide() requires a slide factory.");
7861
8183
  this.#entries.push({
7862
8184
  kind: "slide",
7863
- factory: slide
8185
+ ...options ? { options } : {},
8186
+ factory
7864
8187
  });
7865
8188
  this.#artifacts.invalidateFromSource();
7866
8189
  return this;
@@ -7876,10 +8199,22 @@ var Deck = class {
7876
8199
  this.#artifacts.invalidateFromSource();
7877
8200
  return this;
7878
8201
  }
8202
+ /**
8203
+ * Replace the current compiled graph artifact before calling `project()` or `render()`.
8204
+ *
8205
+ * @param graph - The Semantic Author Graph to use as this Deck's compiled state.
8206
+ * @returns This Deck, for fluent pipeline editing.
8207
+ */
7879
8208
  defineGraph(graph) {
7880
8209
  this.#artifacts.replaceGraphArtifact(this, graph);
7881
8210
  return this;
7882
8211
  }
8212
+ /**
8213
+ * Replace the current projected document model artifact before calling `render()`.
8214
+ *
8215
+ * @param projection - The projected PPTX Package Model to use as this Deck's projection state.
8216
+ * @returns This Deck, for fluent pipeline editing.
8217
+ */
7883
8218
  defineProjection(projection) {
7884
8219
  this.#artifacts.replaceProjectionArtifact(projection);
7885
8220
  return this;
@@ -7897,6 +8232,11 @@ var Deck = class {
7897
8232
  }
7898
8233
  return compileSource(this, this.#artifacts);
7899
8234
  }
8235
+ /**
8236
+ * Project this root Deck into the configured output document model.
8237
+ *
8238
+ * @returns A project result with diagnostics, stage summaries, and the projected model when valid.
8239
+ */
7900
8240
  project() {
7901
8241
  return projectSource({
7902
8242
  source: this,
@@ -7906,6 +8246,12 @@ var Deck = class {
7906
8246
  artifacts: this.#artifacts
7907
8247
  });
7908
8248
  }
8249
+ /**
8250
+ * Render this root Deck with the default writer adapter or an explicit Writer Adapter.
8251
+ *
8252
+ * @param config - Render options for the default adapter, or an explicit Writer Adapter.
8253
+ * @returns A Promise resolving to render diagnostics, stage summaries, and an artifact when render succeeds.
8254
+ */
7909
8255
  render(config) {
7910
8256
  return renderSource({
7911
8257
  source: this,
@@ -7918,4 +8264,4 @@ var Deck = class {
7918
8264
  }
7919
8265
  };
7920
8266
  //#endregion
7921
- export { CompositionDiagnosticError, Deck, DeckDiagnosticError, EMU_PER_INCH, Fragment, Image, POINTS_PER_INCH, SemanticGraphDiagnosticError, Shape, Slide, StyleDiagnosticError, StyleSheet, Text, Theme, View, createElement, formatDiagnostic, formatDiagnostics };
8267
+ export { CompositionDiagnosticError, Deck, DeckDiagnosticError, EMU_PER_INCH, Fragment, Image, POINTS_PER_INCH, SemanticGraphDiagnosticError, Shape, StyleDiagnosticError, StyleSheet, Text, Theme, View, createElement, formatDiagnostic, formatDiagnostics };