@a3s-lab/office 0.33.0 → 0.35.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.
Files changed (30) hide show
  1. package/README.md +23 -19
  2. package/dist/0~5809.js +123 -0
  3. package/dist/{0~7614.js → 0~7828.js} +376 -5
  4. package/dist/0~pdf-viewer.js +5 -1
  5. package/dist/0~presentation-editor.js +597 -71
  6. package/dist/0~spreadsheet-editor.js +166 -18
  7. package/dist/0~work-pptx-export.js +50 -14
  8. package/dist/0~work-pptx-import.js +21 -9
  9. package/dist/4121.js +122 -1
  10. package/dist/4560.js +33 -0
  11. package/dist/internal/features/work/editors/presentation-animation-panel.d.ts +11 -0
  12. package/dist/internal/features/work/editors/presentation-command-types.d.ts +16 -1
  13. package/dist/internal/features/work/editors/presentation-editor-focus.d.ts +2 -0
  14. package/dist/internal/features/work/editors/presentation-presenter-view.d.ts +2 -1
  15. package/dist/internal/features/work/editors/presentation-slide-canvas.d.ts +11 -3
  16. package/dist/internal/features/work/editors/presentation-text-editor.d.ts +7 -0
  17. package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +10 -0
  18. package/dist/internal/features/work/editors/spreadsheet-command-selection.d.ts +22 -1
  19. package/dist/internal/features/work/editors/use-presentation-animation-commands.d.ts +15 -0
  20. package/dist/internal/features/work/editors/use-presentation-selection.d.ts +1 -1
  21. package/dist/internal/features/work/work-pptx-animation.d.ts +13 -0
  22. package/dist/internal/features/work/work-pptx-groups.d.ts +4 -0
  23. package/dist/internal/features/work/work-presentation-animation-constraints.d.ts +4 -0
  24. package/dist/internal/features/work/work-presentation-animation.d.ts +20 -0
  25. package/dist/internal/features/work/work-presentation-clipboard.d.ts +10 -3
  26. package/dist/internal/features/work/work-types.d.ts +17 -0
  27. package/dist/office-kernel.wasm +0 -0
  28. package/dist/styles.css +123 -0
  29. package/package.json +19 -13
  30. package/dist/0~work-presentation-transition.js +0 -38
@@ -5315,6 +5315,70 @@ function spreadsheetCellFillRangeIsSafe(range) {
5315
5315
  function sameSpreadsheetCellRange(left, right) {
5316
5316
  return left.row[0] === right.row[0] && left.row[1] === right.row[1] && left.column[0] === right.column[0] && left.column[1] === right.column[1];
5317
5317
  }
5318
+ function canEditSpreadsheetSelection(context) {
5319
+ return Boolean(context.editable && context.workbook && context.targetSheetId);
5320
+ }
5321
+ function spreadsheetLiveCommandRange(context) {
5322
+ const selection = spreadsheetLiveCommandSelection(context);
5323
+ return spreadsheetSingleRange(selection ?? context.fallbackRange);
5324
+ }
5325
+ function spreadsheetLiveCommandSelection(context) {
5326
+ return spreadsheetLiveCommandSelections(context)?.at(-1);
5327
+ }
5328
+ function spreadsheetLiveCommandSelections(context) {
5329
+ const shadow = context.selectionRef?.current;
5330
+ if (shadow?.sheetId === context.targetSheetId) return [
5331
+ shadow.selection
5332
+ ];
5333
+ return context.workbook?.getSelection();
5334
+ }
5335
+ function acceptSpreadsheetSelectionChange(selectionRef, sheetId, selection) {
5336
+ const nextSelection = finiteSpreadsheetSelection(selection);
5337
+ const requested = selectionRef.requested;
5338
+ if (requested && (requested.sheetId !== sheetId || !sameSpreadsheetSelectionValue(requested.selection, nextSelection))) return null;
5339
+ const next = {
5340
+ sheetId,
5341
+ selection: nextSelection
5342
+ };
5343
+ selectionRef.current = next;
5344
+ return next;
5345
+ }
5346
+ function rememberSpreadsheetCommandSelection(context, selection) {
5347
+ if (!context.selectionRef || !context.targetSheetId) return;
5348
+ const next = {
5349
+ ...selection,
5350
+ row: [
5351
+ ...selection.row
5352
+ ],
5353
+ column: [
5354
+ ...selection.column
5355
+ ]
5356
+ };
5357
+ context.selectionRef.current = {
5358
+ sheetId: context.targetSheetId,
5359
+ selection: next
5360
+ };
5361
+ context.selectionRef.requested = {
5362
+ sheetId: context.targetSheetId,
5363
+ selection: {
5364
+ ...next,
5365
+ row: [
5366
+ ...next.row
5367
+ ],
5368
+ column: [
5369
+ ...next.column
5370
+ ]
5371
+ }
5372
+ };
5373
+ }
5374
+ function releaseSpreadsheetSelectionRequest(selectionRef) {
5375
+ selectionRef.requested = null;
5376
+ }
5377
+ function sameSpreadsheetSelectionValue(left, right) {
5378
+ const normalizedLeft = finiteSpreadsheetSelection(left);
5379
+ const normalizedRight = finiteSpreadsheetSelection(right);
5380
+ return normalizedLeft.row[0] === normalizedRight.row[0] && normalizedLeft.row[1] === normalizedRight.row[1] && normalizedLeft.column[0] === normalizedRight.column[0] && normalizedLeft.column[1] === normalizedRight.column[1] && normalizedLeft.row_focus === normalizedRight.row_focus && normalizedLeft.column_focus === normalizedRight.column_focus;
5381
+ }
5318
5382
  function createSpreadsheetCellFillExtension() {
5319
5383
  return createOfficeEditorExtension({
5320
5384
  name: 'spreadsheetCellFill',
@@ -5365,9 +5429,11 @@ function materializeSpreadsheetCellFillRows(sheet, plan) {
5365
5429
  }
5366
5430
  function spreadsheetSelectedCellFillPlan(context, direction) {
5367
5431
  if (!context.editable || !context.workbook || !context.targetSheetId || context.targetSheetId !== context.activeSheetId) return null;
5368
- const selections = context.workbook.getSelection();
5432
+ const selections = spreadsheetLiveCommandSelections(context);
5369
5433
  if (selections?.length !== 1) return null;
5370
- const plan = planSpreadsheetCellFill(selections[0], direction);
5434
+ const selection = selections[0];
5435
+ if (!selection) return null;
5436
+ const plan = planSpreadsheetCellFill(selection, direction);
5371
5437
  if (!plan) return null;
5372
5438
  const sheet = context.content.sheets.find((candidate)=>candidate.id === context.targetSheetId);
5373
5439
  return canApplySpreadsheetCellFill(sheet, plan) ? plan : null;
@@ -6323,13 +6389,6 @@ function applySelectedCellStyle(context, preset) {
6323
6389
  function liveSpreadsheetCellStyleRange(context) {
6324
6390
  return spreadsheetSingleRange(context.workbook?.getSelection()?.at(-1) ?? context.fallbackRange);
6325
6391
  }
6326
- function canEditSpreadsheetSelection(context) {
6327
- return Boolean(context.editable && context.workbook && context.targetSheetId);
6328
- }
6329
- function spreadsheetLiveCommandRange(context) {
6330
- const selection = context.workbook?.getSelection()?.at(-1);
6331
- return spreadsheetSingleRange(selection ?? context.fallbackRange);
6332
- }
6333
6392
  const MAX_SPREADSHEET_ROWS = 1048576;
6334
6393
  const spreadsheetPasteContentOptions = [
6335
6394
  {
@@ -8493,7 +8552,7 @@ function updateSpreadsheetSelection(context, storage, update) {
8493
8552
  if (!context.workbook || !context.targetSheetId) return false;
8494
8553
  const sheet = context.content.sheets.find((candidate)=>candidate.id === context.targetSheetId);
8495
8554
  if (!sheet) return false;
8496
- const liveSelection = context.workbook.getSelection()?.at(-1) ?? context.fallbackRange;
8555
+ const liveSelection = spreadsheetLiveCommandSelection(context) ?? context.fallbackRange;
8497
8556
  const rememberedFocus = storage.focus;
8498
8557
  const selection = rememberedFocus && spreadsheetSelectionContainsFocus(liveSelection, rememberedFocus) ? {
8499
8558
  ...liveSelection,
@@ -8507,6 +8566,7 @@ function updateSpreadsheetSelection(context, storage, update) {
8507
8566
  ], {
8508
8567
  id: context.targetSheetId
8509
8568
  });
8569
+ rememberSpreadsheetCommandSelection(context, next);
8510
8570
  storage.focus = {
8511
8571
  row: next.row_focus ?? next.row[1] ?? next.row[0] ?? 0,
8512
8572
  column: next.column_focus ?? next.column[1] ?? next.column[0] ?? 0
@@ -10010,6 +10070,16 @@ function pasteCells(context, values) {
10010
10070
  ], {
10011
10071
  id: context.targetSheetId
10012
10072
  });
10073
+ rememberSpreadsheetCommandSelection(context, {
10074
+ row: [
10075
+ ...range.row
10076
+ ],
10077
+ column: [
10078
+ ...range.column
10079
+ ],
10080
+ row_focus: range.row[0],
10081
+ column_focus: range.column[0]
10082
+ });
10013
10083
  } catch {}
10014
10084
  syncSpreadsheetFormulaBar(context, data[0][0]);
10015
10085
  return true;
@@ -25395,6 +25465,60 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
25395
25465
  const editorFocusOrigin = useOfficeEditorFocusOrigin();
25396
25466
  const workbookRef = useRef(null);
25397
25467
  const projectedWorkbookSheetsRef = useRef([]);
25468
+ useLayoutEffect(()=>{
25469
+ const container = spreadsheetCanvasRef.current;
25470
+ if (!container || preview) return;
25471
+ let pendingEditor = null;
25472
+ let pointerEnteredEditor = false;
25473
+ const moveEditorCaretToEnd = (editor)=>{
25474
+ if (document.activeElement !== editor || !editor.isConnected || !editor.textContent) return false;
25475
+ const selection = document.getSelection();
25476
+ if (!selection) return false;
25477
+ const range = document.createRange();
25478
+ range.selectNodeContents(editor);
25479
+ range.collapse(false);
25480
+ selection.removeAllRanges();
25481
+ selection.addRange(range);
25482
+ return true;
25483
+ };
25484
+ const handlePointerDown = (event)=>{
25485
+ pointerEnteredEditor = event.target instanceof Element && Boolean(event.target.closest('.luckysheet-cell-input'));
25486
+ };
25487
+ const handleFocusIn = (event)=>{
25488
+ const target = event.target;
25489
+ const editor = target instanceof Element ? target.closest('.luckysheet-cell-input') : null;
25490
+ if (!editor || pointerEnteredEditor) {
25491
+ pendingEditor = null;
25492
+ pointerEnteredEditor = false;
25493
+ return;
25494
+ }
25495
+ pendingEditor = editor;
25496
+ queueMicrotask(()=>{
25497
+ if (pendingEditor === editor && moveEditorCaretToEnd(editor)) pendingEditor = null;
25498
+ });
25499
+ };
25500
+ const observer = new MutationObserver(()=>{
25501
+ const editor = pendingEditor;
25502
+ if (!editor || document.activeElement !== editor) return;
25503
+ if (!editor.textContent) return;
25504
+ moveEditorCaretToEnd(editor);
25505
+ pendingEditor = null;
25506
+ });
25507
+ container.addEventListener('pointerdown', handlePointerDown, true);
25508
+ container.addEventListener('focusin', handleFocusIn, true);
25509
+ observer.observe(container, {
25510
+ characterData: true,
25511
+ childList: true,
25512
+ subtree: true
25513
+ });
25514
+ return ()=>{
25515
+ container.removeEventListener('pointerdown', handlePointerDown, true);
25516
+ container.removeEventListener('focusin', handleFocusIn, true);
25517
+ observer.disconnect();
25518
+ };
25519
+ }, [
25520
+ preview
25521
+ ]);
25398
25522
  const spreadsheetZoomRef = useRef(100);
25399
25523
  const [workbookInstance, setWorkbookInstance] = useState(null);
25400
25524
  const bindWorkbookInstance = useCallback((instance)=>{
@@ -25413,6 +25537,10 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
25413
25537
  const [panel, setPanel] = useState(null);
25414
25538
  const panelTriggerRef = useRef(null);
25415
25539
  const [selectionState, setSelectionState] = useState(null);
25540
+ const selectionStateRef = useRef({
25541
+ current: null,
25542
+ requested: null
25543
+ });
25416
25544
  const formatPainterSelectionHandlerRef = useRef((_sheetId, _selection)=>void 0);
25417
25545
  const [contextMenu, setContextMenu] = useState(null);
25418
25546
  const [formatCellsDialog, setFormatCellsDialog] = useState(null);
@@ -25588,15 +25716,16 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
25588
25716
  collaborationView?.activateSheet(id);
25589
25717
  if (previewRef.current) setPreviewActiveSheetId(id);
25590
25718
  else setNavigationActiveSheetId(id);
25719
+ selectionStateRef.current.current = null;
25720
+ releaseSpreadsheetSelectionRequest(selectionStateRef.current);
25591
25721
  setSelectionState(null);
25592
25722
  },
25593
25723
  afterSelectionChange: (sheetId, selection)=>{
25594
- collaborationView?.select(sheetId, selection);
25595
- setSelectionState({
25596
- sheetId,
25597
- selection
25598
- });
25599
- formatPainterSelectionHandlerRef.current(sheetId, selection);
25724
+ const next = acceptSpreadsheetSelectionChange(selectionStateRef.current, sheetId, selection);
25725
+ if (!next) return;
25726
+ collaborationView?.select(sheetId, next.selection);
25727
+ setSelectionState(next);
25728
+ formatPainterSelectionHandlerRef.current(sheetId, next.selection);
25600
25729
  },
25601
25730
  beforeUpdateCell: (row, column)=>{
25602
25731
  const sheet = contentRef.current.sheets.find((candidate)=>candidate.id === activeSheetIdRef.current);
@@ -25876,6 +26005,8 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
25876
26005
  if (!sheet) return false;
25877
26006
  activeSheetIdRef.current = sheetId;
25878
26007
  if (collaborationView && !collaborationView.activateSheet(sheetId)) return false;
26008
+ selectionStateRef.current.current = null;
26009
+ releaseSpreadsheetSelectionRequest(selectionStateRef.current);
25879
26010
  setSelectionState(null);
25880
26011
  if (previewRef.current) setPreviewActiveSheetId(sheetId);
25881
26012
  try {
@@ -25910,7 +26041,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
25910
26041
  targetRow: activeCell.row,
25911
26042
  targetColumn: activeCell.column
25912
26043
  });
25913
- setSelectionState({
26044
+ const nextSelection = {
25914
26045
  sheetId,
25915
26046
  selection: {
25916
26047
  row: [
@@ -25922,7 +26053,21 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
25922
26053
  row_focus: activeCell.row,
25923
26054
  column_focus: activeCell.column
25924
26055
  }
25925
- });
26056
+ };
26057
+ selectionStateRef.current.current = nextSelection;
26058
+ selectionStateRef.current.requested = {
26059
+ sheetId,
26060
+ selection: {
26061
+ ...nextSelection.selection,
26062
+ row: [
26063
+ ...nextSelection.selection.row
26064
+ ],
26065
+ column: [
26066
+ ...nextSelection.selection.column
26067
+ ]
26068
+ }
26069
+ };
26070
+ setSelectionState(nextSelection);
25926
26071
  } catch {
25927
26072
  return false;
25928
26073
  }
@@ -26043,6 +26188,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
26043
26188
  toggle: (attribute)=>richTextSelectionRef.current?.toggle(contentRef.current, acceptSpreadsheetCommandChange, attribute) ?? false
26044
26189
  },
26045
26190
  selection: selectionState,
26191
+ selectionRef: selectionStateRef.current,
26046
26192
  table: spreadsheetTable.commandPort,
26047
26193
  targetSheetGridSize,
26048
26194
  targetSheetId: toolbarSheetId,
@@ -26150,6 +26296,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
26150
26296
  if ('Escape' === event.key && isSpreadsheetCellEditingTarget(event.target)) requestAnimationFrame(()=>focusSpreadsheetGrid(spreadsheetCanvasRef.current));
26151
26297
  };
26152
26298
  const handleSpreadsheetKeyDownCapture = (event)=>{
26299
+ releaseSpreadsheetSelectionRequest(selectionStateRef.current);
26153
26300
  if ('Alt' === event.key && !event.repeat && event.target instanceof Element && event.target.closest('.fortune-sheet-overlay') && reserveAutoFilterAltKey()) {
26154
26301
  event.preventDefault();
26155
26302
  event.stopPropagation();
@@ -26158,6 +26305,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
26158
26305
  handleSpreadsheetEditingEscape(event);
26159
26306
  };
26160
26307
  const handleSpreadsheetPointerDownCapture = (event)=>{
26308
+ releaseSpreadsheetSelectionRequest(selectionStateRef.current);
26161
26309
  const controller = richTextSelectionRef.current;
26162
26310
  if (!controller) return;
26163
26311
  if (!isSpreadsheetRichTextFormatPointerTarget(event.target)) return void controller.clear();
@@ -3,7 +3,7 @@ import { normalizeRadarStyle, presentationChartShowsLegend, presentationChartAxe
3
3
  import { directChildren, xmlNamespacePrefix, parseXml, firstDescendant, directChild, descendants, childPath, attribute } from "./4121.js";
4
4
  import { workSpreadsheetChartAxisShowsMajorGridlinesByDefault, workSpreadsheetChartAxisDefaultLabelPosition, workSpreadsheetChartAxisIsCategoryAxis, workSpreadsheetChartAxisIsValueAxis } from "./8715.js";
5
5
  import { presentationGroupPath, withPresentationDesign } from "./0~1403.js";
6
- import { patchPptxChartLayoutAndSeriesStyles, patchPptxTransitions, patchPptxComments, patchPptxChartDataLabels, patchPptxChartSeriesAnalysis } from "./0~7614.js";
6
+ import { patchPptxChartLayoutAndSeriesStyles, patchPptxTransitions, patchPptxComments, patchPptxChartDataLabels, patchPptxChartSeriesAnalysis, patchPptxAnimations } from "./0~7828.js";
7
7
  const DRAWING_NAMESPACE = 'http://schemas.openxmlformats.org/drawingml/2006/main';
8
8
  async function patchPptxChartAxes(buffer, slides) {
9
9
  const charts = slides.flatMap((slide)=>slide.elements.flatMap((element)=>'chart' === element.type && element.chart ? [
@@ -270,27 +270,40 @@ const PRESENTATIONML_NAMESPACE = 'http://schemas.openxmlformats.org/presentation
270
270
  const DRAWINGML_NAMESPACE = 'http://schemas.openxmlformats.org/drawingml/2006/main';
271
271
  const GROUPABLE_PART = /^ppt\/(?:slides|slideLayouts|slideMasters)\/[^/]+\.xml$/;
272
272
  class PptxGroupExportRegistry {
273
+ animatedElementKeys = new Set();
273
274
  bindings = new Map();
275
+ bindingsByElement = new Map();
274
276
  roleCounts = new Map();
275
277
  markerSequence = 0;
276
278
  get size() {
277
279
  return this.bindings.size;
278
280
  }
281
+ registerAnimatedElements(scope, elementIds) {
282
+ for (const elementId of elementIds)this.animatedElementKeys.add(exportElementKey(scope, elementId));
283
+ }
279
284
  objectName(scope, element, role) {
280
285
  const groupPath = presentationGroupPath(element);
281
- if (!groupPath.length) return;
286
+ const elementKey = exportElementKey(scope, element.id);
287
+ if (!groupPath.length && !this.animatedElementKeys.has(elementKey)) return;
288
+ const existing = this.bindingsByElement.get(elementKey);
289
+ if (existing) return existing.marker;
282
290
  const roleCount = (this.roleCounts.get(role) ?? 0) + 1;
283
291
  this.roleCounts.set(role, roleCount);
284
292
  this.markerSequence += 1;
285
293
  const marker = `${EXPORT_MARKER_PREFIX}${this.markerSequence}`;
286
- this.bindings.set(marker, {
294
+ const binding = {
287
295
  displayName: `${pptxRoleName(role)} ${roleCount}`,
288
296
  groupPath,
289
297
  groupScope: scope,
290
298
  marker
291
- });
299
+ };
300
+ this.bindings.set(marker, binding);
301
+ this.bindingsByElement.set(elementKey, binding);
292
302
  return marker;
293
303
  }
304
+ markerForElement(scope, elementId) {
305
+ return this.bindingsByElement.get(exportElementKey(scope, elementId))?.marker;
306
+ }
294
307
  binding(marker) {
295
308
  return this.bindings.get(marker);
296
309
  }
@@ -315,7 +328,7 @@ async function patchPptxNativeGroups(buffer, registry) {
315
328
  }
316
329
  for (const binding of registry.values()){
317
330
  const count = found.get(binding.marker) ?? 0;
318
- if (1 !== count) throw new Error(`PPTX group export expected one generated object for ${binding.displayName}, but found ${count}.`);
331
+ if (1 !== count) throw new Error(`PPTX export expected one generated object for ${binding.displayName}, but found ${count}.`);
319
332
  }
320
333
  return archive.generateAsync({
321
334
  type: 'arraybuffer',
@@ -323,6 +336,7 @@ async function patchPptxNativeGroups(buffer, registry) {
323
336
  });
324
337
  }
325
338
  function patchPptxShapeTree(shapeTree, registry, found) {
339
+ normalizePptxNonVisualIds(shapeTree);
326
340
  const sceneNodes = directChildren(shapeTree).filter(isPptxSceneNode).map((node, order)=>{
327
341
  const properties = firstDescendant(node, 'cNvPr');
328
342
  const objectName = properties ? attribute(properties, 'name') : null;
@@ -342,9 +356,9 @@ function patchPptxShapeTree(shapeTree, registry, found) {
342
356
  });
343
357
  if (!sceneNodes.some((item)=>item.binding)) return false;
344
358
  const roots = new Map();
345
- const rootNodes = sceneNodes.filter((item)=>!item.binding);
359
+ const rootNodes = sceneNodes.filter((item)=>!item.binding?.groupPath.length);
346
360
  for (const item of sceneNodes){
347
- if (!item.binding) continue;
361
+ if (!item.binding?.groupPath.length) continue;
348
362
  let siblings = roots;
349
363
  let bucket;
350
364
  for (const groupId of item.binding.groupPath){
@@ -378,7 +392,6 @@ function patchPptxShapeTree(shapeTree, registry, found) {
378
392
  ].sort((left, right)=>left.order - right.order);
379
393
  const extensionList = directChild(shapeTree, 'extLst') ?? null;
380
394
  for (const item of renderedRoots)shapeTree.insertBefore(item.node, extensionList);
381
- normalizePptxNonVisualIds(shapeTree);
382
395
  return true;
383
396
  }
384
397
  function renderPptxGroup(bucket, document, nextId, nextGroupNumber) {
@@ -492,6 +505,9 @@ function normalizePptxNonVisualIds(shapeTree) {
492
505
  function groupBucketKey(scope, groupId) {
493
506
  return `${scope}\u0000${groupId}`;
494
507
  }
508
+ function exportElementKey(scope, elementId) {
509
+ return `${scope}\u0000${elementId}`;
510
+ }
495
511
  function isPptxSceneNode(node) {
496
512
  return [
497
513
  'contentPart',
@@ -735,7 +751,9 @@ function createPptxExportState(artifact, PptxGenJS) {
735
751
  if (!source.useLayoutBackground) slide.background = {
736
752
  color: source.background.replace('#', '')
737
753
  };
738
- for (const element of source.elements)addPresentationElement(slide, element, presentation, slideWidth, slideHeight, groups, `slide:${source.id}`, element.placeholder ? binding?.placeholderNames.get(element.placeholder.key) : void 0);
754
+ const groupScope = `slide:${source.id}`;
755
+ groups.registerAnimatedElements(groupScope, source.animations?.map((animation)=>animation.elementId) ?? []);
756
+ for (const element of source.elements)addPresentationElement(slide, element, presentation, slideWidth, slideHeight, groups, groupScope, element.placeholder ? binding?.placeholderNames.get(element.placeholder.key) : void 0);
739
757
  if (source.notes?.trim()) slide.addNotes(source.notes);
740
758
  }
741
759
  return {
@@ -758,7 +776,8 @@ async function createPptxBlob(artifact, PptxGenJS) {
758
776
  const withChartSeriesAnalysis = await patchPptxChartSeriesAnalysis(withChartAxes, slides);
759
777
  const withTransitions = await patchPptxTransitions(withChartSeriesAnalysis, slides);
760
778
  const withComments = await patchPptxComments(withTransitions, slides, 'presentation' === artifact.content.type ? artifact.content.width ?? 13.333 : 13.333, 'presentation' === artifact.content.type ? artifact.content.height ?? 7.5 : 7.5);
761
- const patched = await patchPptxNativeGroups(withComments, groups);
779
+ const withAnimations = await patchPptxAnimations(withComments, slides, groups);
780
+ const patched = await patchPptxNativeGroups(withAnimations, groups);
762
781
  return new Blob([
763
782
  patched
764
783
  ], {
@@ -886,8 +905,13 @@ function addPresentationElement(slide, element, presentation, slideWidth, slideH
886
905
  });
887
906
  return;
888
907
  }
889
- if ('shape' === element.type) addShape(slide, element, presentation, x, y, width, height, resolvedPlaceholder, groups.objectName(groupScope, element, 'shape'));
890
- if (element.text) addText(slide, element, x, y, width, height, resolvedPlaceholder, groups.objectName(groupScope, element, 'text'));
908
+ if ('shape' === element.type) {
909
+ const objectName = groups.objectName(groupScope, element, 'shape');
910
+ if (element.text || element.textRuns?.length) addText(slide, element, x, y, width, height, resolvedPlaceholder, objectName, pptxShapeType(presentation, element));
911
+ else addShape(slide, element, presentation, x, y, width, height, resolvedPlaceholder, objectName);
912
+ return;
913
+ }
914
+ if ('text' === element.type) addText(slide, element, x, y, width, height, resolvedPlaceholder, groups.objectName(groupScope, element, 'text'));
891
915
  }
892
916
  function pptxChartData(chart) {
893
917
  if (presentationChartUsesNumericXAxis(chart.type)) return [
@@ -926,7 +950,7 @@ function pptxLegendPosition(position) {
926
950
  return 'r';
927
951
  }
928
952
  function addShape(slide, element, presentation, x, y, width, height, placeholder, objectName) {
929
- const shapeType = 'ellipse' === element.shapeType ? presentation.ShapeType.ellipse : 'triangle' === element.shapeType ? presentation.ShapeType.triangle : 'diamond' === element.shapeType ? presentation.ShapeType.diamond : 'roundRect' === element.shapeType ? presentation.ShapeType.roundRect : presentation.ShapeType.rect;
953
+ const shapeType = pptxShapeType(presentation, element);
930
954
  const fillColor = element.fill.replace('#', '');
931
955
  const borderColor = (element.borderColor ?? element.fill).replace('#', '');
932
956
  const options = {
@@ -954,7 +978,7 @@ function addShape(slide, element, presentation, x, y, width, height, placeholder
954
978
  };
955
979
  slide.addShape(shapeType, options);
956
980
  }
957
- function addText(slide, element, x, y, width, height, placeholder, objectName) {
981
+ function addText(slide, element, x, y, width, height, placeholder, objectName, shape) {
958
982
  const text = element.textRuns?.length ? element.textRuns.map((run)=>({
959
983
  text: run.text,
960
984
  options: {
@@ -989,9 +1013,14 @@ function addText(slide, element, x, y, width, height, placeholder, objectName) {
989
1013
  valign: element.verticalAlign ?? 'middle',
990
1014
  margin: 'transparent' === element.fill ? 0 : 10,
991
1015
  breakLine: false,
1016
+ shape,
992
1017
  fill: 'transparent' === element.fill ? void 0 : {
993
1018
  color: element.fill.replace('#', '')
994
1019
  },
1020
+ line: element.borderWidth && element.borderColor ? {
1021
+ color: element.borderColor.replace('#', ''),
1022
+ width: element.borderWidth
1023
+ } : void 0,
995
1024
  hyperlink: element.href ? {
996
1025
  url: element.href
997
1026
  } : void 0,
@@ -1001,6 +1030,13 @@ function addText(slide, element, x, y, width, height, placeholder, objectName) {
1001
1030
  } : {}
1002
1031
  });
1003
1032
  }
1033
+ function pptxShapeType(presentation, element) {
1034
+ if ('ellipse' === element.shapeType) return presentation.ShapeType.ellipse;
1035
+ if ('triangle' === element.shapeType) return presentation.ShapeType.triangle;
1036
+ if ('diamond' === element.shapeType) return presentation.ShapeType.diamond;
1037
+ if ('roundRect' === element.shapeType) return presentation.ShapeType.roundRect;
1038
+ return presentation.ShapeType.rect;
1039
+ }
1004
1040
  async function presentationArrayBuffer(output) {
1005
1041
  if (output instanceof ArrayBuffer) return output;
1006
1042
  if (output instanceof Blob) return output.arrayBuffer();
@@ -1,6 +1,6 @@
1
1
  import { contentTypeForPart, directChildren, bytesToDataUrl, OoxmlPackage, firstDescendant, descendants, directChild, childPath, attribute, createOfficeId as createWorkId } from "./4121.js";
2
2
  import { normalizeRadarStyle, normalizePresentationChartLegendPosition, presentationChartUsesNumericXAxis, normalizePresentationBubbleScale, normalizePresentationBubbleSizeRepresents, withPresentationChartLayout, normalizeDoughnutHoleSize, normalizePresentationScatterStyle } from "./0~work-presentation-charts.js";
3
- import { loadPptxCommentAuthors, readPptxSlideComments, readPptxChartLayoutAndSeriesStyles, readPptxTransition, readPptxChartSeriesAnalysis, readPptxChartDataLabels } from "./0~7614.js";
3
+ import { loadPptxCommentAuthors, readPptxSlideComments, readPptxChartLayoutAndSeriesStyles, readPptxAnimations, readPptxTransition, readPptxChartSeriesAnalysis, readPptxChartDataLabels } from "./0~7828.js";
4
4
  import { parseXlsxChartAxes } from "./4166.js";
5
5
  import { scaledPresentationVisuals } from "./0~work-presentation-visual-scale.js";
6
6
  async function loadPptxTheme(archive, presentationRelationships) {
@@ -547,6 +547,7 @@ async function parseSlide(archive, slidePart, slideNumber, slideWidthEmu, slideH
547
547
  theme,
548
548
  issues,
549
549
  imageBudget,
550
+ elementIdByPptxShapeId: new Map(),
550
551
  location: `幻灯片 ${slideNumber}`
551
552
  };
552
553
  const design = await ensurePptxDesignDefinitions(archive, inheritance.layout, inheritance.master, context, designs);
@@ -554,6 +555,7 @@ async function parseSlide(archive, slidePart, slideNumber, slideWidthEmu, slideH
554
555
  const shapeTree = firstDescendant(document1, 'spTree');
555
556
  for (const child of shapeTree ? directChildren(shapeTree) : [])elements.push(...await parseSlideNode(child, context));
556
557
  const resolvedElements = inheritPptxPlaceholderStyles(elements, design.master, design.layout);
558
+ const animationResult = readPptxAnimations(document1, context.elementIdByPptxShapeId);
557
559
  const transition = readPptxTransition(document1);
558
560
  const commentResult = await readPptxSlideComments(archive, relationships, commentAuthors, slideNumber, slideWidthEmu, slideHeightEmu);
559
561
  if (commentResult.comments.length) addIssue(context, 'pptx.comments', 'Comments', `${commentResult.comments.length} traditional slide comment(s), authors, dates, and positions are preserved and editable.`, 'info');
@@ -564,7 +566,8 @@ async function parseSlide(archive, slidePart, slideNumber, slideWidthEmu, slideH
564
566
  addIssue(context, 'pptx.transition', 'Slide transitions', transition.transition ? 'Basic slide transitions and advance timing are preserved, editable, and replayed in presentation preview.' : 'This slide transition is not editable and remains in the original PPTX only.', transition.transition ? 'info' : 'warning');
565
567
  for (const diagnostic of transition.diagnostics)addIssue(context, diagnostic.code, 'Slide transitions', diagnostic.message);
566
568
  }
567
- if (firstDescendant(document1, 'timing')) addIssue(context, 'pptx.animation', 'Animations', 'Object animations are not replayed and will be omitted on export.');
569
+ if (animationResult.animations.length) addIssue(context, 'pptx.animation', 'Animations', `${animationResult.animations.length} supported object entrance animation(s) are preserved, editable, replayed, and exported.`, 'info');
570
+ for (const diagnostic of animationResult.diagnostics)addIssue(context, diagnostic.code, 'Animations', diagnostic.message);
568
571
  for (const relationship of relationships.values())if (relationship.type.includes('/audio') || relationship.type.includes('/video') || relationship.type.includes('/media')) addIssue(context, 'pptx.media', 'Embedded media', 'Audio and video remain in the original file but are not playable yet.');
569
572
  else if (relationship.type.endsWith('/oleObject') || relationship.type.endsWith('/package')) addIssue(context, 'pptx.ole', 'Embedded objects', 'Embedded Office or OLE objects remain in the original file only.');
570
573
  const slideBackground = readPptxBackground(document1, theme);
@@ -578,7 +581,8 @@ async function parseSlide(archive, slidePart, slideNumber, slideWidthEmu, slideH
578
581
  elements: resolvedElements,
579
582
  notes: await readSpeakerNotes(archive, relationships, context),
580
583
  comments: commentResult.comments.length ? commentResult.comments : void 0,
581
- transition: transition.transition
584
+ transition: transition.transition,
585
+ animations: animationResult.animations.length ? animationResult.animations : void 0
582
586
  };
583
587
  }
584
588
  async function loadPptxPresentationDesigns(archive, relationships, slideWidthEmu, slideHeightEmu, theme, issues, imageBudget, registry) {
@@ -592,6 +596,7 @@ async function loadPptxPresentationDesigns(archive, relationships, slideWidthEmu
592
596
  theme,
593
597
  issues,
594
598
  imageBudget,
599
+ elementIdByPptxShapeId: new Map(),
595
600
  location: '母版与布局'
596
601
  };
597
602
  for (const relationship of relationships.values()){
@@ -659,6 +664,7 @@ function ensureFallbackPptxMaster(registry) {
659
664
  async function parsePptxDesignElements(part, context) {
660
665
  const partContext = {
661
666
  ...context,
667
+ elementIdByPptxShapeId: new Map(),
662
668
  relationships: part.relationships,
663
669
  placeholders: new Map()
664
670
  };
@@ -712,24 +718,30 @@ function inheritPptxPlaceholderStyle(element, definition) {
712
718
  };
713
719
  }
714
720
  async function parseSlideNode(node, context, transform) {
715
- if ('sp' === node.localName) return [
721
+ let elements;
722
+ if ('sp' === node.localName) elements = [
716
723
  withImportedGroupTransform(parseShape(node, context, transform), transform)
717
724
  ];
718
- if ('pic' === node.localName) return [
725
+ else if ('pic' === node.localName) elements = [
719
726
  withImportedGroupTransform(await parsePicture(node, context, transform), transform)
720
727
  ];
721
- if ('graphicFrame' === node.localName) return [
728
+ else if ('graphicFrame' === node.localName) elements = [
722
729
  withImportedGroupTransform(await parseGraphicFrame(node, context, transform), transform)
723
730
  ];
724
- if ('cxnSp' === node.localName) return [
731
+ else if ('cxnSp' === node.localName) elements = [
725
732
  withImportedGroupTransform(parseConnector(node, context, transform), transform)
726
733
  ];
727
- if ('grpSp' === node.localName) return parseGroup(node, context, transform);
734
+ else {
735
+ if ('grpSp' === node.localName) return parseGroup(node, context, transform);
736
+ elements = [];
737
+ }
728
738
  if ([
729
739
  'contentPart',
730
740
  'oleObj'
731
741
  ].includes(node.localName)) addIssue(context, 'pptx.content-part', 'Embedded content', 'An embedded slide object remains available in the original PPTX only.');
732
- return [];
742
+ const pptxShapeId = attribute(firstDescendant(node, 'cNvPr') ?? node, 'id');
743
+ if (pptxShapeId && 1 === elements.length) context.elementIdByPptxShapeId.set(pptxShapeId, elements[0].id);
744
+ return elements;
733
745
  }
734
746
  function parseShape(node, context, transform) {
735
747
  const box = elementBox(node, context, transform);