@a3s-lab/office 0.32.0 → 0.33.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 (39) hide show
  1. package/README.md +59 -7
  2. package/dist/0~3539.js +2 -2
  3. package/dist/0~3557.js +1 -1
  4. package/dist/0~3635.js +1 -1
  5. package/dist/0~7048.js +1 -2
  6. package/dist/{0~6090.js → 0~8136.js} +71 -2
  7. package/dist/{0~4595.js → 0~9073.js} +3 -72
  8. package/dist/0~9445.js +1 -1
  9. package/dist/0~document-editor.js +2 -2
  10. package/dist/0~markdown-editor.js +2 -2
  11. package/dist/0~pdf-page-organization-engine.js +187 -0
  12. package/dist/0~pdf-viewer.js +1014 -30
  13. package/dist/0~presentation-editor.js +2 -2
  14. package/dist/0~spreadsheet-editor.js +2 -2
  15. package/dist/core.d.ts +1 -0
  16. package/dist/internal/features/work/editors/pdf-editor-extensions.d.ts +11 -0
  17. package/dist/internal/features/work/editors/pdf-page-organization-engine.d.ts +2 -0
  18. package/dist/internal/features/work/editors/pdf-page-organization-plan.d.ts +10 -0
  19. package/dist/internal/features/work/editors/pdf-page-organization-types.d.ts +68 -0
  20. package/dist/internal/features/work/editors/pdf-page-organization-worker-client.d.ts +2 -0
  21. package/dist/internal/features/work/editors/pdf-page-organization-worker-protocol.d.ts +13 -0
  22. package/dist/internal/features/work/editors/pdf-page-organization.d.ts +3 -0
  23. package/dist/internal/features/work/editors/pdf-page-organization.worker.d.ts +1 -0
  24. package/dist/internal/features/work/editors/pdf-page-organizer-dialog.d.ts +17 -0
  25. package/dist/internal/features/work/editors/pdf-thumbnail-rail.d.ts +4 -0
  26. package/dist/internal/features/work/editors/pdf-toolbar.d.ts +2 -1
  27. package/dist/internal/features/work/editors/pdf-viewer.d.ts +3 -1
  28. package/dist/internal/features/work/editors/use-pdf-page-organization.d.ts +38 -0
  29. package/dist/office-kernel.wasm +0 -0
  30. package/dist/pdf-page-organization.worker.js +19667 -0
  31. package/dist/pdf-page-organization.worker.js.LICENSE.txt +14 -0
  32. package/dist/react.d.ts +1 -0
  33. package/dist/styles.css +315 -0
  34. package/dist/vue.d.ts +3 -1
  35. package/dist/vue.js +2 -0
  36. package/dist/web-component.d.ts +3 -1
  37. package/dist/web-component.js +9 -0
  38. package/docs/latest/en/browser-editor-architecture.md +29 -6
  39. package/package.json +5 -1
@@ -0,0 +1,14 @@
1
+ /*! *****************************************************************************
2
+ Copyright (c) Microsoft Corporation.
3
+
4
+ Permission to use, copy, modify, and/or distribute this software for any
5
+ purpose with or without fee is hereby granted.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+ PERFORMANCE OF THIS SOFTWARE.
14
+ ***************************************************************************** */
package/dist/react.d.ts CHANGED
@@ -3,6 +3,7 @@ import type { DocumentEditorProps as InternalDocumentEditorProps } from './inter
3
3
  import type { MarkdownEditorProps as InternalMarkdownEditorProps } from './internal/features/work/editors/markdown-editor';
4
4
  import type { PdfViewerProps as InternalPdfViewerProps } from './internal/features/work/editors/pdf-viewer';
5
5
  export { PDF_EVIDENCE_COORDINATE_BASIS, type PdfEvidenceBounds, type PdfEvidenceOverlay, type PdfEvidencePage, type PdfEvidenceRegion, type PdfEvidenceRegionLocation, } from './internal/features/work/editors/pdf-evidence-contract';
6
+ export type { PdfPageOrganizationExport } from './internal/features/work/editors/use-pdf-page-organization';
6
7
  import type { PresentationEditorProps as InternalPresentationEditorProps } from './internal/features/work/editors/presentation-editor';
7
8
  import type { SpreadsheetEditorProps as InternalSpreadsheetEditorProps } from './internal/features/work/editors/spreadsheet-editor';
8
9
  import type { WorkOfficeFileAction } from './internal/features/work/editors/work-office-chrome';
package/dist/styles.css CHANGED
@@ -22700,6 +22700,321 @@ sub [data-office-character-position-half-points], sup [data-office-character-pos
22700
22700
  }
22701
22701
  }
22702
22702
 
22703
+ .work-pdf-page-organization {
22704
+ border-right: 1px solid var(--a3s-line);
22705
+ padding-right: 5px;
22706
+ }
22707
+
22708
+ .work-pdf-page-organizer-trigger.ds-button {
22709
+ border-color: #0000;
22710
+ gap: 5px;
22711
+ height: 28px;
22712
+ min-height: 28px;
22713
+ padding-inline: 8px;
22714
+ font-size: 10px;
22715
+ }
22716
+
22717
+ .work-pdf-page-organizer-dialog {
22718
+ width: min(980px, 100%);
22719
+ }
22720
+
22721
+ .work-pdf-page-organizer-dialog .ds-dialog-body {
22722
+ gap: 12px;
22723
+ min-height: 0;
22724
+ display: grid;
22725
+ }
22726
+
22727
+ .work-pdf-page-organizer-actions {
22728
+ grid-template-columns: repeat(9, minmax(72px, 1fr));
22729
+ gap: 5px;
22730
+ display: grid;
22731
+ }
22732
+
22733
+ .work-pdf-page-organizer-actions .ds-button {
22734
+ white-space: nowrap;
22735
+ gap: 5px;
22736
+ min-width: 0;
22737
+ min-height: 36px;
22738
+ padding-inline: 7px;
22739
+ font-size: 10px;
22740
+ }
22741
+
22742
+ .work-pdf-page-organizer-selection {
22743
+ min-height: 28px;
22744
+ color: var(--a3s-muted);
22745
+ align-items: center;
22746
+ gap: 8px;
22747
+ font-size: 11px;
22748
+ display: flex;
22749
+ }
22750
+
22751
+ .work-pdf-page-organizer-selection output {
22752
+ font-variant-numeric: tabular-nums;
22753
+ margin-right: auto;
22754
+ font-weight: 650;
22755
+ }
22756
+
22757
+ .work-pdf-page-organizer-selection button {
22758
+ border: 1px solid var(--a3s-line);
22759
+ background: var(--a3s-panel);
22760
+ min-height: 28px;
22761
+ color: var(--a3s-muted);
22762
+ font: inherit;
22763
+ cursor: pointer;
22764
+ border-radius: 6px;
22765
+ padding: 0 9px;
22766
+ }
22767
+
22768
+ .work-pdf-page-organizer-selection button:hover:not(:disabled), .work-pdf-page-organizer-selection button:focus-visible {
22769
+ border-color: var(--a3s-line-strong);
22770
+ background: var(--a3s-panel-soft);
22771
+ color: var(--a3s-ink);
22772
+ outline: 0;
22773
+ }
22774
+
22775
+ .work-pdf-page-organizer-viewport {
22776
+ border: 1px solid var(--a3s-line);
22777
+ background: linear-gradient(var(--a3s-panel-soft), var(--a3s-panel-soft)) padding-box,
22778
+ var(--a3s-panel-soft);
22779
+ overscroll-behavior: contain;
22780
+ scrollbar-gutter: stable;
22781
+ border-radius: 10px;
22782
+ height: min(51vh, 552px);
22783
+ min-height: 260px;
22784
+ overflow: auto;
22785
+ }
22786
+
22787
+ .work-pdf-page-organizer-list {
22788
+ gap: 12px;
22789
+ padding: 12px;
22790
+ display: grid;
22791
+ }
22792
+
22793
+ .work-pdf-page-organizer-list > span[aria-hidden="true"] {
22794
+ display: block;
22795
+ }
22796
+
22797
+ .work-pdf-page-organizer-list > button {
22798
+ border: 1px solid var(--a3s-line);
22799
+ background: var(--a3s-panel);
22800
+ width: 100%;
22801
+ height: 172px;
22802
+ color: var(--a3s-ink);
22803
+ text-align: left;
22804
+ cursor: grab;
22805
+ border-radius: 9px;
22806
+ outline: 0;
22807
+ grid-template-columns: 72px minmax(0, 1fr);
22808
+ align-items: center;
22809
+ gap: 14px;
22810
+ padding: 12px 16px;
22811
+ transition: border-color .12s, background-color .12s, box-shadow .12s;
22812
+ display: grid;
22813
+ }
22814
+
22815
+ .work-pdf-page-organizer-list > button:hover:not(:disabled) {
22816
+ border-color: var(--a3s-line-strong);
22817
+ background: color-mix(in srgb, var(--work-pdf-accent) 3%, var(--a3s-panel));
22818
+ }
22819
+
22820
+ .work-pdf-page-organizer-list > button:focus-visible {
22821
+ border-color: var(--work-pdf-accent);
22822
+ box-shadow: 0 0 0 2px
22823
+ color-mix(in srgb, var(--work-pdf-accent) 18%, transparent);
22824
+ }
22825
+
22826
+ .work-pdf-page-organizer-list > button.selected {
22827
+ border-color: color-mix(in srgb, var(--work-pdf-accent) 70%, var(--a3s-line));
22828
+ background: color-mix(in srgb, var(--work-pdf-accent) 8%, var(--a3s-panel));
22829
+ }
22830
+
22831
+ .work-pdf-page-organizer-list > button:active:not(:disabled) {
22832
+ cursor: grabbing;
22833
+ }
22834
+
22835
+ .work-pdf-page-organizer-number {
22836
+ color: var(--a3s-ink);
22837
+ font-variant-numeric: tabular-nums;
22838
+ justify-items: center;
22839
+ gap: 5px;
22840
+ font-size: 18px;
22841
+ font-weight: 700;
22842
+ display: grid;
22843
+ }
22844
+
22845
+ .work-pdf-page-organizer-number small {
22846
+ background: color-mix(in srgb, var(--work-pdf-accent) 10%, var(--a3s-panel));
22847
+ color: var(--work-pdf-accent);
22848
+ border-radius: 999px;
22849
+ padding: 2px 6px;
22850
+ font-size: 9px;
22851
+ font-weight: 650;
22852
+ }
22853
+
22854
+ .work-pdf-page-organizer-preview {
22855
+ border: 1px solid var(--a3s-line);
22856
+ background: #e7e9ee;
22857
+ border-radius: 4px;
22858
+ justify-self: center;
22859
+ place-items: center;
22860
+ width: min(100%, 560px);
22861
+ height: 146px;
22862
+ display: grid;
22863
+ overflow: hidden;
22864
+ }
22865
+
22866
+ .work-pdf-page-organizer-preview img {
22867
+ object-fit: contain;
22868
+ max-width: 100%;
22869
+ max-height: 100%;
22870
+ display: block;
22871
+ }
22872
+
22873
+ .work-pdf-page-organizer-preview[data-state="loading"]:after {
22874
+ content: "";
22875
+ background: linear-gradient(90deg, #ffffff47, #ffffffc2, #ffffff47);
22876
+ border-radius: 999px;
22877
+ width: 48%;
22878
+ height: 8px;
22879
+ animation: 1.1s ease-in-out infinite work-pdf-organizer-loading;
22880
+ }
22881
+
22882
+ .work-pdf-page-organizer-preview[data-state="error"]:after {
22883
+ color: #676d78;
22884
+ content: "无法生成缩略图";
22885
+ font-size: 10px;
22886
+ }
22887
+
22888
+ .work-pdf-page-organizer-error, .work-pdf-page-organizer-diagnostics, .work-pdf-page-organizer-boundary {
22889
+ border: 1px solid var(--a3s-line);
22890
+ border-radius: 8px;
22891
+ margin: 0;
22892
+ padding: 10px 12px;
22893
+ font-size: 11px;
22894
+ line-height: 1.5;
22895
+ }
22896
+
22897
+ .work-pdf-page-organizer-error {
22898
+ border-color: color-mix(in srgb, var(--a3s-red) 38%, var(--a3s-line));
22899
+ background: color-mix(in srgb, var(--a3s-red) 5%, var(--a3s-panel));
22900
+ color: var(--a3s-red);
22901
+ align-items: flex-start;
22902
+ gap: 12px;
22903
+ display: flex;
22904
+ }
22905
+
22906
+ .work-pdf-page-organizer-error > div {
22907
+ flex: 1;
22908
+ min-width: 0;
22909
+ }
22910
+
22911
+ .work-pdf-page-organizer-error p {
22912
+ overflow-wrap: anywhere;
22913
+ margin: 2px 0 4px;
22914
+ }
22915
+
22916
+ .work-pdf-page-organizer-error code {
22917
+ font-size: 9px;
22918
+ }
22919
+
22920
+ .work-pdf-page-organizer-error > button {
22921
+ color: currentColor;
22922
+ cursor: pointer;
22923
+ background: none;
22924
+ border: 0;
22925
+ border-radius: 6px;
22926
+ width: 30px;
22927
+ height: 30px;
22928
+ padding: 0;
22929
+ font-size: 18px;
22930
+ }
22931
+
22932
+ .work-pdf-page-organizer-diagnostics {
22933
+ border-color: color-mix(in srgb, #b7791f 35%, var(--a3s-line));
22934
+ color: #8b5e16;
22935
+ padding-left: 28px;
22936
+ }
22937
+
22938
+ .work-pdf-page-organizer-boundary {
22939
+ background: var(--a3s-panel-soft);
22940
+ color: var(--a3s-muted);
22941
+ }
22942
+
22943
+ @keyframes work-pdf-organizer-loading {
22944
+ 0%, 100% {
22945
+ opacity: .45;
22946
+ transform: translateX(-12%);
22947
+ }
22948
+
22949
+ 50% {
22950
+ opacity: 1;
22951
+ transform: translateX(12%);
22952
+ }
22953
+ }
22954
+
22955
+ @media (width <= 980px) {
22956
+ .work-pdf-page-organization {
22957
+ display: none;
22958
+ }
22959
+
22960
+ .work-pdf-page-organizer-actions {
22961
+ grid-template-columns: repeat(3, minmax(0, 1fr));
22962
+ }
22963
+ }
22964
+
22965
+ @media (width <= 560px) {
22966
+ .work-pdf-page-organizer-dialog .ds-dialog-body {
22967
+ gap: 9px;
22968
+ }
22969
+
22970
+ .work-pdf-page-organizer-actions {
22971
+ overscroll-behavior: contain;
22972
+ grid-template-columns: repeat(2, minmax(0, 1fr));
22973
+ max-height: 188px;
22974
+ overflow-y: auto;
22975
+ }
22976
+
22977
+ .work-pdf-page-organizer-actions .ds-button {
22978
+ min-height: 44px;
22979
+ }
22980
+
22981
+ .work-pdf-page-organizer-selection button {
22982
+ min-width: 44px;
22983
+ min-height: 36px;
22984
+ }
22985
+
22986
+ .work-pdf-page-organizer-viewport {
22987
+ height: min(38vh, 420px);
22988
+ min-height: 220px;
22989
+ }
22990
+
22991
+ .work-pdf-page-organizer-list {
22992
+ padding-inline: 8px;
22993
+ }
22994
+
22995
+ .work-pdf-page-organizer-list > button {
22996
+ grid-template-columns: 48px minmax(0, 1fr);
22997
+ padding-inline: 10px;
22998
+ }
22999
+
23000
+ .work-pdf-page-organizer-number {
23001
+ font-size: 15px;
23002
+ }
23003
+ }
23004
+
23005
+ @media (forced-colors: active) {
23006
+ .work-pdf-page-organizer-list > button.selected {
23007
+ outline: 2px solid highlight;
23008
+ }
23009
+ }
23010
+
23011
+ @media (prefers-reduced-motion: reduce) {
23012
+ .work-pdf-page-organizer-list > button, .work-pdf-page-organizer-preview[data-state="loading"]:after {
23013
+ transition: none;
23014
+ animation: none;
23015
+ }
23016
+ }
23017
+
22703
23018
  .work-pdf-export-surface {
22704
23019
  z-index: -1000;
22705
23020
  color: #20232b;
package/dist/vue.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Extensions } from '@tiptap/core';
2
2
  import { type PropType } from 'vue';
3
- import type { DocumentContent, DocumentReviewConflictEvent, EditorAgentRequest, GetDocumentSelectionMenuItems, GetMarkdownSelectionMenuItems, MarkdownContent, OfficeCollaborationPresence, OfficeCollaborationSession, PdfCollaborationContent, PresentationContent, SpreadsheetContent } from './core';
3
+ import type { DocumentContent, DocumentReviewConflictEvent, EditorAgentRequest, GetDocumentSelectionMenuItems, GetMarkdownSelectionMenuItems, MarkdownContent, OfficeCollaborationPresence, OfficeCollaborationSession, PdfCollaborationContent, PdfPageOrganizationExport, PresentationContent, SpreadsheetContent } from './core';
4
4
  import type { OfficeTheme } from './office-surface';
5
5
  import { type DocumentLayoutFont, type OfficeFileAction, type PdfEvidenceOverlay, type PdfEvidenceRegion } from './react';
6
6
  export declare const DocumentEditor: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
@@ -274,6 +274,7 @@ export declare const PdfViewer: import("vue").DefineComponent<import("vue").Extr
274
274
  type: PropType<() => Promise<Blob>>;
275
275
  };
276
276
  onSave: PropType<(pdf: Blob) => Promise<boolean>>;
277
+ onPageExport: PropType<(files: readonly PdfPageOrganizationExport[]) => boolean | Promise<boolean>>;
277
278
  saveLabel: StringConstructor;
278
279
  selectedEvidenceRegionId: StringConstructor;
279
280
  sourceKey: StringConstructor;
@@ -302,6 +303,7 @@ export declare const PdfViewer: import("vue").DefineComponent<import("vue").Extr
302
303
  type: PropType<() => Promise<Blob>>;
303
304
  };
304
305
  onSave: PropType<(pdf: Blob) => Promise<boolean>>;
306
+ onPageExport: PropType<(files: readonly PdfPageOrganizationExport[]) => boolean | Promise<boolean>>;
305
307
  saveLabel: StringConstructor;
306
308
  selectedEvidenceRegionId: StringConstructor;
307
309
  sourceKey: StringConstructor;
package/dist/vue.js CHANGED
@@ -232,6 +232,7 @@ const PdfViewer = defineComponent({
232
232
  type: Function
233
233
  },
234
234
  onSave: Function,
235
+ onPageExport: Function,
235
236
  saveLabel: String,
236
237
  selectedEvidenceRegionId: String,
237
238
  sourceKey: String,
@@ -257,6 +258,7 @@ const PdfViewer = defineComponent({
257
258
  onCollaborationChange: (content)=>emit('collaborationChange', content),
258
259
  onEvidenceRegionSelect: (region)=>emit('evidenceRegionSelect', region),
259
260
  onPageChange: (pageNumber)=>emit('pageChange', pageNumber),
261
+ onPageExport: props.onPageExport,
260
262
  onSave: props.onSave,
261
263
  saveLabel: props.saveLabel,
262
264
  selectedEvidenceRegionId: props.selectedEvidenceRegionId,
@@ -1,6 +1,6 @@
1
1
  import type { Extensions } from '@tiptap/core';
2
2
  import { type ReactNode } from 'react';
3
- import type { DocumentContent, EditorAgentRequest, GetDocumentSelectionMenuItems, GetMarkdownSelectionMenuItems, MarkdownContent, OfficeCollaborationPresence, OfficeCollaborationSession, PdfCollaborationContent, PresentationContent, SpreadsheetContent } from './core';
3
+ import type { DocumentContent, EditorAgentRequest, GetDocumentSelectionMenuItems, GetMarkdownSelectionMenuItems, MarkdownContent, OfficeCollaborationPresence, OfficeCollaborationSession, PdfCollaborationContent, PdfPageOrganizationExport, PresentationContent, SpreadsheetContent } from './core';
4
4
  import type { OfficeTheme } from './office-surface';
5
5
  import { type DocumentLayoutFont, type OfficeFileAction, type PdfEvidenceOverlay } from './react';
6
6
  declare const HTMLElementBase: {
@@ -92,6 +92,8 @@ export declare class A3SPdfViewerElement extends A3SOfficeElement {
92
92
  set onCollaborationChange(value: ((content: PdfCollaborationContent) => void) | undefined);
93
93
  get onSave(): ((pdf: Blob) => Promise<boolean>) | undefined;
94
94
  set onSave(value: ((pdf: Blob) => Promise<boolean>) | undefined);
95
+ get onPageExport(): ((files: readonly PdfPageOrganizationExport[]) => boolean | Promise<boolean>) | undefined;
96
+ set onPageExport(value: ((files: readonly PdfPageOrganizationExport[]) => boolean | Promise<boolean>) | undefined);
95
97
  get selectedEvidenceRegionId(): string | undefined;
96
98
  set selectedEvidenceRegionId(value: string | undefined);
97
99
  get theme(): OfficeTheme;
@@ -308,6 +308,7 @@ class A3SPdfViewerElement extends A3SOfficeElement {
308
308
  #loadSource;
309
309
  #onCollaborationChange;
310
310
  #onSave;
311
+ #onPageExport;
311
312
  static get observedAttributes() {
312
313
  return [
313
314
  'file-name',
@@ -354,6 +355,13 @@ class A3SPdfViewerElement extends A3SOfficeElement {
354
355
  this.#onSave = value;
355
356
  this.requestRender();
356
357
  }
358
+ get onPageExport() {
359
+ return this.#onPageExport;
360
+ }
361
+ set onPageExport(value) {
362
+ this.#onPageExport = value;
363
+ this.requestRender();
364
+ }
357
365
  get selectedEvidenceRegionId() {
358
366
  return this.getAttribute('selected-evidence-region-id') ?? void 0;
359
367
  }
@@ -387,6 +395,7 @@ class A3SPdfViewerElement extends A3SOfficeElement {
387
395
  },
388
396
  onEvidenceRegionSelect: (region)=>dispatchDetail(this, 'evidence-select', region),
389
397
  onPageChange: (pageNumber)=>dispatchDetail(this, 'page-change', pageNumber),
398
+ onPageExport: this.onPageExport,
390
399
  onSave: this.onSave,
391
400
  saveLabel: this.getAttribute('save-label') ?? void 0,
392
401
  selectedEvidenceRegionId: this.selectedEvidenceRegionId,
@@ -1556,13 +1556,36 @@ pages: EmbedPDF already mounts only six to seven pages behind its Shadow DOM
1556
1556
  boundary, while CSS containment cannot cancel PDFium tasks or release bitmap
1557
1557
  memory.
1558
1558
 
1559
- Existing PDF password handling remains in the PDF document lifecycle rather
1560
- than the removed toolbar. Form-authoring controls, redaction review, page
1561
- organization, and compatibility fixtures remain part of this stage.
1559
+ The first PDF-workbench slice adds a second lazy Worker boundary for page
1560
+ organization. The UI sends bounded source bytes plus a typed insert, delete,
1561
+ rotate, reorder, merge, extract, or split plan to `pdf-lib`; it never moves a
1562
+ `PDFDocument` or page object across threads. A source mutation transfers one
1563
+ result byte array back, replaces the viewer's complete Blob, reopens it in
1564
+ PDFium, and records the before/after Blob pair as one Undo entry. Exports return
1565
+ typed files without changing the source or history. The toolbar consumes
1566
+ PDFium annotation/form history before this page history, so one user intent
1567
+ never spans both stacks. Primary sources are capped at 256 MiB, merge inputs at
1568
+ 128 MiB, and each result at 4,096 pages.
1569
+
1570
+ The rewrite boundary is fail closed. Malformed, encrypted, or signed sources
1571
+ cannot be mutated. Delete, reorder, and merge additionally reject forms,
1572
+ outlines, and tagged structure because their catalog references cannot yet be
1573
+ rewritten safely. Extract and split can copy page ranges while returning an
1574
+ explicit diagnostic for omitted document-level objects. Collaboration and
1575
+ evidence-overlay sessions hide page organization because both attach stable
1576
+ records to immutable source-page identities. `onPageExport` is the typed host
1577
+ port for derived files; `onSave` remains the only persistence port for the
1578
+ mutated source.
1562
1579
 
1563
- Exit criteria: annotations and form changes survive reopen; destructive
1564
- redaction requires an explicit review step; large documents render a bounded
1565
- page window rather than the complete file.
1580
+ Existing PDF password handling remains in the PDF document lifecycle rather
1581
+ than the removed toolbar. Form-authoring controls, redaction review,
1582
+ document-level catalog rewriting, and broader compatibility fixtures remain
1583
+ part of this stage.
1584
+
1585
+ Exit criteria: annotations, form changes, and page mutations survive PDFium and
1586
+ independent-parser reopen; destructive redaction requires an explicit review
1587
+ step; large documents render a bounded page window rather than the complete
1588
+ file.
1566
1589
 
1567
1590
  ### Stage 6: loss-preserving Office persistence
1568
1591
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a3s-lab/office",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "description": "Open-source collaborative browser editors for documents, Markdown, spreadsheets, presentations, and PDFs.",
5
5
  "keywords": [
6
6
  "office",
@@ -114,6 +114,7 @@
114
114
  "playground:visual:spreadsheet-rich-text": "playwright test visual-tests/spreadsheet-rich-text.functional.spec.ts --config playwright.config.ts",
115
115
  "playground:visual:spreadsheet-underline": "playwright test visual-tests/spreadsheet-underline.functional.spec.ts --config playwright.config.ts",
116
116
  "playground:visual:spreadsheet-table": "playwright test visual-tests/spreadsheet-table.functional.spec.ts --config playwright.config.ts",
117
+ "playground:visual:pdf-page-organization": "playwright test visual-tests/pdf-page-organization.functional.spec.ts --config playwright.config.ts",
117
118
  "playground:visual:update": "playwright test --config playwright.config.ts --update-snapshots",
118
119
  "performance:fixtures": "bun .a3s-test/performance/generate-fixtures.ts",
119
120
  "performance:large-document-edits": "bun .a3s-test/performance/generate-fixtures.ts --documents-only && bun .a3s-test/performance/benchmark-document-edit.ts http://127.0.0.1:4175/ 3",
@@ -130,6 +131,8 @@
130
131
  "test:e2e:large-documents:check": "a3s-test check tests/e2e/word-large-document-windowing.acl --json",
131
132
  "test:e2e:large-pdf": "bun .a3s-test/performance/generate-fixtures.ts --pdf-only && a3s-test run tests/e2e/pdf-large-windowing.acl --json",
132
133
  "test:e2e:large-pdf:check": "a3s-test check tests/e2e/pdf-large-windowing.acl --json",
134
+ "test:e2e:pdf-page-organization": "bun run test:e2e:fixtures && A3S_TEST_SUITE=tests/e2e/pdf-page-organization.acl bash scripts/run-a3s-test-web-gate.sh",
135
+ "test:e2e:pdf-page-organization:check": "a3s-test check tests/e2e/pdf-page-organization.acl --json",
133
136
  "test:e2e:large-presentation": "bun .a3s-test/performance/generate-fixtures.ts --presentations-only && a3s-test run tests/e2e/presentation-large-windowing.acl --json",
134
137
  "test:e2e:large-presentation:check": "a3s-test check tests/e2e/presentation-large-windowing.acl --json",
135
138
  "test:e2e:initial-focus": "a3s-test run tests/e2e/office-editor-initial-focus.acl --json",
@@ -284,6 +287,7 @@
284
287
  "jszip": "^3.10.1",
285
288
  "lucide-react": "^0.544.0",
286
289
  "mammoth": "^1.12.0",
290
+ "pdf-lib": "1.17.1",
287
291
  "pptxgenjs": "^4.0.1",
288
292
  "xlsx": "^0.18.5",
289
293
  "y-protocols": "1.0.7",