@lofcz/pptxtojson 2.2.1 → 2.2.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.d.ts CHANGED
@@ -43,8 +43,12 @@ export interface PatternFill {
43
43
 
44
44
  export type Fill = ColorFill | ImageFill | GradientFill | PatternFill
45
45
 
46
+ export type BorderColor =
47
+ | { type: 'color', value: string }
48
+ | { type: 'gradient', value: GradientFill['value'] }
49
+
46
50
  export interface Border {
47
- borderColor: string
51
+ borderColor: BorderColor
48
52
  borderWidth: number
49
53
  borderType:'solid' | 'dashed' | 'dotted'
50
54
  }
@@ -81,7 +85,7 @@ export interface Shape {
81
85
  top: number
82
86
  width: number
83
87
  height: number
84
- borderColor: string
88
+ borderColor: BorderColor
85
89
  borderWidth: number
86
90
  borderType: 'solid' | 'dashed' | 'dotted'
87
91
  borderStrokeDasharray: string
@@ -114,7 +118,7 @@ export interface Text {
114
118
  top: number
115
119
  width: number
116
120
  height: number
117
- borderColor: string
121
+ borderColor: BorderColor
118
122
  borderWidth: number
119
123
  borderType: 'solid' | 'dashed' | 'dotted'
120
124
  borderStrokeDasharray: string
@@ -155,7 +159,7 @@ export interface Image {
155
159
  r?: number
156
160
  }
157
161
  geom: string
158
- borderColor: string
162
+ borderColor: BorderColor
159
163
  borderWidth: number
160
164
  borderType: 'solid' | 'dashed' | 'dotted'
161
165
  borderStrokeDasharray: string
@@ -339,12 +343,41 @@ export interface SlideTransition {
339
343
  direction: string | null
340
344
  }
341
345
 
346
+ export type AnimationTrigger = 'onClick' | 'withPrevious' | 'afterPrevious'
347
+ export type AnimationClass = 'entr' | 'exit' | 'emph' | 'path' | 'verb' | 'mediacall'
348
+ export type SlideBuildType = 'paragraph' | 'diagram' | 'graphic' | 'oleChart'
349
+
350
+ export interface SlideAnimation {
351
+ /** cNvPr id of the target shape (`p:spTgt@spid`) */
352
+ spid: string
353
+ trigger: AnimationTrigger
354
+ class: AnimationClass
355
+ presetId: number
356
+ presetSubtype: number
357
+ /** Duration in milliseconds */
358
+ duration: number
359
+ /** Delay in milliseconds before the effect starts */
360
+ delay: number
361
+ /** `p:animEffect@filter` when present (fade, wipe, barn, …) */
362
+ filter?: string
363
+ }
364
+
365
+ export interface SlideBuild {
366
+ spid: string
367
+ type: SlideBuildType
368
+ animBg?: boolean
369
+ }
370
+
342
371
  export interface Slide {
343
372
  fill: Fill
344
373
  elements: Element[]
345
374
  layoutElements: Element[]
346
375
  note: string
347
376
  transition?: SlideTransition | null
377
+ /** Click / withPrevious / afterPrevious effects in presenter order */
378
+ animations: SlideAnimation[]
379
+ /** `p:bldLst` paragraph / graphic / diagram builds */
380
+ builds: SlideBuild[]
348
381
  }
349
382
 
350
383
  export interface Options {
package/dist/index.js CHANGED
@@ -9431,6 +9431,164 @@ function parseTransition(transitionNode) {
9431
9431
  }
9432
9432
  return transition;
9433
9433
  }
9434
+ const PRESET_CLASSES = new Set([
9435
+ 'entr',
9436
+ 'exit',
9437
+ 'emph',
9438
+ 'path',
9439
+ 'verb',
9440
+ 'mediacall'
9441
+ ]);
9442
+ const NODE_TYPE_TO_TRIGGER = {
9443
+ clickEffect: 'onClick',
9444
+ withEffect: 'withPrevious',
9445
+ afterEffect: 'afterPrevious',
9446
+ clickPar: 'onClick',
9447
+ withGroup: 'withPrevious',
9448
+ afterGroup: 'afterPrevious',
9449
+ interactiveSeq: 'onClick'
9450
+ };
9451
+ function asArray(value) {
9452
+ if (null == value) return [];
9453
+ return Array.isArray(value) ? value : [
9454
+ value
9455
+ ];
9456
+ }
9457
+ function parseMs(value) {
9458
+ if (null == value || '' === value || 'indefinite' === value) return null;
9459
+ const ms = parseInt(value, 10);
9460
+ return Number.isFinite(ms) ? ms : null;
9461
+ }
9462
+ function findTimingNode(content) {
9463
+ if (!content) return null;
9464
+ return getTextByPathList(content, [
9465
+ 'p:sld',
9466
+ 'p:timing'
9467
+ ]) || getTextByPathList(content, [
9468
+ 'p:sld',
9469
+ 'mc:AlternateContent',
9470
+ 'mc:Choice',
9471
+ 'p:timing'
9472
+ ]) || getTextByPathList(content, [
9473
+ 'p:sld',
9474
+ 'mc:AlternateContent',
9475
+ 'mc:Fallback',
9476
+ 'p:timing'
9477
+ ]);
9478
+ }
9479
+ function collectSpids(node, out = []) {
9480
+ if (!node || 'object' != typeof node) return out;
9481
+ const spid = node.attrs?.spid;
9482
+ if (null != spid && '' !== spid) out.push(String(spid));
9483
+ for (const key of Object.keys(node))if ('attrs' !== key && 'value' !== key) for (const child of asArray(node[key]))collectSpids(child, out);
9484
+ return out;
9485
+ }
9486
+ function collectDuration(node) {
9487
+ let found = null;
9488
+ const walk = (n)=>{
9489
+ if (!n || 'object' != typeof n) return;
9490
+ const ms = parseMs(n.attrs?.dur);
9491
+ if (null != ms && ms >= 0) found = ms;
9492
+ for (const key of Object.keys(n))if ('attrs' !== key && 'value' !== key) for (const child of asArray(n[key]))walk(child);
9493
+ };
9494
+ walk(node);
9495
+ return found;
9496
+ }
9497
+ function collectFilter(node) {
9498
+ let filter = '';
9499
+ const walk = (n)=>{
9500
+ if (!n || 'object' != typeof n) return;
9501
+ if (n.attrs?.filter) filter = n.attrs.filter;
9502
+ for (const key of Object.keys(n))if ('attrs' !== key && 'value' !== key) for (const child of asArray(n[key]))walk(child);
9503
+ };
9504
+ walk(node);
9505
+ return filter;
9506
+ }
9507
+ function collectDelay(node, inherited = 0) {
9508
+ const fromAttr = parseMs(node?.attrs?.delay);
9509
+ if (null != fromAttr && fromAttr >= 0) return fromAttr;
9510
+ const condRoot = node?.['p:stCondLst'];
9511
+ for (const cond of asArray(condRoot?.['p:cond'] || condRoot)){
9512
+ const fromCond = parseMs(cond?.attrs?.delay);
9513
+ if (null != fromCond && fromCond >= 0) return fromCond;
9514
+ }
9515
+ return inherited;
9516
+ }
9517
+ function collectEffects(node, inheritedTrigger = 'onClick', inheritedDelay = 0, results = []) {
9518
+ if (!node || 'object' != typeof node) return results;
9519
+ const attrs = node.attrs || {};
9520
+ const trigger = NODE_TYPE_TO_TRIGGER[attrs.nodeType] || inheritedTrigger;
9521
+ const delay = collectDelay(node, inheritedDelay);
9522
+ if (attrs.presetClass && PRESET_CLASSES.has(attrs.presetClass)) {
9523
+ const spids = [
9524
+ ...new Set(collectSpids(node))
9525
+ ];
9526
+ const duration = collectDuration(node);
9527
+ const filter = collectFilter(node);
9528
+ const effectTrigger = NODE_TYPE_TO_TRIGGER[attrs.nodeType] || trigger;
9529
+ for (const spid of spids){
9530
+ const animation = {
9531
+ spid,
9532
+ trigger: effectTrigger,
9533
+ class: attrs.presetClass,
9534
+ presetId: parseInt(attrs.presetID || '0', 10) || 0,
9535
+ presetSubtype: parseInt(attrs.presetSubtype || '0', 10) || 0,
9536
+ duration: null != duration ? duration : 1000,
9537
+ delay
9538
+ };
9539
+ if (filter) animation.filter = filter;
9540
+ results.push(animation);
9541
+ }
9542
+ return results;
9543
+ }
9544
+ for (const key of Object.keys(node))if ('attrs' !== key && 'value' !== key) for (const child of asArray(node[key]))collectEffects(child, trigger, delay, results);
9545
+ return results;
9546
+ }
9547
+ function parseBuildList(timing) {
9548
+ const bldLst = timing?.['p:bldLst'];
9549
+ if (!bldLst) return [];
9550
+ const kinds = [
9551
+ [
9552
+ 'p:bldP',
9553
+ 'paragraph'
9554
+ ],
9555
+ [
9556
+ 'p:bldDgm',
9557
+ 'diagram'
9558
+ ],
9559
+ [
9560
+ 'p:bldGraphic',
9561
+ 'graphic'
9562
+ ],
9563
+ [
9564
+ 'p:bldOleChart',
9565
+ 'oleChart'
9566
+ ]
9567
+ ];
9568
+ const builds = [];
9569
+ for (const [tag, type] of kinds)for (const node of asArray(bldLst[tag])){
9570
+ const spid = node?.attrs?.spid;
9571
+ if (null == spid || '' === spid) continue;
9572
+ const item = {
9573
+ spid: String(spid),
9574
+ type
9575
+ };
9576
+ if (node.attrs?.animBg === '1' || node.attrs?.animBg === 'true') item.animBg = true;
9577
+ builds.push(item);
9578
+ }
9579
+ return builds;
9580
+ }
9581
+ function parseTiming(slideContent) {
9582
+ const timing = findTimingNode(slideContent);
9583
+ if (!timing) return {
9584
+ animations: [],
9585
+ builds: []
9586
+ };
9587
+ return {
9588
+ animations: collectEffects(timing),
9589
+ builds: parseBuildList(timing)
9590
+ };
9591
+ }
9434
9592
  async function loadDiagramFile(warpObj, filename, transformDrawing = false) {
9435
9593
  if (!filename) return null;
9436
9594
  const cacheKey = `${transformDrawing ? 'drawing:' : 'xml:'}${filename}`;
@@ -9944,6 +10102,7 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
9944
10102
  if (!transitionNode) transitionNode = findTransitionNode(slideLayoutContent, 'p:sldLayout');
9945
10103
  if (!transitionNode) transitionNode = findTransitionNode(slideMasterContent, 'p:sldMaster');
9946
10104
  const transition = parseTransition(transitionNode);
10105
+ const { animations, builds } = parseTiming(slideContent);
9947
10106
  const showMasterSpOnSlide = getTextByPathList(slideContent, [
9948
10107
  'p:sld',
9949
10108
  'attrs',
@@ -9957,7 +10116,9 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
9957
10116
  layoutElements,
9958
10117
  note,
9959
10118
  transition,
9960
- hideBackground
10119
+ hideBackground,
10120
+ animations,
10121
+ builds
9961
10122
  };
9962
10123
  }
9963
10124
  function getHyperlinkFromCNvPr(cNvPr, warpObj) {