deckjsx 0.8.2 → 0.8.3

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 { c as isAuthoredTag, i as createAuthorElement, o as isAuthorTreeChild, s as isAuthorTreeNode, t as authorElementPropsFromEntries } from "./tree-DNsco0U3.mjs";
2
- import { A as diagnostic, C as parsePointToken, D as EMU_PER_INCH, E as pointsToEmu, F as formatDiagnostic, I as formatDiagnostics, M as DeckDiagnosticError, N as SemanticGraphDiagnosticError, O as POINTS_PER_INCH, P as StyleDiagnosticError, S as parsePercentage$1, T as parseStrokeWidth, _ as isCssWideKeyword, a as isInspectableThemePayload, b as parseLength, c as fingerprintString, d as createWriterRenderContext, f as createTemplateHandle, g as DEFAULT_FONT_SIZE_PT, h as validateSlideTemplates, i as isContentTypesPayload, j as CompositionDiagnosticError, k as createDiagnostics, l as stableJson, m as templateRefValue, n as pptxMediaAssetLoadRequirements, o as isRecord$2, p as isTemplateAreaRef, r as validatePptxPackageModel, s as projectedRelationshipTarget, t as pptx, u as withPackagePartFingerprints, v as isDeckLengthString, w as parsePointValue, x as parseLengthToken, y as isDeckPointLengthString } from "./adapter-B3Efckbf.mjs";
1
+ import { c as isAuthoredTag, i as createAuthorElement, o as isAuthorTreeChild, s as isAuthorTreeNode, t as authorElementPropsFromEntries } from "./tree-DY5XQegS.mjs";
2
+ import { A as diagnostic, C as parsePointToken, D as EMU_PER_INCH, E as pointsToEmu, F as formatDiagnostic, I as formatDiagnostics, M as DeckDiagnosticError, N as SemanticGraphDiagnosticError, O as POINTS_PER_INCH, P as StyleDiagnosticError, S as parsePercentage$1, T as parseStrokeWidth, _ as isCssWideKeyword, a as isInspectableThemePayload, b as parseLength, c as fingerprintString, d as createWriterRenderContext, f as createTemplateHandle, g as DEFAULT_FONT_SIZE_PT, h as validateSlideTemplates, i as isContentTypesPayload, j as CompositionDiagnosticError, k as createDiagnostics, l as stableJson, m as templateRefValue, n as pptxMediaAssetLoadRequirements, o as isRecord$2, p as isTemplateAreaRef, r as validatePptxPackageModel, s as projectedRelationshipTarget, t as pptx, u as withPackagePartFingerprints, v as isDeckLengthString, w as parsePointValue, x as parseLengthToken, y as isDeckPointLengthString } from "./adapter-CGOiv9ip.mjs";
3
3
  import { n as isPptxMediaPart, o as isPptxSlidePart, r as isPptxPackageModel } from "./model-DIuh51qh.mjs";
4
4
  //#region src/composition/types.ts
5
5
  const COMPOSITION_SOURCE = Symbol("deckjsx.compositionSource");
@@ -318,6 +318,7 @@ function packagePartOrderGroup(part) {
318
318
  if (part.kind === "relationships" && part.path.startsWith("ppt/slideLayouts/_rels/")) return "slideLayoutRelationships";
319
319
  if (part.kind === "view-properties") return "viewProperties";
320
320
  if (part.kind === "presentation-properties") return "presentationProperties";
321
+ if (part.kind === "table-styles") return "tableStyles";
321
322
  if (part.kind === "slide") return "slide";
322
323
  if (part.kind === "relationships" && part.path.startsWith("ppt/slides/_rels/")) return "slideRelationships";
323
324
  if (part.kind === "media") return "media";
@@ -336,6 +337,7 @@ const PACKAGE_PART_ORDER_GROUP_ORDER = {
336
337
  slideLayoutRelationships: 71,
337
338
  viewProperties: 75,
338
339
  presentationProperties: 76,
340
+ tableStyles: 77,
339
341
  slide: 80,
340
342
  slideRelationships: 81,
341
343
  media: 90,
@@ -459,7 +461,7 @@ function normalizePackagePartRequirement(requirement) {
459
461
  function packagePartRequirement(part, relationshipPartIdsByTargetPartId) {
460
462
  if (part.requirement) return normalizePackagePartRequirement(part.requirement);
461
463
  if (part.kind === "media") {
462
- const dependencies = relationshipPartIdsByTargetPartId.get(part.id) ?? [];
464
+ const dependencies = [...new Set(relationshipPartIdsByTargetPartId.get(part.id) ?? [])];
463
465
  return {
464
466
  status: "conditional",
465
467
  required: dependencies.length > 0,
@@ -713,6 +715,21 @@ const ELEMENT_DEFAULTS = {
713
715
  rounding: false,
714
716
  margin: 0
715
717
  },
718
+ video: {
719
+ display: "block",
720
+ visibility: "visible",
721
+ opacity: 1,
722
+ rotation: 0,
723
+ zIndex: 0,
724
+ overflow: "visible",
725
+ position: "static",
726
+ fit: "contain",
727
+ objectFit: "contain",
728
+ objectPosition: "50% 50%",
729
+ transparency: 0,
730
+ rounding: false,
731
+ margin: 0
732
+ },
716
733
  shape: {
717
734
  display: "block",
718
735
  visibility: "visible",
@@ -742,6 +759,7 @@ function elementDefaultsFor(node) {
742
759
  case "text": return ELEMENT_DEFAULTS.text;
743
760
  case "textRun": return ELEMENT_DEFAULTS.textRun;
744
761
  case "image": return ELEMENT_DEFAULTS.image;
762
+ case "video": return ELEMENT_DEFAULTS.video;
745
763
  case "shape": return ELEMENT_DEFAULTS.shape;
746
764
  case "document": return;
747
765
  }
@@ -1411,6 +1429,62 @@ const IMAGE_STYLE_KEYS = [
1411
1429
  "marginBottom",
1412
1430
  "marginLeft"
1413
1431
  ];
1432
+ const VIDEO_STYLE_KEYS = [
1433
+ "opacity",
1434
+ "rotation",
1435
+ "transform",
1436
+ "transformOrigin",
1437
+ "filter",
1438
+ "mixBlendMode",
1439
+ "isolation",
1440
+ "zIndex",
1441
+ "flipH",
1442
+ "flipV",
1443
+ "overflow",
1444
+ "alignSelf",
1445
+ "justifySelf",
1446
+ "placeSelf",
1447
+ "position",
1448
+ "order",
1449
+ "flexGrow",
1450
+ "flexShrink",
1451
+ "flexBasis",
1452
+ "gridArea",
1453
+ "gridColumnStart",
1454
+ "gridColumnEnd",
1455
+ "gridRowStart",
1456
+ "gridRowEnd",
1457
+ "gridColumn",
1458
+ "gridRow",
1459
+ "display",
1460
+ "visibility",
1461
+ "x",
1462
+ "y",
1463
+ "inset",
1464
+ "left",
1465
+ "top",
1466
+ "right",
1467
+ "bottom",
1468
+ "width",
1469
+ "height",
1470
+ "aspectRatio",
1471
+ "minWidth",
1472
+ "minHeight",
1473
+ "maxWidth",
1474
+ "maxHeight",
1475
+ "fit",
1476
+ "objectFit",
1477
+ "objectPosition",
1478
+ "transparency",
1479
+ "rounding",
1480
+ "borderRadius",
1481
+ "boxShadow",
1482
+ "margin",
1483
+ "marginTop",
1484
+ "marginRight",
1485
+ "marginBottom",
1486
+ "marginLeft"
1487
+ ];
1414
1488
  const SHAPE_STYLE_KEYS = [
1415
1489
  ...VIEW_STYLE_KEYS,
1416
1490
  "href",
@@ -1854,9 +1928,10 @@ var PipelineArtifactCollection = class {
1854
1928
  styleIds.push(node.styleRef);
1855
1929
  stylesBySourceKey.set(sourceKey, styleIds);
1856
1930
  }
1857
- if (node.kind === "image" && node.assetRef) {
1931
+ const nodeAssetIds = node.kind === "image" && node.assetRef ? [node.assetRef] : node.kind === "video" ? [node.assetRef, node.posterAssetRef].filter((id) => id !== void 0) : [];
1932
+ if (nodeAssetIds.length > 0) {
1858
1933
  const assetIds = assetsBySourceKey.get(sourceKey) ?? [];
1859
- assetIds.push(node.assetRef);
1934
+ assetIds.push(...nodeAssetIds);
1860
1935
  assetsBySourceKey.set(sourceKey, assetIds);
1861
1936
  }
1862
1937
  });
@@ -1980,6 +2055,7 @@ function assetEntityId(material) {
1980
2055
  //#region src/graph/roles.ts
1981
2056
  function semanticKindForTag(tag) {
1982
2057
  if (tag === "img") return "image";
2058
+ if (tag === "video") return "video";
1983
2059
  if (tag === "shape") return "shape";
1984
2060
  if (tag === "p" || /^h[1-6]$/.test(tag) || tag === "span") return tag === "span" ? "textRun" : "text";
1985
2061
  return "container";
@@ -2009,6 +2085,7 @@ function semanticRoleForTag(tag) {
2009
2085
  level: Number(tag.slice(1))
2010
2086
  };
2011
2087
  case "img": return { kind: "image" };
2088
+ case "video": return { kind: "video" };
2012
2089
  case "shape": return { kind: "shape" };
2013
2090
  case "span": return;
2014
2091
  }
@@ -2039,6 +2116,9 @@ function isSlideElement(node) {
2039
2116
  function isImageElement(node) {
2040
2117
  return node.source.kind === "tag" && node.source.tag === "img";
2041
2118
  }
2119
+ function isVideoElement(node) {
2120
+ return node.source.kind === "tag" && node.source.tag === "video";
2121
+ }
2042
2122
  function isShapeElement(node) {
2043
2123
  return node.source.kind === "tag" && node.source.tag === "shape";
2044
2124
  }
@@ -2061,6 +2141,15 @@ function supportedPropNamesFor(node) {
2061
2141
  "src",
2062
2142
  "data"
2063
2143
  ]);
2144
+ case "video": return new Set([
2145
+ "className",
2146
+ "style",
2147
+ "area",
2148
+ "src",
2149
+ "data",
2150
+ "poster",
2151
+ "posterData"
2152
+ ]);
2064
2153
  case "shape": return new Set([
2065
2154
  "className",
2066
2155
  "style",
@@ -2079,6 +2168,7 @@ function supportedStyleNamesFor(node) {
2079
2168
  switch (node.source.tag) {
2080
2169
  case "span": return new Set(TEXT_RUN_STYLE_KEYS);
2081
2170
  case "img": return new Set(IMAGE_STYLE_KEYS);
2171
+ case "video": return new Set(VIDEO_STYLE_KEYS);
2082
2172
  case "shape": return new Set(SHAPE_STYLE_KEYS);
2083
2173
  case "p":
2084
2174
  case "h1":
@@ -2192,6 +2282,19 @@ function authoringPropDiagnostic(input) {
2192
2282
  ...input.help ? { help: input.help } : {}
2193
2283
  });
2194
2284
  }
2285
+ function videoPosterMissingDiagnostic(input) {
2286
+ return diagnostic({
2287
+ severity: "warning",
2288
+ code: "W_COMPILE_VIDEO_POSTER_MISSING",
2289
+ title: "video poster is missing",
2290
+ message: "Video nodes without poster or posterData may render with a black placeholder until the playback renderer loads the media.",
2291
+ labels: [{
2292
+ path: `${input.path}.props`,
2293
+ message: "Add poster or posterData when the first visual frame matters."
2294
+ }],
2295
+ help: ["The video is still included as playable media; this warning only covers the static placeholder."]
2296
+ });
2297
+ }
2195
2298
  function unsupportedStylePropDiagnostic(input) {
2196
2299
  return diagnostic({
2197
2300
  severity: "warning",
@@ -2317,6 +2420,134 @@ function assetForImage(state, idMaterial, props, path) {
2317
2420
  state.assets.set(id, entity);
2318
2421
  return id;
2319
2422
  }
2423
+ function mediaSourceFromString(value) {
2424
+ if (/^https?:\/\//i.test(value)) return {
2425
+ kind: "url",
2426
+ url: value
2427
+ };
2428
+ return {
2429
+ kind: "path",
2430
+ path: value
2431
+ };
2432
+ }
2433
+ function dataMediaType$1(value) {
2434
+ const commaIndex = value.indexOf(",");
2435
+ if (!value.startsWith("data:") || commaIndex === -1) return;
2436
+ const metadata = value.slice(5, commaIndex);
2437
+ return metadata ? metadata.replace(/;base64$/, "") : void 0;
2438
+ }
2439
+ function assetForVideoSource(input) {
2440
+ const { state, props, path } = input;
2441
+ const hasSrc = props.src !== void 0;
2442
+ const hasData = props.data !== void 0;
2443
+ if (hasSrc && typeof props.src !== "string") {
2444
+ addDiagnostic(state, authoringPropDiagnostic({
2445
+ code: "E_COMPILE_VIDEO_SOURCE_INVALID",
2446
+ title: "video src prop is invalid",
2447
+ path: `${path}.props.src`,
2448
+ message: "The video src prop must be a string when it is provided."
2449
+ }));
2450
+ return;
2451
+ }
2452
+ if (hasData && typeof props.data !== "string") {
2453
+ addDiagnostic(state, authoringPropDiagnostic({
2454
+ code: "E_COMPILE_VIDEO_SOURCE_INVALID",
2455
+ title: "video data prop is invalid",
2456
+ path: `${path}.props.data`,
2457
+ message: "The video data prop must be a string when it is provided."
2458
+ }));
2459
+ return;
2460
+ }
2461
+ if (typeof props.src === "string" && typeof props.data === "string") {
2462
+ addDiagnostic(state, authoringPropDiagnostic({
2463
+ code: "E_COMPILE_VIDEO_SOURCE_INVALID",
2464
+ title: "video source props are ambiguous",
2465
+ path: `${path}.props`,
2466
+ message: "Use either video src or video data, not both."
2467
+ }));
2468
+ return;
2469
+ }
2470
+ if (typeof props.src !== "string" && typeof props.data !== "string") {
2471
+ addDiagnostic(state, authoringPropDiagnostic({
2472
+ code: "E_COMPILE_VIDEO_SOURCE_INVALID",
2473
+ title: "video source is missing",
2474
+ path: `${path}.props`,
2475
+ message: "Video nodes require either src or data.",
2476
+ help: ["Add a src path or data URI to the video."]
2477
+ }));
2478
+ return;
2479
+ }
2480
+ let source;
2481
+ if (typeof props.src === "string") source = mediaSourceFromString(props.src);
2482
+ else {
2483
+ const data = props.data;
2484
+ if (typeof data !== "string") return;
2485
+ source = {
2486
+ kind: "data",
2487
+ data
2488
+ };
2489
+ }
2490
+ const id = assetEntityId(input.idMaterial);
2491
+ state.assets.set(id, {
2492
+ id,
2493
+ kind: "video",
2494
+ source,
2495
+ metadata: source.kind === "data" ? { mediaType: dataMediaType$1(source.data) } : {},
2496
+ resolution: "unresolved"
2497
+ });
2498
+ return id;
2499
+ }
2500
+ function assetForVideoPoster(state, idMaterial, props, path) {
2501
+ const hasPoster = props.poster !== void 0;
2502
+ const hasPosterData = props.posterData !== void 0;
2503
+ if (!hasPoster && !hasPosterData) return;
2504
+ if (hasPoster && typeof props.poster !== "string") {
2505
+ addDiagnostic(state, authoringPropDiagnostic({
2506
+ code: "E_COMPILE_VIDEO_POSTER_INVALID",
2507
+ title: "video poster prop is invalid",
2508
+ path: `${path}.props.poster`,
2509
+ message: "The video poster prop must be a string when it is provided."
2510
+ }));
2511
+ return;
2512
+ }
2513
+ if (hasPosterData && typeof props.posterData !== "string") {
2514
+ addDiagnostic(state, authoringPropDiagnostic({
2515
+ code: "E_COMPILE_VIDEO_POSTER_INVALID",
2516
+ title: "video posterData prop is invalid",
2517
+ path: `${path}.props.posterData`,
2518
+ message: "The video posterData prop must be a string when it is provided."
2519
+ }));
2520
+ return;
2521
+ }
2522
+ if (typeof props.poster === "string" && typeof props.posterData === "string") {
2523
+ addDiagnostic(state, authoringPropDiagnostic({
2524
+ code: "E_COMPILE_VIDEO_POSTER_INVALID",
2525
+ title: "video poster props are ambiguous",
2526
+ path: `${path}.props`,
2527
+ message: "Use either video poster or video posterData, not both."
2528
+ }));
2529
+ return;
2530
+ }
2531
+ let source;
2532
+ if (typeof props.poster === "string") source = mediaSourceFromString(props.poster);
2533
+ else {
2534
+ const data = props.posterData;
2535
+ if (typeof data !== "string") return;
2536
+ source = {
2537
+ kind: "data",
2538
+ data
2539
+ };
2540
+ }
2541
+ const id = assetEntityId(idMaterial);
2542
+ state.assets.set(id, {
2543
+ id,
2544
+ kind: "image",
2545
+ source,
2546
+ metadata: source.kind === "data" ? { mediaType: dataMediaType$1(source.data) } : {},
2547
+ resolution: "unresolved"
2548
+ });
2549
+ return id;
2550
+ }
2320
2551
  function semanticBase(state, node, id, kind, path, material, context) {
2321
2552
  const styleRef = styleRefFor(state, material, kind, node.props);
2322
2553
  const templateAreaRef = templateAreaRefFor(state, templateAreaValueFor(node), path, context);
@@ -2585,6 +2816,27 @@ function buildNode(state, node, context, index) {
2585
2816
  kind: "image"
2586
2817
  };
2587
2818
  }
2819
+ if (isVideoElement(node)) {
2820
+ if (node.children.length > 0) addDiagnostic(state, invalidStructure(path, "video cannot have children", "Video nodes are leaf nodes."));
2821
+ const assetRef = assetForVideoSource({
2822
+ state,
2823
+ idMaterial: material,
2824
+ props: node.props,
2825
+ path
2826
+ });
2827
+ const posterAssetRef = assetForVideoPoster(state, [...material, "poster"], node.props, path);
2828
+ if (node.props.poster === void 0 && node.props.posterData === void 0) addDiagnostic(state, videoPosterMissingDiagnostic({ path }));
2829
+ state.nodes.set(id, {
2830
+ ...semanticBase(state, node, id, "video", path, material, nodeContext),
2831
+ kind: "video",
2832
+ ...assetRef ? { assetRef } : {},
2833
+ ...posterAssetRef ? { posterAssetRef } : {}
2834
+ });
2835
+ return {
2836
+ id,
2837
+ kind: "video"
2838
+ };
2839
+ }
2588
2840
  if (isShapeElement(node)) {
2589
2841
  state.nodes.set(id, {
2590
2842
  ...semanticBase(state, node, id, "shape", path, material, nodeContext),
@@ -2812,6 +3064,9 @@ function effectiveProjectedValues(element) {
2812
3064
  ...element.kind === "text" ? { textStyle: element.style } : {},
2813
3065
  ...element.kind === "image" ? { imageSource: element.source } : {},
2814
3066
  ...element.kind === "image" ? { imageObjectPosition: element.objectPosition } : {},
3067
+ ...element.kind === "video" ? { videoSource: element.source } : {},
3068
+ ...element.kind === "video" && element.posterSource ? { videoPosterSource: element.posterSource } : {},
3069
+ ...element.kind === "video" ? { videoObjectPosition: element.objectPosition } : {},
2815
3070
  ...element.unsupportedSemantics?.length ? { unsupportedSemantics: element.unsupportedSemantics } : {}
2816
3071
  };
2817
3072
  }
@@ -3161,10 +3416,12 @@ function rawTextForNode(graph, node) {
3161
3416
  return text.length > 0 ? text : void 0;
3162
3417
  }
3163
3418
  function originFor$1(node) {
3419
+ const videoAssetIds = node.kind === "video" ? [node.assetRef, node.posterAssetRef].filter((id) => id !== void 0) : [];
3164
3420
  return {
3165
3421
  graphNodeIds: [node.id],
3166
3422
  ...node.styleRef ? { styleEntityIds: [node.styleRef] } : {},
3167
3423
  ...node.kind === "image" && node.assetRef ? { assetEntityIds: [node.assetRef] } : {},
3424
+ ...videoAssetIds.length > 0 ? { assetEntityIds: videoAssetIds } : {},
3168
3425
  ...node.origin.source ? { source: node.origin.source } : {}
3169
3426
  };
3170
3427
  }
@@ -3335,6 +3592,9 @@ function collectTextOrigin(graph, node) {
3335
3592
  ...styleEntityIds.length > 0 ? { styleEntityIds: [...new Set(styleEntityIds)] } : {}
3336
3593
  };
3337
3594
  }
3595
+ function collectVideoAssetIds(node) {
3596
+ return [node.assetRef, node.posterAssetRef].filter((id) => id !== void 0);
3597
+ }
3338
3598
  function layoutOriginFor(graph, node, templates) {
3339
3599
  const templateAreaKind = templateAreaKindFor$1(node, templates);
3340
3600
  if (node.kind === "text") return {
@@ -3347,6 +3607,7 @@ function layoutOriginFor(graph, node, templates) {
3347
3607
  graphNodeIds: [node.id],
3348
3608
  ...node.styleRef ? { styleEntityIds: [node.styleRef] } : {},
3349
3609
  ...node.kind === "image" && node.assetRef ? { assetEntityIds: [node.assetRef] } : {},
3610
+ ...node.kind === "video" && collectVideoAssetIds(node).length > 0 ? { assetEntityIds: collectVideoAssetIds(node) } : {},
3350
3611
  ...node.origin.source ? { source: node.origin.source } : {},
3351
3612
  ...node.templateAreaRef ? { templateAreaRef: node.templateAreaRef } : {},
3352
3613
  ...templateAreaKind ? { templateAreaKind } : {}
@@ -3415,6 +3676,23 @@ function layoutInputNodeFromGraph(graph, resolvedStyles, node, assetProbeArtifac
3415
3676
  origin: layoutOriginFor(graph, node, templates)
3416
3677
  };
3417
3678
  }
3679
+ case "video": {
3680
+ const props = propsWithTemplateAreaFrame(resolvedStyles, node, templates);
3681
+ const asset = node.assetRef ? graph.assets.get(node.assetRef) : void 0;
3682
+ if (!asset) return;
3683
+ const posterAsset = node.posterAssetRef ? graph.assets.get(node.posterAssetRef) : void 0;
3684
+ return {
3685
+ kind: "video",
3686
+ props: {
3687
+ ...props,
3688
+ ...videoSourceProps(asset),
3689
+ ...posterAsset ? videoPosterSourceProps(posterAsset) : {}
3690
+ },
3691
+ ...node.assetRef ? { assetProbe: assetProbeArtifacts?.get(node.assetRef)?.probe } : {},
3692
+ ...node.posterAssetRef ? { posterAssetProbe: assetProbeArtifacts?.get(node.posterAssetRef)?.probe } : {},
3693
+ origin: layoutOriginFor(graph, node, templates)
3694
+ };
3695
+ }
3418
3696
  case "shape": return {
3419
3697
  kind: "shape",
3420
3698
  props: {
@@ -3431,6 +3709,14 @@ function imageSourceProps(asset) {
3431
3709
  if (asset.source.kind === "data") return { data: asset.source.data };
3432
3710
  return { src: asset.source.kind === "path" ? asset.source.path : asset.source.url };
3433
3711
  }
3712
+ function videoSourceProps(asset) {
3713
+ if (asset.source.kind === "data") return { data: asset.source.data };
3714
+ return { src: asset.source.kind === "path" ? asset.source.path : asset.source.url };
3715
+ }
3716
+ function videoPosterSourceProps(asset) {
3717
+ if (asset.source.kind === "data") return { posterData: asset.source.data };
3718
+ return { poster: asset.source.kind === "path" ? asset.source.path : asset.source.url };
3719
+ }
3434
3720
  function buildLayoutInputSnapshot(input) {
3435
3721
  const document = input.graph.nodes.get(input.graph.documentId);
3436
3722
  const slideNodes = document?.kind === "document" ? document.children.map((id) => input.graph.nodes.get(id)).filter((node) => node?.kind === "slide") : [];
@@ -6049,6 +6335,25 @@ function normalizeImageProps(props, context) {
6049
6335
  margin: resolveBoxSpacing(resolved.margin, resolved.marginTop, resolved.marginRight, resolved.marginBottom, resolved.marginLeft)
6050
6336
  };
6051
6337
  }
6338
+ function normalizeVideoProps(props, context) {
6339
+ const { style, ...rest } = props;
6340
+ const resolved = {
6341
+ ...rest,
6342
+ ...style
6343
+ };
6344
+ const inset = resolveInset(resolved.inset, resolved.top, resolved.right, resolved.bottom, resolved.left);
6345
+ return {
6346
+ ...resolved,
6347
+ top: inset?.top ?? resolved.top,
6348
+ right: inset?.right ?? resolved.right,
6349
+ bottom: inset?.bottom ?? resolved.bottom,
6350
+ left: inset?.left ?? resolved.left,
6351
+ fit: normalizeImageFit(resolved.fit ?? resolved.objectFit),
6352
+ objectPosition: resolved.objectPosition,
6353
+ rounding: resolved.rounding ?? (resolved.borderRadius !== void 0 ? parseLength(resolved.borderRadius, 0, 0, context) > 0 : void 0),
6354
+ margin: resolveBoxSpacing(resolved.margin, resolved.marginTop, resolved.marginRight, resolved.marginBottom, resolved.marginLeft)
6355
+ };
6356
+ }
6052
6357
  function normalizeSlideProps(props) {
6053
6358
  const { style, ...rest } = props;
6054
6359
  const resolved = {
@@ -7714,8 +8019,41 @@ function imageSourceFromProps(props) {
7714
8019
  };
7715
8020
  throw new Error("Image requires either src or data.");
7716
8021
  }
8022
+ function videoSourceFromProps(props) {
8023
+ if (props.src) {
8024
+ if (/^https?:\/\//i.test(props.src)) return {
8025
+ kind: "url",
8026
+ url: props.src
8027
+ };
8028
+ return {
8029
+ kind: "path",
8030
+ path: props.src
8031
+ };
8032
+ }
8033
+ if (props.data) return {
8034
+ kind: "data",
8035
+ data: props.data
8036
+ };
8037
+ throw new Error("Video requires either src or data.");
8038
+ }
8039
+ function videoPosterSourceFromProps(props) {
8040
+ if (props.poster) {
8041
+ if (/^https?:\/\//i.test(props.poster)) return {
8042
+ kind: "url",
8043
+ url: props.poster
8044
+ };
8045
+ return {
8046
+ kind: "path",
8047
+ path: props.poster
8048
+ };
8049
+ }
8050
+ if (props.posterData) return {
8051
+ kind: "data",
8052
+ data: props.posterData
8053
+ };
8054
+ }
7717
8055
  function isLayoutInputContentNode(value) {
7718
- return typeof value === "object" && value !== null && "kind" in value && (value.kind === "view" || value.kind === "text" || value.kind === "image" || value.kind === "shape");
8056
+ return typeof value === "object" && value !== null && "kind" in value && (value.kind === "view" || value.kind === "text" || value.kind === "image" || value.kind === "video" || value.kind === "shape");
7719
8057
  }
7720
8058
  function isLayoutInputTextNode(value) {
7721
8059
  return typeof value === "object" && value !== null && "kind" in value && value.kind === "text";
@@ -7744,6 +8082,13 @@ function layoutChildFromNode(child, siblingOrder, context) {
7744
8082
  siblingOrder,
7745
8083
  ...origin ? { origin } : {}
7746
8084
  };
8085
+ case "video": return {
8086
+ kind: "video",
8087
+ source: child,
8088
+ props: normalizeVideoProps(child.props, context),
8089
+ siblingOrder,
8090
+ ...origin ? { origin } : {}
8091
+ };
7747
8092
  case "shape": return {
7748
8093
  kind: "shape",
7749
8094
  source: child,
@@ -7866,6 +8211,7 @@ function getChildPadding(node, context, percentageBaseEmu = 0) {
7866
8211
  return parseSpacing(props.padding, getTextLengthContext(props, context), percentageBaseEmu);
7867
8212
  }
7868
8213
  case "image": return EMPTY_SPACING;
8214
+ case "video": return EMPTY_SPACING;
7869
8215
  case "shape": return EMPTY_SPACING;
7870
8216
  }
7871
8217
  }
@@ -7904,7 +8250,7 @@ function estimateChildContentSize(node, dimension, parent, mainAxis, context) {
7904
8250
  const isMainDimension = mainAxis === "horizontal" && dimension === "width" || mainAxis === "vertical" && dimension === "height";
7905
8251
  const basis = dimension === "width" ? parent.widthEmu : parent.heightEmu;
7906
8252
  const authoredValue = authoredLengthOrUndefined(isMainDimension && mainAxis ? resolveChildMainLength(node, mainAxis) : node.props[dimension]);
7907
- if (authoredValue !== void 0) return inflateSpecifiedBoxSize(parseLength(authoredValue, basis, 0, getNodeLengthContext(node, context)), node.kind === "image" ? "border-box" : node.props.boxSizing ?? "border-box", getChildPadding(node, context, parent.widthEmu), dimension);
8253
+ if (authoredValue !== void 0) return inflateSpecifiedBoxSize(parseLength(authoredValue, basis, 0, getNodeLengthContext(node, context)), node.kind === "image" || node.kind === "video" ? "border-box" : node.props.boxSizing ?? "border-box", getChildPadding(node, context, parent.widthEmu), dimension);
7908
8254
  if (node.kind === "text") {
7909
8255
  if (dimension === "width" && mainAxis === "horizontal") return 0;
7910
8256
  return estimateTextAutoContentSize(node, dimension, parent, context);
@@ -7915,7 +8261,7 @@ function estimateChildContentSize(node, dimension, parent, mainAxis, context) {
7915
8261
  const authoredOppositeValue = authoredLengthOrUndefined((mainAxis === "horizontal" && oppositeDimension === "width" || mainAxis === "vertical" && oppositeDimension === "height") && mainAxis ? resolveChildMainLength(node, mainAxis) : node.props[oppositeDimension]);
7916
8262
  if (authoredOppositeValue === void 0) return 0;
7917
8263
  const oppositeSize = parseLength(authoredOppositeValue, oppositeBasis, 0, getNodeLengthContext(node, context));
7918
- return inflateSpecifiedBoxSize(dimension === "width" ? oppositeSize * aspectRatio : oppositeSize / aspectRatio, node.kind === "image" ? "border-box" : node.props.boxSizing ?? "border-box", getChildPadding(node, context, parent.widthEmu), dimension);
8264
+ return inflateSpecifiedBoxSize(dimension === "width" ? oppositeSize * aspectRatio : oppositeSize / aspectRatio, node.kind === "image" || node.kind === "video" ? "border-box" : node.props.boxSizing ?? "border-box", getChildPadding(node, context, parent.widthEmu), dimension);
7919
8265
  }
7920
8266
  function getNodeMargin(node, context, percentageBaseEmu = 0) {
7921
8267
  switch (node.kind) {
@@ -7925,6 +8271,7 @@ function getNodeMargin(node, context, percentageBaseEmu = 0) {
7925
8271
  return parseSpacingAllowAuto(props.margin, getTextLengthContext(props, context), percentageBaseEmu);
7926
8272
  }
7927
8273
  case "image": return parseSpacingAllowAuto(node.props.margin, context, percentageBaseEmu);
8274
+ case "video": return parseSpacingAllowAuto(node.props.margin, context, percentageBaseEmu);
7928
8275
  case "shape": return parseSpacingAllowAuto(node.props.margin, context, percentageBaseEmu);
7929
8276
  }
7930
8277
  }
@@ -8607,6 +8954,123 @@ function compileImageNode(node, parentFrame, idGenerator, placement, clipRect, c
8607
8954
  source: imageSourceFromProps(props)
8608
8955
  };
8609
8956
  }
8957
+ const DEFAULT_VIDEO_ASPECT_RATIO = 16 / 9;
8958
+ function isUnspecifiedVideoDimension(value) {
8959
+ if (value === void 0) return true;
8960
+ if (typeof value === "string") {
8961
+ const normalized = value.trim().toLowerCase();
8962
+ return normalized === "auto" || isCssWideKeyword(normalized);
8963
+ }
8964
+ return false;
8965
+ }
8966
+ function videoPropsWithFallbackFrame(props, parentFrame) {
8967
+ const missingWidth = isUnspecifiedVideoDimension(props.width);
8968
+ const missingHeight = isUnspecifiedVideoDimension(props.height);
8969
+ if (!missingWidth && !missingHeight) return {
8970
+ props,
8971
+ missingHeight,
8972
+ missingWidth,
8973
+ unsupportedSemantics: []
8974
+ };
8975
+ const aspectRatio = parseAspectRatio(props.aspectRatio) ?? DEFAULT_VIDEO_ASPECT_RATIO;
8976
+ const fallbackWidthIn = parentFrame.widthEmu / EMU_PER_INCH / 2;
8977
+ return {
8978
+ props: {
8979
+ ...props,
8980
+ aspectRatio: props.aspectRatio ?? `${DEFAULT_VIDEO_ASPECT_RATIO}`,
8981
+ ...missingWidth && missingHeight ? { width: fallbackWidthIn } : {}
8982
+ },
8983
+ missingHeight,
8984
+ missingWidth,
8985
+ unsupportedSemantics: [{
8986
+ feature: "layout",
8987
+ property: missingWidth && missingHeight ? "width,height" : missingWidth ? "width" : "height",
8988
+ value: missingWidth && missingHeight ? "auto auto" : "auto",
8989
+ reason: "Video frame size was omitted; deckjsx synthesized a 16:9 fallback frame for the initial playable video projection.",
8990
+ fallback: {
8991
+ strategy: "synthesizeFallbackFrame",
8992
+ preserves: ["playableVideoMedia"],
8993
+ missing: [
8994
+ ...missingWidth ? ["authoredWidth"] : [],
8995
+ ...missingHeight ? ["authoredHeight"] : [],
8996
+ ...props.aspectRatio === void 0 ? [`defaultAspectRatio=${aspectRatio}`] : []
8997
+ ]
8998
+ }
8999
+ }]
9000
+ };
9001
+ }
9002
+ function compileVideoNode(node, parentFrame, idGenerator, placement, clipRect, context) {
9003
+ const videoFrame = videoPropsWithFallbackFrame(node.props, parentFrame);
9004
+ const { props } = videoFrame;
9005
+ const fit = normalizeProjectedImageFit(props.fit);
9006
+ const resolved = frameFromProps(props, parentFrame, videoFrame.missingWidth || videoFrame.missingHeight ? {
9007
+ ...placement?.xEmu !== void 0 ? { xEmu: placement.xEmu } : {},
9008
+ ...placement?.yEmu !== void 0 ? { yEmu: placement.yEmu } : {},
9009
+ ...!videoFrame.missingWidth && placement?.widthEmu !== void 0 ? { widthEmu: placement.widthEmu } : {},
9010
+ ...!videoFrame.missingHeight && placement?.heightEmu !== void 0 ? { heightEmu: placement.heightEmu } : {}
9011
+ } : placement, context);
9012
+ const shadow = parseShadowShorthandOrIgnore({
9013
+ property: "boxShadow",
9014
+ value: props.boxShadow
9015
+ });
9016
+ const objectPosition = parseObjectPosition(props.objectPosition, {
9017
+ widthEmu: resolved.widthEmu,
9018
+ heightEmu: resolved.heightEmu
9019
+ });
9020
+ if (!props.src && !props.data) throw new Error("Video requires either src or data.");
9021
+ const originalFrame = {
9022
+ xEmu: resolved.xEmu,
9023
+ yEmu: resolved.yEmu,
9024
+ widthEmu: resolved.widthEmu,
9025
+ heightEmu: resolved.heightEmu
9026
+ };
9027
+ const visibleFrame = intersectClipRect(originalFrame, clipRect);
9028
+ if (!visibleFrame) return null;
9029
+ const clip = clippingMetadata(originalFrame, clipRect, visibleFrame);
9030
+ const unsupportedSemantics = [
9031
+ ...unsupportedCssLayoutValueSemantics(props),
9032
+ ...unsupportedTransformSemantics$1(props),
9033
+ ...unsupportedCompositingSemantics$1(props),
9034
+ ...unsupportedOpacityStackingContextSemantics$1(props),
9035
+ ...unsupportedClippingTransformSemantics({
9036
+ clip,
9037
+ rotation: resolved.rotation,
9038
+ flipH: resolved.flipH,
9039
+ flipV: resolved.flipV
9040
+ }),
9041
+ ...unsupportedObjectPositionSemantics({
9042
+ value: props.objectPosition,
9043
+ resolved: objectPosition
9044
+ }),
9045
+ ...unsupportedObjectFitSemantics(props.fit),
9046
+ ...shadow.unsupportedSemantics,
9047
+ ...videoFrame.unsupportedSemantics
9048
+ ];
9049
+ const posterSource = videoPosterSourceFromProps(props);
9050
+ return {
9051
+ id: idGenerator.nextNode(),
9052
+ kind: "video",
9053
+ ...node.origin ? { origin: node.origin } : {},
9054
+ frame: visibleFrame,
9055
+ siblingOrder: node.siblingOrder,
9056
+ ...clip ? { clip } : {},
9057
+ sourceFrame: originalFrame,
9058
+ opacity: resolved.opacity,
9059
+ rotation: resolved.rotation,
9060
+ zIndex: resolved.zIndex,
9061
+ ...props.visibility !== void 0 ? { visibility: props.visibility } : {},
9062
+ flipH: resolved.flipH,
9063
+ flipV: resolved.flipV,
9064
+ ...unsupportedSemantics.length ? { unsupportedSemantics } : {},
9065
+ fit,
9066
+ ...objectPosition ? { objectPosition } : {},
9067
+ transparency: normalizeTransparency$1(props.transparency),
9068
+ rounding: props.rounding,
9069
+ ...shadow.shadow ? { shadow: shadow.shadow } : {},
9070
+ source: videoSourceFromProps(props),
9071
+ ...posterSource ? { posterSource } : {}
9072
+ };
9073
+ }
8610
9074
  function compileShapeNode(node, parentFrame, idGenerator, placement, clipRect, context) {
8611
9075
  const { props } = node;
8612
9076
  const resolved = frameFromProps(props, parentFrame, placement, context);
@@ -8680,6 +9144,7 @@ function compileNode(child, parentFrame, idGenerator, placement, clipRect, conte
8680
9144
  case "view": return compileGroupNode(child, parentFrame, idGenerator, placement, clipRect, context, resolutionOptions);
8681
9145
  case "text": return compileTextNode(child, parentFrame, idGenerator, placement, clipRect, context);
8682
9146
  case "image": return compileImageNode(child, parentFrame, idGenerator, placement, clipRect, context);
9147
+ case "video": return compileVideoNode(child, parentFrame, idGenerator, placement, clipRect, context);
8683
9148
  case "shape": return compileShapeNode(child, parentFrame, idGenerator, placement, clipRect, context);
8684
9149
  }
8685
9150
  }
@@ -8807,6 +9272,7 @@ function mediaContentType(extension) {
8807
9272
  case "png": return "image/png";
8808
9273
  case "gif": return "image/gif";
8809
9274
  case "svg": return "image/svg+xml";
9275
+ case "mp4": return "video/mp4";
8810
9276
  default: return "application/octet-stream";
8811
9277
  }
8812
9278
  }
@@ -8871,8 +9337,15 @@ function buildPptxManifest(input) {
8871
9337
  targetPath: input.presentationPropertiesPart.path,
8872
9338
  type: "presentationProperties"
8873
9339
  }),
9340
+ relationship({
9341
+ id: input.serializedId("rId5"),
9342
+ ownerPath: input.presentationPart.path,
9343
+ targetPartId: input.tableStylesPart.id,
9344
+ targetPath: input.tableStylesPart.path,
9345
+ type: "tableStyles"
9346
+ }),
8874
9347
  ...input.slides.map((slide, index) => relationship({
8875
- id: input.serializedId(`rId${index + 5}`),
9348
+ id: input.serializedId(`rId${index + 6}`),
8876
9349
  ownerPath: input.presentationPart.path,
8877
9350
  targetPartId: slide.id,
8878
9351
  targetPath: slide.path,
@@ -8920,6 +9393,7 @@ function buildPptxManifest(input) {
8920
9393
  override(input.extendedDocumentPropertiesPart, "application/vnd.openxmlformats-officedocument.extended-properties+xml"),
8921
9394
  override(input.viewPropertiesPart, "application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml"),
8922
9395
  override(input.presentationPropertiesPart, "application/vnd.openxmlformats-officedocument.presentationml.presProps+xml"),
9396
+ override(input.tableStylesPart, "application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml"),
8923
9397
  ...input.slides.map((slide) => override(slide, "application/vnd.openxmlformats-officedocument.presentationml.slide+xml"))
8924
9398
  ]
8925
9399
  };
@@ -8961,7 +9435,8 @@ function buildPptxManifest(input) {
8961
9435
  documentPropertiesPart: input.documentPropertiesPart,
8962
9436
  extendedDocumentPropertiesPart: input.extendedDocumentPropertiesPart,
8963
9437
  viewPropertiesPart: input.viewPropertiesPart,
8964
- presentationPropertiesPart: input.presentationPropertiesPart
9438
+ presentationPropertiesPart: input.presentationPropertiesPart,
9439
+ tableStylesPart: input.tableStylesPart
8965
9440
  };
8966
9441
  }
8967
9442
  //#endregion
@@ -8994,6 +9469,7 @@ function mediaTypeFromExtension$1(extension) {
8994
9469
  case "png": return "image/png";
8995
9470
  case "gif": return "image/gif";
8996
9471
  case "svg": return "image/svg+xml";
9472
+ case "mp4": return "video/mp4";
8997
9473
  default: return;
8998
9474
  }
8999
9475
  }
@@ -9003,6 +9479,7 @@ function extensionFromMediaType$1(mediaType) {
9003
9479
  case "image/png": return "png";
9004
9480
  case "image/gif": return "gif";
9005
9481
  case "image/svg+xml": return "svg";
9482
+ case "video/mp4": return "mp4";
9006
9483
  default: return;
9007
9484
  }
9008
9485
  }
@@ -9014,9 +9491,10 @@ function dataMediaType(value) {
9014
9491
  }
9015
9492
  function mediaAllocationKey(input) {
9016
9493
  const asset = input.assetEntityId ? input.assets?.get(input.assetEntityId) : void 0;
9494
+ const mediaKind = input.mediaKind ?? "image";
9017
9495
  const hash = asset?.probe?.hash;
9018
- if (hash) return `hash:${hash}:${asset?.probe?.extension ?? asset?.probe?.mediaType ?? imageExtension(input.source)}`;
9019
- return `source:${asset?.resolverScope ?? "deckjsx:builtin"}:${imageSourceKey(input.source)}`;
9496
+ if (hash) return `${mediaKind}:hash:${hash}:${asset?.probe?.extension ?? asset?.probe?.mediaType ?? imageExtension(input.source)}`;
9497
+ return `${mediaKind}:source:${asset?.resolverScope ?? "deckjsx:builtin"}:${imageSourceKey(input.source)}`;
9020
9498
  }
9021
9499
  function mediaPartIdForSource(input) {
9022
9500
  return packageIdentity("media", fingerprintString(mediaAllocationKey(input)));
@@ -9087,6 +9565,7 @@ function mediaPayloadFor(input) {
9087
9565
  } : void 0;
9088
9566
  const allocationKey = mediaAllocationKey(input);
9089
9567
  return {
9568
+ mediaKind: input.mediaKind ?? "image",
9090
9569
  source: input.source,
9091
9570
  sources: [input.source],
9092
9571
  ...input.elementId ? { elementId: input.elementId } : {},
@@ -9143,22 +9622,43 @@ function mergeMediaPackagePart(part, payload) {
9143
9622
  payload: mergeMediaPartPayload(part.payload, payload)
9144
9623
  };
9145
9624
  }
9146
- function withCanonicalImageMediaPartIds(slides, assets) {
9625
+ function withCanonicalMediaPartIds(slides, assets) {
9147
9626
  return slides.map((slide) => ({
9148
9627
  ...slide,
9149
9628
  payload: {
9150
9629
  ...slide.payload,
9151
9630
  drawing: drawingFromElements(mapElements(slideDrawingChildren(slide), (element) => {
9152
- if (element.kind !== "image") return element;
9153
- const assetEntityId = element.origin.assetEntityIds?.[0];
9154
- return {
9155
- ...element,
9156
- mediaPartId: mediaPartIdForSource({
9157
- source: element.source,
9158
- ...assetEntityId ? { assetEntityId } : {},
9159
- assets
9160
- })
9161
- };
9631
+ if (element.kind === "image") {
9632
+ const assetEntityId = element.origin.assetEntityIds?.[0];
9633
+ return {
9634
+ ...element,
9635
+ mediaPartId: mediaPartIdForSource({
9636
+ source: element.source,
9637
+ mediaKind: "image",
9638
+ ...assetEntityId ? { assetEntityId } : {},
9639
+ assets
9640
+ })
9641
+ };
9642
+ }
9643
+ if (element.kind === "video") {
9644
+ const [assetEntityId, posterAssetEntityId] = element.origin.assetEntityIds ?? [];
9645
+ return {
9646
+ ...element,
9647
+ mediaPartId: mediaPartIdForSource({
9648
+ source: element.source,
9649
+ mediaKind: "video",
9650
+ ...assetEntityId ? { assetEntityId } : {},
9651
+ assets
9652
+ }),
9653
+ ...element.posterSource ? { posterMediaPartId: mediaPartIdForSource({
9654
+ source: element.posterSource,
9655
+ mediaKind: "image",
9656
+ ...posterAssetEntityId ? { assetEntityId: posterAssetEntityId } : {},
9657
+ assets
9658
+ }) } : {}
9659
+ };
9660
+ }
9661
+ return element;
9162
9662
  }))
9163
9663
  }
9164
9664
  }));
@@ -9191,10 +9691,12 @@ function mediaPartsFor(slides, assets) {
9191
9691
  mediaIndex += 1;
9192
9692
  }
9193
9693
  walkElements(slideDrawingChildren(slide), (element) => {
9194
- if (element.kind !== "image" || !element.mediaPartId) return;
9694
+ if (element.kind !== "image" && element.kind !== "video") return;
9695
+ if (!element.mediaPartId) return;
9195
9696
  const assetEntityId = element.origin.assetEntityIds?.[0];
9196
9697
  const payload = mediaPayloadFor({
9197
9698
  source: element.source,
9699
+ mediaKind: element.kind === "video" ? "video" : "image",
9198
9700
  elementId: element.id,
9199
9701
  ...assetEntityId ? { assetEntityId } : {},
9200
9702
  assets
@@ -9210,6 +9712,7 @@ function mediaPartsFor(slides, assets) {
9210
9712
  kind: "media",
9211
9713
  path: `ppt/media/media${mediaIndex}.${mediaExtension({
9212
9714
  source: element.source,
9715
+ mediaKind: element.kind === "video" ? "video" : "image",
9213
9716
  ...assetEntityId ? { assetEntityId } : {},
9214
9717
  assets
9215
9718
  })}`,
@@ -9220,13 +9723,44 @@ function mediaPartsFor(slides, assets) {
9220
9723
  payload
9221
9724
  });
9222
9725
  mediaIndex += 1;
9726
+ if (element.kind !== "video" || !element.posterSource || !element.posterMediaPartId) return;
9727
+ const posterAssetEntityId = element.origin.assetEntityIds?.[1];
9728
+ const posterPayload = mediaPayloadFor({
9729
+ source: element.posterSource,
9730
+ mediaKind: "image",
9731
+ elementId: element.id,
9732
+ ...posterAssetEntityId ? { assetEntityId: posterAssetEntityId } : {},
9733
+ assets
9734
+ });
9735
+ const currentPoster = parts.get(element.posterMediaPartId);
9736
+ if (currentPoster) {
9737
+ parts.set(element.posterMediaPartId, mergeMediaPackagePart(currentPoster, posterPayload));
9738
+ return;
9739
+ }
9740
+ parts.set(element.posterMediaPartId, {
9741
+ id: element.posterMediaPartId,
9742
+ category: "authored-content",
9743
+ kind: "media",
9744
+ path: `ppt/media/media${mediaIndex}.${mediaExtension({
9745
+ source: element.posterSource,
9746
+ mediaKind: "image",
9747
+ ...posterAssetEntityId ? { assetEntityId: posterAssetEntityId } : {},
9748
+ assets
9749
+ })}`,
9750
+ origin: {
9751
+ ...element.origin.graphNodeIds ? { graphNodeIds: element.origin.graphNodeIds } : {},
9752
+ ...element.origin.source ? { source: element.origin.source } : {}
9753
+ },
9754
+ payload: posterPayload
9755
+ });
9756
+ mediaIndex += 1;
9223
9757
  });
9224
9758
  }
9225
9759
  return [...parts.values()];
9226
9760
  }
9227
9761
  function withHyperlinkRelationship(input) {
9228
9762
  const { element } = input;
9229
- if (element.kind === "group" || !element.hyperlink) return element;
9763
+ if (element.kind === "group" || element.kind === "video" || !element.hyperlink) return element;
9230
9764
  const relationshipId = nextSlideRelationshipId(input.relationships);
9231
9765
  const serialized = {
9232
9766
  ...element.serialized,
@@ -9262,6 +9796,9 @@ function withHyperlinkRelationship(input) {
9262
9796
  function nextSlideRelationshipId(relationships) {
9263
9797
  return mediaRelationshipId(relationships.length + 1);
9264
9798
  }
9799
+ function relationshipKey(type, mediaPartId) {
9800
+ return `${type}:${mediaPartId}`;
9801
+ }
9265
9802
  function attachMediaRelationships(slides, mediaParts, assets) {
9266
9803
  const mediaPartById = new Map(mediaParts.map((part) => [part.id, part]));
9267
9804
  return slides.map((slide) => {
@@ -9269,7 +9806,8 @@ function attachMediaRelationships(slides, mediaParts, assets) {
9269
9806
  const relationshipByMediaPartId = /* @__PURE__ */ new Map();
9270
9807
  for (const backgroundImage of backgroundImageLayersForSlide(slide, assets)) {
9271
9808
  const mediaPart = mediaPartById.get(backgroundImage.mediaPartId);
9272
- if (!mediaPart || relationshipByMediaPartId.has(backgroundImage.mediaPartId)) continue;
9809
+ const key = relationshipKey("image", backgroundImage.mediaPartId);
9810
+ if (!mediaPart || relationshipByMediaPartId.has(key)) continue;
9273
9811
  const relationship = {
9274
9812
  id: nextSlideRelationshipId(relationships),
9275
9813
  target: projectedRelationshipTarget({
@@ -9280,7 +9818,7 @@ function attachMediaRelationships(slides, mediaParts, assets) {
9280
9818
  targetPath: mediaPart.path,
9281
9819
  type: "image"
9282
9820
  };
9283
- relationshipByMediaPartId.set(backgroundImage.mediaPartId, relationship);
9821
+ relationshipByMediaPartId.set(key, relationship);
9284
9822
  relationships.push(relationship);
9285
9823
  }
9286
9824
  const children = mapElements(slideDrawingChildren(slide), (element) => {
@@ -9288,7 +9826,8 @@ function attachMediaRelationships(slides, mediaParts, assets) {
9288
9826
  if (nextElement.kind === "image" && nextElement.mediaPartId) {
9289
9827
  const mediaPart = mediaPartById.get(nextElement.mediaPartId);
9290
9828
  if (mediaPart) {
9291
- const relationship = relationshipByMediaPartId.get(nextElement.mediaPartId) ?? {
9829
+ const key = relationshipKey("image", nextElement.mediaPartId);
9830
+ const relationship = relationshipByMediaPartId.get(key) ?? {
9292
9831
  id: nextSlideRelationshipId(relationships),
9293
9832
  target: projectedRelationshipTarget({
9294
9833
  ownerPath: slide.path,
@@ -9298,8 +9837,8 @@ function attachMediaRelationships(slides, mediaParts, assets) {
9298
9837
  targetPath: mediaPart.path,
9299
9838
  type: "image"
9300
9839
  };
9301
- if (!relationshipByMediaPartId.has(nextElement.mediaPartId)) {
9302
- relationshipByMediaPartId.set(nextElement.mediaPartId, relationship);
9840
+ if (!relationshipByMediaPartId.has(key)) {
9841
+ relationshipByMediaPartId.set(key, relationship);
9303
9842
  relationships.push(relationship);
9304
9843
  }
9305
9844
  nextElement = {
@@ -9311,6 +9850,69 @@ function attachMediaRelationships(slides, mediaParts, assets) {
9311
9850
  };
9312
9851
  }
9313
9852
  }
9853
+ if (nextElement.kind === "video" && nextElement.mediaPartId) {
9854
+ const mediaPart = mediaPartById.get(nextElement.mediaPartId);
9855
+ if (mediaPart) {
9856
+ const videoKey = relationshipKey("video", nextElement.mediaPartId);
9857
+ const videoRelationship = relationshipByMediaPartId.get(videoKey) ?? {
9858
+ id: nextSlideRelationshipId(relationships),
9859
+ target: projectedRelationshipTarget({
9860
+ ownerPath: slide.path,
9861
+ targetPath: mediaPart.path
9862
+ }),
9863
+ targetPartId: mediaPart.id,
9864
+ targetPath: mediaPart.path,
9865
+ type: "video"
9866
+ };
9867
+ if (!relationshipByMediaPartId.has(videoKey)) {
9868
+ relationshipByMediaPartId.set(videoKey, videoRelationship);
9869
+ relationships.push(videoRelationship);
9870
+ }
9871
+ const mediaKey = relationshipKey("media", nextElement.mediaPartId);
9872
+ const mediaRelationship = relationshipByMediaPartId.get(mediaKey) ?? {
9873
+ id: nextSlideRelationshipId(relationships),
9874
+ target: projectedRelationshipTarget({
9875
+ ownerPath: slide.path,
9876
+ targetPath: mediaPart.path
9877
+ }),
9878
+ targetPartId: mediaPart.id,
9879
+ targetPath: mediaPart.path,
9880
+ type: "media"
9881
+ };
9882
+ if (!relationshipByMediaPartId.has(mediaKey)) {
9883
+ relationshipByMediaPartId.set(mediaKey, mediaRelationship);
9884
+ relationships.push(mediaRelationship);
9885
+ }
9886
+ nextElement = {
9887
+ ...nextElement,
9888
+ serialized: {
9889
+ ...nextElement.serialized,
9890
+ relationshipId: videoRelationship.id,
9891
+ mediaRelationshipId: mediaRelationship.id
9892
+ }
9893
+ };
9894
+ }
9895
+ if (nextElement.posterMediaPartId) {
9896
+ const posterPart = mediaPartById.get(nextElement.posterMediaPartId);
9897
+ if (posterPart) {
9898
+ const posterKey = relationshipKey("image", nextElement.posterMediaPartId);
9899
+ const posterRelationship = relationshipByMediaPartId.get(posterKey) ?? {
9900
+ id: nextSlideRelationshipId(relationships),
9901
+ target: projectedRelationshipTarget({
9902
+ ownerPath: slide.path,
9903
+ targetPath: posterPart.path
9904
+ }),
9905
+ targetPartId: posterPart.id,
9906
+ targetPath: posterPart.path,
9907
+ type: "image"
9908
+ };
9909
+ if (!relationshipByMediaPartId.has(posterKey)) {
9910
+ relationshipByMediaPartId.set(posterKey, posterRelationship);
9911
+ relationships.push(posterRelationship);
9912
+ }
9913
+ }
9914
+ }
9915
+ }
9314
9916
  return withHyperlinkRelationship({
9315
9917
  element: nextElement,
9316
9918
  ownerPath: slide.path,
@@ -9365,6 +9967,9 @@ function textRunStyleFor(node, resolvedStyles) {
9365
9967
  function imageStyleFor(node, resolvedStyles) {
9366
9968
  return targetStyle(pptxStyleFor(node, resolvedStyles), IMAGE_STYLE_KEYS);
9367
9969
  }
9970
+ function videoStyleFor(node, resolvedStyles) {
9971
+ return targetStyle(pptxStyleFor(node, resolvedStyles), VIDEO_STYLE_KEYS);
9972
+ }
9368
9973
  function shapeStyleFor(node, resolvedStyles, shape) {
9369
9974
  return {
9370
9975
  ...targetStyle(pptxStyleFor(node, resolvedStyles), SHAPE_STYLE_KEYS),
@@ -9846,6 +10451,17 @@ function unsupportedSemanticsForGraphNode(node, resolvedStyles) {
9846
10451
  }).unsupportedSemantics
9847
10452
  ];
9848
10453
  }
10454
+ case "video": {
10455
+ const props = normalizeVideoProps(videoStyleFor(node, resolvedStyles));
10456
+ return [
10457
+ ...unsupportedTransformSemantics(props),
10458
+ ...unsupportedCompositingSemantics(props),
10459
+ ...parseShadowSafely({
10460
+ property: "boxShadow",
10461
+ value: props.boxShadow
10462
+ }).unsupportedSemantics
10463
+ ];
10464
+ }
9849
10465
  case "shape": {
9850
10466
  const props = normalizeShapeProps({ ...shapeStyleFor(node, resolvedStyles, node.shape) });
9851
10467
  const strokes = resolveNodeStrokesSafely(props);
@@ -9925,7 +10541,7 @@ function collectPptxUnsupportedProjectionModelDiagnostics(projection, options =
9925
10541
  const slideItems = [];
9926
10542
  walkElements(slide.payload.drawing.children, (element) => {
9927
10543
  for (const semantic of element.unsupportedSemantics ?? []) {
9928
- if (!options.includeAllUnsupportedSemantics && semantic.feature !== "border" && semantic.feature !== "clipping" && semantic.feature !== "filter" && semantic.feature !== "blend" && semantic.feature !== "isolation" && semantic.feature !== "outline" && semantic.feature !== "stroke" && !(semantic.feature === "opacity" && semantic.property === "stackingContext") && !(semantic.feature === "transform" && semantic.property === "stackingContext")) continue;
10544
+ if (!options.includeAllUnsupportedSemantics && semantic.feature !== "border" && semantic.feature !== "clipping" && semantic.feature !== "filter" && semantic.feature !== "blend" && semantic.feature !== "isolation" && semantic.feature !== "outline" && semantic.feature !== "stroke" && semantic.fallback?.strategy !== "synthesizeFallbackFrame" && !(semantic.feature === "opacity" && semantic.property === "stackingContext") && !(semantic.feature === "transform" && semantic.property === "stackingContext")) continue;
9929
10545
  const graphNodeId = element.origin.graphNodeIds?.[0];
9930
10546
  slideItems.push(diagnostic({
9931
10547
  severity: "warning",
@@ -9965,6 +10581,10 @@ const DEFAULT_OBJECT_POSITION = {
9965
10581
  x: .5,
9966
10582
  y: .5
9967
10583
  };
10584
+ const DEFAULT_VIDEO_POSTER_SOURCE = {
10585
+ kind: "data",
10586
+ data: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNgYAAAAAMAASsJTYQAAAAASUVORK5CYII="
10587
+ };
9968
10588
  const DEFAULT_TEXT_FIT = "none";
9969
10589
  const DEFAULT_TEXT_DIRECTION = "horz";
9970
10590
  const DEFAULT_TEXT_VERTICAL_ALIGN = "top";
@@ -10571,6 +11191,7 @@ function compileElement(input) {
10571
11191
  case "container": return compileContainer(input.graph, input.resolvedStyles, node, input.templates, input.packagePartId, input.parentFrame, input.indexPath, input.context);
10572
11192
  case "text": return compileText(input.graph, input.resolvedStyles, node, input.templates, input.packagePartId, input.parentFrame, input.indexPath, input.context);
10573
11193
  case "image": return compileImage(input.graph, input.resolvedStyles, node, input.templates, input.packagePartId, input.parentFrame, input.indexPath, input.context);
11194
+ case "video": return;
10574
11195
  case "shape": return compileShape(node, input.resolvedStyles, input.templates, input.packagePartId, input.parentFrame, input.indexPath, input.context);
10575
11196
  case "document":
10576
11197
  case "slide":
@@ -10729,6 +11350,23 @@ function mapProjectedLayoutNodeToElement(input) {
10729
11350
  shadow: input.node.shadow,
10730
11351
  hyperlink: input.node.hyperlink
10731
11352
  };
11353
+ case "video": {
11354
+ const posterSource = input.node.posterSource ?? DEFAULT_VIDEO_POSTER_SOURCE;
11355
+ return {
11356
+ ...base,
11357
+ kind: "video",
11358
+ mediaPartId: mediaPartIdForElement(base.id),
11359
+ posterMediaPartId: packageIdentity("media", `${base.id}:poster`),
11360
+ sourceFrame: input.node.sourceFrame,
11361
+ source: input.node.source,
11362
+ posterSource,
11363
+ fit: input.node.fit,
11364
+ objectPosition: input.node.objectPosition ?? DEFAULT_OBJECT_POSITION,
11365
+ transparency: input.node.transparency,
11366
+ rounding: input.node.rounding,
11367
+ shadow: input.node.shadow
11368
+ };
11369
+ }
10732
11370
  case "shape": {
10733
11371
  const backgroundLayers = projectBackgroundLayers({
10734
11372
  layers: input.node.backgroundLayers,
@@ -11617,6 +12255,17 @@ function defaultPptxSupportParts(input) {
11617
12255
  editable: true,
11618
12256
  settings: {}
11619
12257
  }
12258
+ },
12259
+ tableStylesPart: {
12260
+ id: packageIdentity("support", "table-styles"),
12261
+ category: "support",
12262
+ kind: "table-styles",
12263
+ path: "ppt/tableStyles.xml",
12264
+ payload: {
12265
+ kind: "table-styles",
12266
+ editable: true,
12267
+ defaultStyleId: "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}"
12268
+ }
11620
12269
  }
11621
12270
  };
11622
12271
  }
@@ -11657,7 +12306,7 @@ function projectGraphToPptxPackageInternal(input) {
11657
12306
  widthEmu: size.widthEmu,
11658
12307
  heightEmu: size.heightEmu
11659
12308
  };
11660
- const projectedSlidesWithMedia = withCanonicalImageMediaPartIds(slideIds.flatMap((slideId, slideIndex) => {
12309
+ const projectedSlidesWithMedia = withCanonicalMediaPartIds(slideIds.flatMap((slideId, slideIndex) => {
11661
12310
  const slide = input.graph.nodes.get(slideId);
11662
12311
  if (slide?.kind !== "slide") return [];
11663
12312
  const layoutSlide = projectedLayout?.slides[slideIndex];
@@ -11713,6 +12362,7 @@ function projectGraphToPptxPackageInternal(input) {
11713
12362
  extendedDocumentPropertiesPart: supportParts.extendedDocumentPropertiesPart,
11714
12363
  viewPropertiesPart: supportParts.viewPropertiesPart,
11715
12364
  presentationPropertiesPart: supportParts.presentationPropertiesPart,
12365
+ tableStylesPart: supportParts.tableStylesPart,
11716
12366
  slides,
11717
12367
  mediaParts,
11718
12368
  serializedId
@@ -11731,6 +12381,7 @@ function projectGraphToPptxPackageInternal(input) {
11731
12381
  manifest.extendedDocumentPropertiesPart,
11732
12382
  manifest.viewPropertiesPart,
11733
12383
  manifest.presentationPropertiesPart,
12384
+ manifest.tableStylesPart,
11734
12385
  ...slides,
11735
12386
  ...slideRelationshipParts,
11736
12387
  ...mediaParts
@@ -11931,10 +12582,11 @@ function assetProbeInvalidFields(result) {
11931
12582
  if (result.byteLength !== void 0 && (!isFiniteNumber(result.byteLength) || result.byteLength < 0)) invalidFields.push("byteLength");
11932
12583
  return invalidFields;
11933
12584
  }
11934
- function missingRequiredAssetProbeFields(probe) {
12585
+ function missingRequiredAssetProbeFields(input) {
12586
+ if (input.assetKind === "video") return [];
11935
12587
  const missingFields = [];
11936
- if (probe?.width === void 0) missingFields.push("width");
11937
- if (probe?.height === void 0) missingFields.push("height");
12588
+ if (input.probe?.width === void 0) missingFields.push("width");
12589
+ if (input.probe?.height === void 0) missingFields.push("height");
11938
12590
  return missingFields;
11939
12591
  }
11940
12592
  function normalizedAssetProbeResult(input) {
@@ -12328,7 +12980,10 @@ async function resolveAssetArtifacts(input) {
12328
12980
  }
12329
12981
  resolverScope = BUILTIN_ASSET_RESOLVER_SCOPE;
12330
12982
  }
12331
- const missingRequiredFields = missingRequiredAssetProbeFields(probe);
12983
+ const missingRequiredFields = missingRequiredAssetProbeFields({
12984
+ probe,
12985
+ assetKind: asset.kind
12986
+ });
12332
12987
  if (missingRequiredFields.length > 0) diagnostics.push(missingRequiredAssetProbeDiagnostics({
12333
12988
  source,
12334
12989
  resolverScope,