@file-viewer/core 2.1.13 → 2.1.14

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.
@@ -78,6 +78,11 @@ export interface FileViewerPdfOptions {
78
78
  defaultNavigationVisible?: boolean;
79
79
  thumbnails?: boolean;
80
80
  rotation?: number;
81
+ /**
82
+ * Initial PDF view position. Prefer the top-level `initialViewState` when the
83
+ * same state should be passed through framework-neutral viewer APIs.
84
+ */
85
+ initialViewState?: FileViewerViewState;
81
86
  streaming?: boolean | 'same-origin';
82
87
  rangeChunkSize?: number;
83
88
  withCredentials?: boolean;
@@ -106,13 +111,19 @@ export interface FileViewerDocxOptions {
106
111
  ignoreLastRenderedPageBreak?: boolean;
107
112
  }
108
113
  export interface FileViewerSpreadsheetOptions {
109
- worker?: boolean;
114
+ worker?: boolean | 'auto';
110
115
  workerUrl?: string;
116
+ /** `worker: 'auto'` 时,大于该字节数的表格自动使用静态 Worker,默认 1MB。 */
117
+ workerAutoThreshold?: number;
111
118
  /** 允许用户在 Excel / CSV / ODS 预览中拖拽表头边界调整列宽,默认关闭以保持历史行为。 */
112
119
  resizableColumns?: boolean;
113
120
  /** 允许用户在 Excel / CSV / ODS 预览中拖拽行头边界调整行高,默认关闭以保持历史行为。 */
114
121
  resizableRows?: boolean;
115
122
  }
123
+ export interface FileViewerPresentationOptions {
124
+ workerUrl?: string | URL;
125
+ workerType?: WorkerType;
126
+ }
116
127
  export type FileRenderExportMode = 'export' | 'print';
117
128
  export interface FileRenderExportOptions {
118
129
  mode: FileRenderExportMode;
@@ -387,9 +398,19 @@ export interface FileViewerOptions {
387
398
  toolbar?: boolean | FileViewerToolbarOptions;
388
399
  search?: boolean | FileViewerSearchOptions;
389
400
  ai?: boolean | FileViewerAiOptions;
401
+ /**
402
+ * Initial renderer view position used after the document becomes ready.
403
+ *
404
+ * Renderers apply the fields they understand. All standard renderer paths
405
+ * expose at least renderer / zoom / scroll snapshots through the generic
406
+ * provider; high-interaction renderers such as PDF, XMind, Geo, 3D, and CAD
407
+ * add page, navigation, canvas, map, camera, or native view details.
408
+ */
409
+ initialViewState?: FileViewerViewState;
390
410
  archive?: FileViewerArchiveOptions;
391
411
  pdf?: FileViewerPdfOptions;
392
412
  docx?: FileViewerDocxOptions;
413
+ presentation?: FileViewerPresentationOptions;
393
414
  spreadsheet?: FileViewerSpreadsheetOptions;
394
415
  typst?: FileViewerTypstOptions;
395
416
  geo?: FileViewerGeoOptions;
@@ -465,6 +486,49 @@ export interface FileViewerZoomProvider {
465
486
  getState: () => FileViewerZoomState;
466
487
  subscribe?: (listener: () => void) => () => void;
467
488
  }
489
+ export interface FileViewerViewScrollState {
490
+ top: number;
491
+ left: number;
492
+ width: number;
493
+ height: number;
494
+ clientWidth: number;
495
+ clientHeight: number;
496
+ topRatio: number;
497
+ leftRatio: number;
498
+ }
499
+ export interface FileViewerNavigationState {
500
+ visible?: boolean;
501
+ mode?: string;
502
+ }
503
+ export interface FileViewerViewState {
504
+ renderer?: string;
505
+ page?: number;
506
+ pageCount?: number;
507
+ scale?: number;
508
+ zoom?: FileViewerZoomState;
509
+ rotation?: number;
510
+ scroll?: Partial<FileViewerViewScrollState>;
511
+ navigation?: FileViewerNavigationState;
512
+ extra?: Record<string, unknown>;
513
+ }
514
+ export type FileViewerViewStateChangeSource = 'initial' | 'api' | 'user' | 'viewer' | (string & {});
515
+ export type FileViewerViewStateChangeAction = 'init' | 'restore' | 'page-change' | 'page-click' | 'page-step' | 'outline-click' | 'zoom-change' | 'zoom-in' | 'zoom-out' | 'zoom-reset' | 'rotation-change' | 'rotate-left' | 'rotate-right' | 'scroll' | 'navigation-toggle' | 'navigation-mode-change' | (string & {});
516
+ export interface FileViewerViewStateChange {
517
+ state: FileViewerViewState;
518
+ action: FileViewerViewStateChangeAction;
519
+ source: FileViewerViewStateChangeSource;
520
+ timestamp: number;
521
+ }
522
+ export interface FileViewerApplyViewStateOptions {
523
+ notify?: boolean;
524
+ action?: FileViewerViewStateChangeAction;
525
+ source?: FileViewerViewStateChangeSource;
526
+ }
527
+ export interface FileViewerViewStateProvider {
528
+ getState: () => FileViewerViewState;
529
+ applyState?: (state: FileViewerViewState, options?: FileViewerApplyViewStateOptions) => FileViewerViewState | Promise<FileViewerViewState>;
530
+ subscribe?: (listener: (change: FileViewerViewStateChange) => void) => () => void;
531
+ }
468
532
  export interface FileViewerSearchMatch {
469
533
  id: string;
470
534
  index: number;
@@ -523,6 +587,7 @@ export interface FileViewerComponentEventMap {
523
587
  'search-change': FileViewerSearchState;
524
588
  'location-change': FileViewerDocumentAnchor | null;
525
589
  'zoom-change': FileViewerZoomState;
590
+ 'view-state-change': FileViewerViewStateChange;
526
591
  }
527
592
  export type FileViewerEventType = keyof FileViewerComponentEventMap;
528
593
  export type FileViewerEvent = {
@@ -543,6 +608,7 @@ export interface FileViewerComponentEmits {
543
608
  (event: 'search-change', state: FileViewerComponentEventMap['search-change']): void;
544
609
  (event: 'location-change', anchor: FileViewerComponentEventMap['location-change']): void;
545
610
  (event: 'zoom-change', state: FileViewerComponentEventMap['zoom-change']): void;
611
+ (event: 'view-state-change', change: FileViewerComponentEventMap['view-state-change']): void;
546
612
  }
547
613
  export interface FileViewerPublicApi {
548
614
  downloadOriginalFile(): Promise<void>;
@@ -552,6 +618,8 @@ export interface FileViewerPublicApi {
552
618
  zoomOut(): Promise<FileViewerZoomState>;
553
619
  resetZoom(): Promise<FileViewerZoomState>;
554
620
  getZoomState(): FileViewerZoomState;
621
+ getViewState(): FileViewerViewState | null;
622
+ applyViewState(state: FileViewerViewState, options?: FileViewerApplyViewStateOptions): Promise<FileViewerViewState | null>;
555
623
  getOperationAvailability(): FileViewerOperationAvailability;
556
624
  getScrollContainer(): HTMLElement | null;
557
625
  searchDocument(query: string): Promise<FileViewerSearchState>;
@@ -695,6 +763,8 @@ export interface FileViewerInstance {
695
763
  zoomOut(): Promise<FileViewerZoomState>;
696
764
  resetZoom(): Promise<FileViewerZoomState>;
697
765
  getZoomState(): FileViewerZoomState;
766
+ getViewState(): FileViewerViewState | null;
767
+ applyViewState(state: FileViewerViewState, options?: FileViewerApplyViewStateOptions): Promise<FileViewerViewState | null>;
698
768
  search(query: string): Promise<FileViewerSearchState>;
699
769
  nextSearchResult(): Promise<FileViewerSearchState>;
700
770
  previousSearchResult(): Promise<FileViewerSearchState>;
@@ -1,5 +1,5 @@
1
1
  export { DEFAULT_FILE_VIEWER_ANCHOR_EXCLUDE_SELECTOR, DEFAULT_FILE_VIEWER_ANCHOR_SELECTOR, collectFileViewerDocumentAnchors, findFileViewerAnchorForElement, getCurrentFileViewerDocumentAnchor, scrollToFileViewerDocumentAnchor, } from './anchors';
2
- export { findFileViewerSearchProvider, findFileViewerZoomProvider, registerFileViewerSearchProvider, registerFileViewerZoomProvider, unregisterFileViewerSearchProvider, unregisterFileViewerZoomProvider, } from './providers';
3
- export type { FileViewerSearchProviderHost, FileViewerZoomProviderHost, } from './providers';
2
+ export { findFileViewerSearchProvider, findFileViewerViewStateProvider, findFileViewerZoomProvider, registerFileViewerSearchProvider, registerFileViewerViewStateProvider, registerFileViewerZoomProvider, unregisterFileViewerSearchProvider, unregisterFileViewerViewStateProvider, unregisterFileViewerZoomProvider, } from './providers';
3
+ export type { FileViewerSearchProviderHost, FileViewerViewStateProviderHost, FileViewerZoomProviderHost, } from './providers';
4
4
  export { DEFAULT_FILE_VIEWER_SCROLL_CONTAINER_CANDIDATE_SELECTOR, DEFAULT_FILE_VIEWER_SCROLL_CONTAINER_SELECTOR, DEFAULT_FILE_VIEWER_SCROLLABLE_OVERFLOW_VALUES, getFileViewerScrollableRange, isFileViewerScrollableElement, resolveFileViewerScrollContainer, } from './scroll';
5
5
  export type { ResolveFileViewerScrollContainerOptions, } from './scroll';
@@ -1,3 +1,3 @@
1
1
  export { DEFAULT_FILE_VIEWER_ANCHOR_EXCLUDE_SELECTOR, DEFAULT_FILE_VIEWER_ANCHOR_SELECTOR, collectFileViewerDocumentAnchors, findFileViewerAnchorForElement, getCurrentFileViewerDocumentAnchor, scrollToFileViewerDocumentAnchor, } from './anchors.js';
2
- export { findFileViewerSearchProvider, findFileViewerZoomProvider, registerFileViewerSearchProvider, registerFileViewerZoomProvider, unregisterFileViewerSearchProvider, unregisterFileViewerZoomProvider, } from './providers.js';
2
+ export { findFileViewerSearchProvider, findFileViewerViewStateProvider, findFileViewerZoomProvider, registerFileViewerSearchProvider, registerFileViewerViewStateProvider, registerFileViewerZoomProvider, unregisterFileViewerSearchProvider, unregisterFileViewerViewStateProvider, unregisterFileViewerZoomProvider, } from './providers.js';
3
3
  export { DEFAULT_FILE_VIEWER_SCROLL_CONTAINER_CANDIDATE_SELECTOR, DEFAULT_FILE_VIEWER_SCROLL_CONTAINER_SELECTOR, DEFAULT_FILE_VIEWER_SCROLLABLE_OVERFLOW_VALUES, getFileViewerScrollableRange, isFileViewerScrollableElement, resolveFileViewerScrollContainer, } from './scroll.js';
@@ -1,13 +1,19 @@
1
- import type { FileViewerSearchProvider, FileViewerZoomProvider } from '../../../contracts/types';
1
+ import type { FileViewerSearchProvider, FileViewerViewStateProvider, FileViewerZoomProvider } from '../../../contracts/types';
2
2
  export interface FileViewerSearchProviderHost extends HTMLElement {
3
3
  __flyfishViewerSearchProvider?: FileViewerSearchProvider;
4
4
  }
5
5
  export interface FileViewerZoomProviderHost extends HTMLElement {
6
6
  __flyfishViewerZoomProvider?: FileViewerZoomProvider;
7
7
  }
8
+ export interface FileViewerViewStateProviderHost extends HTMLElement {
9
+ __flyfishViewerViewStateProvider?: FileViewerViewStateProvider;
10
+ }
8
11
  export declare const registerFileViewerSearchProvider: (host: HTMLElement, provider: FileViewerSearchProvider) => void;
9
12
  export declare const unregisterFileViewerSearchProvider: (host: HTMLElement | null | undefined) => void;
10
13
  export declare const findFileViewerSearchProvider: (root: HTMLElement | null | undefined) => FileViewerSearchProvider | null;
11
14
  export declare const registerFileViewerZoomProvider: (host: HTMLElement, provider: FileViewerZoomProvider) => void;
12
15
  export declare const unregisterFileViewerZoomProvider: (host: HTMLElement | null | undefined) => void;
13
16
  export declare const findFileViewerZoomProvider: (root: HTMLElement | null | undefined) => FileViewerZoomProvider | null;
17
+ export declare const registerFileViewerViewStateProvider: (host: HTMLElement, provider: FileViewerViewStateProvider) => void;
18
+ export declare const unregisterFileViewerViewStateProvider: (host: HTMLElement | null | undefined) => void;
19
+ export declare const findFileViewerViewStateProvider: (root: HTMLElement | null | undefined) => FileViewerViewStateProvider | null;
@@ -1,5 +1,6 @@
1
1
  const searchProviderRegistry = new WeakMap();
2
2
  const zoomProviderRegistry = new WeakMap();
3
+ const viewStateProviderRegistry = new WeakMap();
3
4
  export const registerFileViewerSearchProvider = (host, provider) => {
4
5
  searchProviderRegistry.set(host, provider);
5
6
  host.__flyfishViewerSearchProvider = provider;
@@ -50,3 +51,34 @@ export const findFileViewerZoomProvider = (root) => {
50
51
  ? zoomProviderRegistry.get(host) || host.__flyfishViewerZoomProvider || null
51
52
  : null;
52
53
  };
54
+ export const registerFileViewerViewStateProvider = (host, provider) => {
55
+ viewStateProviderRegistry.set(host, provider);
56
+ host.dataset.viewerViewStateProvider = host.dataset.viewerViewStateProvider || 'custom';
57
+ host.__flyfishViewerViewStateProvider = provider;
58
+ };
59
+ export const unregisterFileViewerViewStateProvider = (host) => {
60
+ if (!host) {
61
+ return;
62
+ }
63
+ viewStateProviderRegistry.delete(host);
64
+ delete host.dataset.viewerViewStateProvider;
65
+ delete host.__flyfishViewerViewStateProvider;
66
+ };
67
+ export const findFileViewerViewStateProvider = (root) => {
68
+ if (!root) {
69
+ return null;
70
+ }
71
+ const direct = viewStateProviderRegistry.get(root) ||
72
+ root.__flyfishViewerViewStateProvider;
73
+ if (direct && root.dataset.viewerViewStateProvider !== 'generic') {
74
+ return direct;
75
+ }
76
+ const hosts = Array.from(root.querySelectorAll('[data-viewer-view-state-provider]'));
77
+ const customHost = hosts.find(host => host.dataset.viewerViewStateProvider !== 'generic');
78
+ const genericHost = hosts.find(host => host.dataset.viewerViewStateProvider === 'generic');
79
+ const host = customHost || genericHost;
80
+ if (host) {
81
+ return viewStateProviderRegistry.get(host) || host.__flyfishViewerViewStateProvider || null;
82
+ }
83
+ return direct || null;
84
+ };
@@ -0,0 +1,44 @@
1
+ import type { FileViewerApplyViewStateOptions, FileViewerViewState, FileViewerViewStateChange, FileViewerViewStateProvider } from '../../contracts/types';
2
+ export interface RegisterFileViewerGenericViewStateProviderOptions {
3
+ host: HTMLElement;
4
+ renderer?: string;
5
+ scrollTarget?: HTMLElement | (() => HTMLElement | null | undefined) | null;
6
+ }
7
+ export interface FileViewerGenericViewStateProviderRegistration {
8
+ provider: FileViewerViewStateProvider;
9
+ destroy: () => void;
10
+ }
11
+ export interface CreateFileViewerViewStateControllerOptions {
12
+ root: () => HTMLElement | null | undefined;
13
+ enabled?: () => boolean;
14
+ onChange?: (change: FileViewerViewStateChange) => void;
15
+ }
16
+ export interface FileViewerViewStateController {
17
+ readonly provider: FileViewerViewStateProvider | null;
18
+ readonly state: FileViewerViewState | null;
19
+ hasProvider(): boolean;
20
+ refreshProvider(): FileViewerViewStateProvider | null;
21
+ observe(): void;
22
+ clearProvider(): FileViewerViewState | null;
23
+ getState(): FileViewerViewState | null;
24
+ applyState(state: FileViewerViewState, options?: FileViewerApplyViewStateOptions): Promise<FileViewerViewState | null>;
25
+ destroy(): void;
26
+ }
27
+ export interface FileViewerViewStateControllerActionHandlers {
28
+ hasViewStateProvider(): boolean;
29
+ refreshViewStateProvider(): FileViewerViewStateProvider | null;
30
+ startViewStateObserver(): FileViewerViewState | null;
31
+ stopViewStateObserver(): FileViewerViewState | null;
32
+ clearViewStateProvider(): FileViewerViewState | null;
33
+ getViewState(): FileViewerViewState | null;
34
+ applyViewState(state: FileViewerViewState, options?: FileViewerApplyViewStateOptions): Promise<FileViewerViewState | null>;
35
+ }
36
+ export declare const cloneFileViewerViewState: (state?: FileViewerViewState | null) => FileViewerViewState | null;
37
+ export declare const createFileViewerViewStateChange: (state: FileViewerViewState, patch?: Partial<Omit<FileViewerViewStateChange, "state">>) => FileViewerViewStateChange;
38
+ export declare const createFileViewerViewStateChangeEmitter: () => {
39
+ emit(change: FileViewerViewStateChange): void;
40
+ subscribe(listener: (change: FileViewerViewStateChange) => void): () => void;
41
+ };
42
+ export declare const registerFileViewerGenericViewStateProvider: ({ host, renderer, scrollTarget, }: RegisterFileViewerGenericViewStateProviderOptions) => FileViewerGenericViewStateProviderRegistration;
43
+ export declare const createFileViewerViewStateController: ({ root, enabled, onChange, }: CreateFileViewerViewStateControllerOptions) => FileViewerViewStateController;
44
+ export declare const createFileViewerViewStateControllerActionHandlers: (controller: FileViewerViewStateController) => FileViewerViewStateControllerActionHandlers;
@@ -0,0 +1,308 @@
1
+ import { findFileViewerViewStateProvider, findFileViewerZoomProvider, registerFileViewerViewStateProvider, resolveFileViewerScrollContainer, unregisterFileViewerViewStateProvider, } from './dom/index.js';
2
+ export const cloneFileViewerViewState = (state) => {
3
+ if (!state) {
4
+ return null;
5
+ }
6
+ return {
7
+ ...state,
8
+ zoom: state.zoom ? { ...state.zoom } : undefined,
9
+ scroll: state.scroll ? { ...state.scroll } : undefined,
10
+ navigation: state.navigation ? { ...state.navigation } : undefined,
11
+ extra: state.extra ? { ...state.extra } : undefined,
12
+ };
13
+ };
14
+ export const createFileViewerViewStateChange = (state, patch = {}) => ({
15
+ state: cloneFileViewerViewState(state) || {},
16
+ action: patch.action || 'init',
17
+ source: patch.source || 'viewer',
18
+ timestamp: patch.timestamp || Date.now(),
19
+ });
20
+ export const createFileViewerViewStateChangeEmitter = () => {
21
+ const listeners = new Set();
22
+ return {
23
+ emit(change) {
24
+ listeners.forEach(listener => listener(change));
25
+ },
26
+ subscribe(listener) {
27
+ listeners.add(listener);
28
+ return () => {
29
+ listeners.delete(listener);
30
+ };
31
+ },
32
+ };
33
+ };
34
+ const getViewStateWindow = (host) => {
35
+ var _a;
36
+ return ((_a = host.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView) || (typeof window !== 'undefined' ? window : undefined);
37
+ };
38
+ const waitForViewStateFrame = (host) => {
39
+ const ownerWindow = getViewStateWindow(host);
40
+ return new Promise(resolve => {
41
+ if (ownerWindow === null || ownerWindow === void 0 ? void 0 : ownerWindow.requestAnimationFrame) {
42
+ ownerWindow.requestAnimationFrame(() => resolve());
43
+ return;
44
+ }
45
+ setTimeout(resolve, 16);
46
+ });
47
+ };
48
+ const readFileViewerScrollState = (element) => {
49
+ const maxTop = Math.max(0, element.scrollHeight - element.clientHeight);
50
+ const maxLeft = Math.max(0, element.scrollWidth - element.clientWidth);
51
+ return {
52
+ top: element.scrollTop || 0,
53
+ left: element.scrollLeft || 0,
54
+ width: element.scrollWidth || 0,
55
+ height: element.scrollHeight || 0,
56
+ clientWidth: element.clientWidth || 0,
57
+ clientHeight: element.clientHeight || 0,
58
+ topRatio: maxTop > 0 ? (element.scrollTop || 0) / maxTop : 0,
59
+ leftRatio: maxLeft > 0 ? (element.scrollLeft || 0) / maxLeft : 0,
60
+ };
61
+ };
62
+ const resolveScrollValue = (value, ratio, maxValue) => {
63
+ if (Number.isFinite(value)) {
64
+ return Number(value);
65
+ }
66
+ if (Number.isFinite(ratio)) {
67
+ return Number(ratio) * maxValue;
68
+ }
69
+ return undefined;
70
+ };
71
+ export const registerFileViewerGenericViewStateProvider = ({ host, renderer, scrollTarget, }) => {
72
+ var _a;
73
+ const emitter = createFileViewerViewStateChangeEmitter();
74
+ const ownerWindow = getViewStateWindow(host);
75
+ let destroyed = false;
76
+ let scrollFrame = 0;
77
+ let suppressScrollEventUntil = 0;
78
+ let unsubscribeZoom = null;
79
+ const resolveScrollTarget = () => {
80
+ if (typeof scrollTarget === 'function') {
81
+ return scrollTarget() || host;
82
+ }
83
+ return scrollTarget || resolveFileViewerScrollContainer(host) || host;
84
+ };
85
+ const getZoomProvider = () => findFileViewerZoomProvider(host);
86
+ const getState = () => {
87
+ var _a, _b;
88
+ const zoom = (_b = (_a = getZoomProvider()) === null || _a === void 0 ? void 0 : _a.getState) === null || _b === void 0 ? void 0 : _b.call(_a);
89
+ const scrollElement = resolveScrollTarget();
90
+ return {
91
+ renderer,
92
+ scale: zoom === null || zoom === void 0 ? void 0 : zoom.scale,
93
+ zoom,
94
+ scroll: scrollElement ? readFileViewerScrollState(scrollElement) : undefined,
95
+ };
96
+ };
97
+ const emit = (action, source = 'viewer') => {
98
+ if (destroyed) {
99
+ return getState();
100
+ }
101
+ const state = getState();
102
+ emitter.emit(createFileViewerViewStateChange(state, { action, source }));
103
+ return state;
104
+ };
105
+ const suppressProgrammaticScrollEvents = () => {
106
+ suppressScrollEventUntil = Math.max(suppressScrollEventUntil, Date.now() + 180);
107
+ };
108
+ const applyScrollState = (scroll) => {
109
+ if (!scroll) {
110
+ return;
111
+ }
112
+ const scrollElement = resolveScrollTarget();
113
+ const maxTop = Math.max(0, scrollElement.scrollHeight - scrollElement.clientHeight);
114
+ const maxLeft = Math.max(0, scrollElement.scrollWidth - scrollElement.clientWidth);
115
+ const top = resolveScrollValue(scroll.top, scroll.topRatio, maxTop);
116
+ const left = resolveScrollValue(scroll.left, scroll.leftRatio, maxLeft);
117
+ suppressProgrammaticScrollEvents();
118
+ if (top !== undefined) {
119
+ scrollElement.scrollTop = Math.min(Math.max(0, top), maxTop);
120
+ }
121
+ if (left !== undefined) {
122
+ scrollElement.scrollLeft = Math.min(Math.max(0, left), maxLeft);
123
+ }
124
+ };
125
+ const scheduleScrollChange = () => {
126
+ if (destroyed || Date.now() < suppressScrollEventUntil || scrollFrame) {
127
+ return;
128
+ }
129
+ const requestFrame = (ownerWindow === null || ownerWindow === void 0 ? void 0 : ownerWindow.requestAnimationFrame) || ((callback) => {
130
+ return setTimeout(() => callback(Date.now()), 16);
131
+ });
132
+ scrollFrame = requestFrame(() => {
133
+ scrollFrame = 0;
134
+ emit('scroll', 'user');
135
+ });
136
+ };
137
+ const provider = {
138
+ getState,
139
+ async applyState(state, options = {}) {
140
+ var _a, _b;
141
+ const source = options.source || 'api';
142
+ const action = options.action || 'restore';
143
+ const notify = options.notify !== false;
144
+ const zoomProvider = getZoomProvider();
145
+ const nextScale = Number((_a = state.scale) !== null && _a !== void 0 ? _a : (_b = state.zoom) === null || _b === void 0 ? void 0 : _b.scale);
146
+ suppressProgrammaticScrollEvents();
147
+ if (Number.isFinite(nextScale) && (zoomProvider === null || zoomProvider === void 0 ? void 0 : zoomProvider.setZoom)) {
148
+ await zoomProvider.setZoom(nextScale);
149
+ }
150
+ await waitForViewStateFrame(host);
151
+ applyScrollState(state.scroll);
152
+ await waitForViewStateFrame(host);
153
+ applyScrollState(state.scroll);
154
+ if (notify) {
155
+ return emit(action, source);
156
+ }
157
+ return getState();
158
+ },
159
+ subscribe: emitter.subscribe,
160
+ };
161
+ host.dataset.viewerViewStateProvider = 'generic';
162
+ registerFileViewerViewStateProvider(host, provider);
163
+ host.addEventListener('scroll', scheduleScrollChange, {
164
+ capture: true,
165
+ passive: true,
166
+ });
167
+ const zoomProvider = getZoomProvider();
168
+ unsubscribeZoom = ((_a = zoomProvider === null || zoomProvider === void 0 ? void 0 : zoomProvider.subscribe) === null || _a === void 0 ? void 0 : _a.call(zoomProvider, () => {
169
+ emit('zoom-change', 'viewer');
170
+ })) || null;
171
+ return {
172
+ provider,
173
+ destroy() {
174
+ destroyed = true;
175
+ unsubscribeZoom === null || unsubscribeZoom === void 0 ? void 0 : unsubscribeZoom();
176
+ unsubscribeZoom = null;
177
+ if (scrollFrame && (ownerWindow === null || ownerWindow === void 0 ? void 0 : ownerWindow.cancelAnimationFrame)) {
178
+ ownerWindow.cancelAnimationFrame(scrollFrame);
179
+ }
180
+ scrollFrame = 0;
181
+ host.removeEventListener('scroll', scheduleScrollChange, true);
182
+ unregisterFileViewerViewStateProvider(host);
183
+ },
184
+ };
185
+ };
186
+ const getMutationObserverConstructor = (root) => {
187
+ var _a, _b;
188
+ return ((_b = (_a = root === null || root === void 0 ? void 0 : root.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView) === null || _b === void 0 ? void 0 : _b.MutationObserver) ||
189
+ (typeof MutationObserver !== 'undefined' ? MutationObserver : undefined);
190
+ };
191
+ export const createFileViewerViewStateController = ({ root, enabled, onChange, }) => {
192
+ let provider = null;
193
+ let unsubscribe = null;
194
+ let observer = null;
195
+ let state = null;
196
+ const readProviderState = () => { var _a; return cloneFileViewerViewState(((_a = provider === null || provider === void 0 ? void 0 : provider.getState) === null || _a === void 0 ? void 0 : _a.call(provider)) || null); };
197
+ const commitState = (nextState, change) => {
198
+ state = cloneFileViewerViewState(nextState);
199
+ if (change && state) {
200
+ onChange === null || onChange === void 0 ? void 0 : onChange({
201
+ ...change,
202
+ state: cloneFileViewerViewState(change.state) || state,
203
+ });
204
+ }
205
+ return cloneFileViewerViewState(state);
206
+ };
207
+ const clearProvider = () => {
208
+ unsubscribe === null || unsubscribe === void 0 ? void 0 : unsubscribe();
209
+ unsubscribe = null;
210
+ provider = null;
211
+ return commitState(null);
212
+ };
213
+ const syncProvider = () => {
214
+ var _a;
215
+ if ((enabled === null || enabled === void 0 ? void 0 : enabled()) === false) {
216
+ clearProvider();
217
+ return null;
218
+ }
219
+ const nextProvider = findFileViewerViewStateProvider(root());
220
+ if (nextProvider !== provider) {
221
+ unsubscribe === null || unsubscribe === void 0 ? void 0 : unsubscribe();
222
+ provider = nextProvider;
223
+ unsubscribe = ((_a = nextProvider === null || nextProvider === void 0 ? void 0 : nextProvider.subscribe) === null || _a === void 0 ? void 0 : _a.call(nextProvider, change => {
224
+ commitState(change.state, change);
225
+ })) || null;
226
+ }
227
+ commitState(readProviderState());
228
+ return nextProvider;
229
+ };
230
+ const disconnectObserver = () => {
231
+ observer === null || observer === void 0 ? void 0 : observer.disconnect();
232
+ observer = null;
233
+ };
234
+ return {
235
+ get provider() {
236
+ return provider;
237
+ },
238
+ get state() {
239
+ return cloneFileViewerViewState(state);
240
+ },
241
+ hasProvider() {
242
+ return !!syncProvider();
243
+ },
244
+ refreshProvider: syncProvider,
245
+ observe() {
246
+ disconnectObserver();
247
+ const currentRoot = root();
248
+ const MutationObserverCtor = getMutationObserverConstructor(currentRoot);
249
+ if (!currentRoot || !MutationObserverCtor) {
250
+ syncProvider();
251
+ return;
252
+ }
253
+ observer = new MutationObserverCtor(() => {
254
+ syncProvider();
255
+ });
256
+ observer.observe(currentRoot, {
257
+ childList: true,
258
+ subtree: true,
259
+ });
260
+ syncProvider();
261
+ },
262
+ clearProvider,
263
+ getState() {
264
+ syncProvider();
265
+ return cloneFileViewerViewState(state);
266
+ },
267
+ async applyState(nextState, options) {
268
+ const nextProvider = syncProvider();
269
+ if (!(nextProvider === null || nextProvider === void 0 ? void 0 : nextProvider.applyState)) {
270
+ return cloneFileViewerViewState(state);
271
+ }
272
+ const appliedState = await nextProvider.applyState(nextState, options);
273
+ commitState(appliedState || nextProvider.getState());
274
+ return cloneFileViewerViewState(state);
275
+ },
276
+ destroy() {
277
+ disconnectObserver();
278
+ clearProvider();
279
+ },
280
+ };
281
+ };
282
+ export const createFileViewerViewStateControllerActionHandlers = (controller) => {
283
+ return {
284
+ hasViewStateProvider() {
285
+ return controller.hasProvider();
286
+ },
287
+ refreshViewStateProvider() {
288
+ return controller.refreshProvider();
289
+ },
290
+ startViewStateObserver() {
291
+ controller.observe();
292
+ return controller.getState();
293
+ },
294
+ stopViewStateObserver() {
295
+ controller.destroy();
296
+ return null;
297
+ },
298
+ clearViewStateProvider() {
299
+ return controller.clearProvider();
300
+ },
301
+ getViewState() {
302
+ return controller.getState();
303
+ },
304
+ applyViewState(state, options) {
305
+ return controller.applyState(state, options);
306
+ },
307
+ };
308
+ };
@@ -4,6 +4,7 @@ export interface CreateFileViewerZoomControllerOptions {
4
4
  root: () => HTMLElement | null | undefined;
5
5
  enabled?: () => boolean;
6
6
  beforeZoom?: (operation: FileViewerZoomOperation) => Promise<boolean> | boolean;
7
+ onChange?: (state: FileViewerZoomState) => void;
7
8
  }
8
9
  export type MutableFileViewerZoomState = FileViewerZoomState;
9
10
  export interface FileViewerZoomController {
@@ -44,4 +45,4 @@ export declare const createFileViewerZoomChangeEmitter: () => {
44
45
  emit(): void;
45
46
  subscribe(listener: () => void): () => void;
46
47
  };
47
- export declare const createFileViewerZoomController: ({ root, enabled, beforeZoom, }: CreateFileViewerZoomControllerOptions) => FileViewerZoomController;
48
+ export declare const createFileViewerZoomController: ({ root, enabled, beforeZoom, onChange, }: CreateFileViewerZoomControllerOptions) => FileViewerZoomController;
@@ -99,11 +99,15 @@ const getMutationObserverConstructor = (root) => {
99
99
  return ((_b = (_a = root === null || root === void 0 ? void 0 : root.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView) === null || _b === void 0 ? void 0 : _b.MutationObserver) ||
100
100
  (typeof MutationObserver !== 'undefined' ? MutationObserver : undefined);
101
101
  };
102
- export const createFileViewerZoomController = ({ root, enabled, beforeZoom, }) => {
102
+ export const createFileViewerZoomController = ({ root, enabled, beforeZoom, onChange, }) => {
103
103
  let provider = null;
104
104
  let unsubscribe = null;
105
105
  let observer = null;
106
+ let runningAction = false;
106
107
  const state = createFileViewerZoomState();
108
+ const notifyChange = () => {
109
+ onChange === null || onChange === void 0 ? void 0 : onChange(cloneFileViewerZoomState(state));
110
+ };
107
111
  const clearProvider = () => {
108
112
  unsubscribe === null || unsubscribe === void 0 ? void 0 : unsubscribe();
109
113
  unsubscribe = null;
@@ -122,6 +126,9 @@ export const createFileViewerZoomController = ({ root, enabled, beforeZoom, }) =
122
126
  provider = nextProvider;
123
127
  unsubscribe = ((_a = nextProvider === null || nextProvider === void 0 ? void 0 : nextProvider.subscribe) === null || _a === void 0 ? void 0 : _a.call(nextProvider, () => {
124
128
  applyFileViewerZoomState(state, nextProvider.getState());
129
+ if (!runningAction) {
130
+ notifyChange();
131
+ }
125
132
  })) || null;
126
133
  }
127
134
  applyFileViewerZoomState(state, ((_b = nextProvider === null || nextProvider === void 0 ? void 0 : nextProvider.getState) === null || _b === void 0 ? void 0 : _b.call(nextProvider)) || null);
@@ -139,9 +146,15 @@ export const createFileViewerZoomController = ({ root, enabled, beforeZoom, }) =
139
146
  if (beforeZoom && await beforeZoom(operation) === false) {
140
147
  return cloneFileViewerZoomState(state);
141
148
  }
142
- const nextState = await action(nextProvider);
143
- applyFileViewerZoomState(state, nextState || nextProvider.getState());
144
- return cloneFileViewerZoomState(state);
149
+ runningAction = true;
150
+ try {
151
+ const nextState = await action(nextProvider);
152
+ applyFileViewerZoomState(state, nextState || nextProvider.getState());
153
+ return cloneFileViewerZoomState(state);
154
+ }
155
+ finally {
156
+ runningAction = false;
157
+ }
145
158
  };
146
159
  return {
147
160
  get provider() {
@@ -1,6 +1,6 @@
1
1
  export { DEFAULT_FILE_VIEWER_ARCHIVE_WORKER_PATH, DEFAULT_FILE_VIEWER_ARCHIVE_WASM_PATH, DEFAULT_FILE_VIEWER_CAD_DWF_WASM_PATH, DEFAULT_FILE_VIEWER_CAD_WASM_PATH, DEFAULT_FILE_VIEWER_CAD_WORKER_PATH, DEFAULT_FILE_VIEWER_DATA_SQL_WASM_URL, DEFAULT_FILE_VIEWER_DOCX_WORKER_JSZIP_PATH, DEFAULT_FILE_VIEWER_DOCX_WORKER_PATH, DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS, DEFAULT_FILE_VIEWER_SPREADSHEET_WORKER_PATH, DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_URL, DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_PACKAGE_PATH, DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL, getFileViewerRendererAssetManifest, listFileViewerRendererAssetManifests, resolveFileViewerArchiveWasmUrl, resolveFileViewerArchiveWorkerUrl, resolveFileViewerAssetUrl, resolveFileViewerCadAssetUrls, resolveFileViewerDataSqlWasmUrl, resolveFileViewerDocxWorkerJsZipUrl, resolveFileViewerDocxWorkerUrl, resolveFileViewerDrawioViewerScriptUrl, resolveFileViewerRendererAssets, resolveFileViewerSpreadsheetWorkerUrl, resolveFileViewerTypstCompilerWasmUrl, resolveFileViewerTypstRendererWasmUrl, } from './assets';
2
2
  export type { FileViewerRendererAssetDefinition, FileViewerRendererAssetKind, FileViewerRendererAssetManifest, FileViewerRendererAssetOptionPath, FileViewerRendererAssetTarget, ResolveFileViewerAssetUrlOptions, ResolveFileViewerRendererAssetsOptions, ResolvedFileViewerCadAssetUrls, ResolvedFileViewerRendererAsset, } from './assets';
3
- export { ADAPTER_PRINT_REQUIRED_EXTENSIONS, createUnsupportedAvailability, DEFAULT_OPERATION_AVAILABILITY, DOM_PRINTABLE_EXTENSIONS, getRendererAvailability, isDomPrintableExtension, isKnownNonPrintableExtension, needsDedicatedPrintAdapter, NON_PRINTABLE_EXTENSIONS, resolvePrintAvailability, } from './registry/capabilities';
3
+ export { ADAPTER_PRINT_REQUIRED_EXTENSIONS, applyFileViewerZoomAvailability, createUnsupportedAvailability, DEFAULT_OPERATION_AVAILABILITY, DOM_PRINTABLE_EXTENSIONS, getRendererAvailability, isDomPrintableExtension, isKnownNonPrintableExtension, needsDedicatedPrintAdapter, NON_PRINTABLE_EXTENSIONS, resolvePrintAvailability, } from './registry/capabilities';
4
4
  export { DEFAULT_FILE_VIEWER_TEXT_CHUNK_OVERLAP, DEFAULT_FILE_VIEWER_TEXT_CHUNK_SIZE, DEFAULT_FILE_VIEWER_ZOOM_SCALE, buildFileViewerDocumentTextChunks, createEmptyFileViewerSearchState, createFileViewerZoomState, normalizeFileViewerAiOptions, normalizeFileViewerSearchOptions, } from './features/document/model';
5
5
  export { ARCHIVE_EXTENSIONS, DEFAULT_RENDERER_DEFINITIONS, DEFAULT_SUPPORTED_EXTENSIONS, IMAGE_EXTENSIONS, MODEL_EXTENSIONS, TEXT_EXTENSIONS, } from './registry/formats';
6
6
  export { FILE_VIEWER_BEFORE_OPERATION_ERROR_PREFIX, FILE_VIEWER_LIFECYCLE_HOOK_ERROR_MESSAGE_PREFIX, FILE_VIEWER_LIFECYCLE_HOOKS, FILE_VIEWER_OPERATION_LABELS, buildFileViewerLifecycleContext, buildFileViewerLifecycleContextFromNormalizedSource, buildFileViewerOperationContext, buildFileViewerOperationContextFromLifecycleState, cloneFileViewerOperationAvailability, createFileViewerLifecycleActions, createFileViewerLifecycleStateController, createFileViewerPublicApi, createFileViewerToolbarActions, createFileViewerToolbarControllerActionHandlers, createFileViewerToolbarZoomSyncSnapshot, DEFAULT_FILE_VIEWER_LIFECYCLE_HOOK_ERROR_LOGGER, DEFAULT_FILE_VIEWER_OPERATION_ERROR_LOGGER, dispatchFileViewerLifecycleEvent, dispatchFileViewerOperationAvailabilityChange, dispatchFileViewerOperationContextEvent, dispatchFileViewerZoomChange, emitFileViewerComponentLifecycleEvent, getFileViewerBeforeOperationHooks, getFileViewerLifecycleHookName, hasVisibleFileViewerToolbarActions, isFileViewerToolbarOperationPermitted, isFileViewerZoomButtonDisabled, normalizeFileViewerToolbar, reportFileViewerLifecycleHookError, reportFileViewerOperationError, resolveFileViewerBeforeOperationErrorMessage, resolveFileViewerLifecycleFallbackSource, resolveFileViewerLifecycleHookErrorMessage, resolveFileViewerOperationAvailability, resolveFileViewerToolbarPosition, resolveFileViewerToolbarState, resolveVisibleFileViewerToolbar, runFileViewerActiveUnloadComplete, runFileViewerActiveUnloadStart, runFileViewerBeforeOperation, runFileViewerLifecycleHook, runFileViewerToolbarAvailabilitySync, runFileViewerToolbarZoomSync, serializeFileViewerContext, } from './lifecycle/operations';
@@ -24,4 +24,4 @@ export { DEFAULT_FILE_VIEWER_STATE_THEME, DEFAULT_FILE_VIEWER_UNSUPPORTED_DESCRI
24
24
  export type { FileViewerErrorMessageFormatter, } from './viewer/state';
25
25
  export { buildFileViewerWatermarkBackgroundImage, buildFileViewerWatermarkInlineStyle, buildFileViewerWatermarkStyle, buildFileViewerWatermarkSvg, normalizeFileViewerWatermark, resolveFileViewerWatermarkPresentationState, } from './features/watermark';
26
26
  export type { FileViewerWatermarkPresentationState, FileViewerWatermarkStyle, } from './features/watermark';
27
- export type { FileRenderContext, FileRenderExportAdapter, FileRenderExportMode, FileRenderExportOptions, FileRenderHandler, FileRenderHandlerComposite, FileViewerBuiltinRendererPreset, FileViewerAiOptions, FileViewerArchiveOptions, FileViewerBeforeOperation, FileViewerCadDwfLineWeightMode, FileViewerCadOptions, FileViewerCadRenderer, FileViewerComponentEmits, FileViewerComponentEventMap, FileViewerComponentProps, FileViewerDocumentAnchor, FileViewerDocumentChunk, FileViewerDocxOptions, FileViewerDrawingOptions, FileViewerDownloadOptions, FileViewerEvent, FileViewerEventHandler, FileViewerEventType, FileViewerExportHtmlOptions, FileViewerFileRef, FileViewerGeoOptions, FileViewerInstance, FileViewerLifecycleContext, FileViewerLifecycleHooks, FileViewerLifecyclePhase, FileViewerI18nOptions, FileViewerLocale, FileViewerMessageKey, FileViewerMessageParams, FileViewerMessageResolver, FileViewerMessages, FileViewerOperationAvailability, FileViewerOperationContext, FileViewerOperationType, FileViewerOptions, FileViewerPdfOptions, FileViewerPrintOptions, FileViewerPublicApi, FileViewerRenderStateKind, FileViewerRenderedInstance, FileViewerRendererCategory, FileViewerSearchMatch, FileViewerSearchOptions, FileViewerSearchProvider, FileViewerSearchState, FileViewerSource, FileViewerSourceKind, FileViewerSpreadsheetOptions, FileViewerStateDescriptor, FileViewerStateTheme, FileViewerThemeMode, FileViewerToolbarActionMap, FileViewerToolbarOptions, FileViewerToolbarPosition, FileViewerTypstOptions, FileViewerWatermarkOptions, FileViewerZoomProvider, FileViewerZoomState, NormalizedFileViewerSource, RenderSurface, RendererCapability, RendererDefinition, RendererLoadContext, RendererLoader, RendererPlugin, RendererRegistry, RendererSession, ViewerCapabilityState, ViewerLifecycleContext, ViewerOperationContext, } from './contracts/types';
27
+ export type { FileRenderContext, FileRenderExportAdapter, FileRenderExportMode, FileRenderExportOptions, FileRenderHandler, FileRenderHandlerComposite, FileViewerBuiltinRendererPreset, FileViewerAiOptions, FileViewerArchiveOptions, FileViewerApplyViewStateOptions, FileViewerBeforeOperation, FileViewerCadDwfLineWeightMode, FileViewerCadOptions, FileViewerCadRenderer, FileViewerComponentEmits, FileViewerComponentEventMap, FileViewerComponentProps, FileViewerDocumentAnchor, FileViewerDocumentChunk, FileViewerDocxOptions, FileViewerDrawingOptions, FileViewerDownloadOptions, FileViewerEvent, FileViewerEventHandler, FileViewerEventType, FileViewerExportHtmlOptions, FileViewerFileRef, FileViewerGeoOptions, FileViewerInstance, FileViewerLifecycleContext, FileViewerLifecycleHooks, FileViewerLifecyclePhase, FileViewerI18nOptions, FileViewerLocale, FileViewerMessageKey, FileViewerMessageParams, FileViewerMessageResolver, FileViewerMessages, FileViewerNavigationState, FileViewerOperationAvailability, FileViewerOperationContext, FileViewerOperationType, FileViewerOptions, FileViewerPdfOptions, FileViewerPresentationOptions, FileViewerPrintOptions, FileViewerPublicApi, FileViewerRenderStateKind, FileViewerRenderedInstance, FileViewerRendererCategory, FileViewerSearchMatch, FileViewerSearchOptions, FileViewerSearchProvider, FileViewerSearchState, FileViewerSource, FileViewerSourceKind, FileViewerSpreadsheetOptions, FileViewerStateDescriptor, FileViewerStateTheme, FileViewerThemeMode, FileViewerToolbarActionMap, FileViewerToolbarOptions, FileViewerToolbarPosition, FileViewerTypstOptions, FileViewerViewScrollState, FileViewerViewState, FileViewerViewStateChange, FileViewerViewStateChangeAction, FileViewerViewStateChangeSource, FileViewerViewStateProvider, FileViewerWatermarkOptions, FileViewerZoomProvider, FileViewerZoomState, NormalizedFileViewerSource, RenderSurface, RendererCapability, RendererDefinition, RendererLoadContext, RendererLoader, RendererPlugin, RendererRegistry, RendererSession, ViewerCapabilityState, ViewerLifecycleContext, ViewerOperationContext, } from './contracts/types';