@rhc-office/sdk 6.6.256

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 (126) hide show
  1. package/README.md +176 -0
  2. package/dist/api/annotation-tool.d.ts +127 -0
  3. package/dist/api/annotation-tool.d.ts.map +1 -0
  4. package/dist/api/callbacks.d.ts +25 -0
  5. package/dist/api/callbacks.d.ts.map +1 -0
  6. package/dist/api/common.d.ts +83 -0
  7. package/dist/api/common.d.ts.map +1 -0
  8. package/dist/api/crypto-tool.d.ts +9 -0
  9. package/dist/api/crypto-tool.d.ts.map +1 -0
  10. package/dist/api/digital-sign-environment.d.ts +100 -0
  11. package/dist/api/digital-sign-environment.d.ts.map +1 -0
  12. package/dist/api/document-sdk.d.ts +111 -0
  13. package/dist/api/document-sdk.d.ts.map +1 -0
  14. package/dist/api/document-tool.d.ts +68 -0
  15. package/dist/api/document-tool.d.ts.map +1 -0
  16. package/dist/api/ekey-tool.d.ts +8 -0
  17. package/dist/api/ekey-tool.d.ts.map +1 -0
  18. package/dist/api/extension-tool.d.ts +5 -0
  19. package/dist/api/extension-tool.d.ts.map +1 -0
  20. package/dist/api/find-tool.d.ts +6 -0
  21. package/dist/api/find-tool.d.ts.map +1 -0
  22. package/dist/api/menu-visibility.d.ts +16 -0
  23. package/dist/api/menu-visibility.d.ts.map +1 -0
  24. package/dist/api/networking-tool.d.ts +7 -0
  25. package/dist/api/networking-tool.d.ts.map +1 -0
  26. package/dist/api/page-tool.d.ts +28 -0
  27. package/dist/api/page-tool.d.ts.map +1 -0
  28. package/dist/api/pdf-formfiller.d.ts +12 -0
  29. package/dist/api/pdf-formfiller.d.ts.map +1 -0
  30. package/dist/api/review-tool.d.ts +71 -0
  31. package/dist/api/review-tool.d.ts.map +1 -0
  32. package/dist/api/sign-server.d.ts +32 -0
  33. package/dist/api/sign-server.d.ts.map +1 -0
  34. package/dist/api/sign-tool.d.ts +31 -0
  35. package/dist/api/sign-tool.d.ts.map +1 -0
  36. package/dist/api/symbology-tool.d.ts +4 -0
  37. package/dist/api/symbology-tool.d.ts.map +1 -0
  38. package/dist/api/template-sign.d.ts +88 -0
  39. package/dist/api/template-sign.d.ts.map +1 -0
  40. package/dist/api/ui-tool.d.ts +35 -0
  41. package/dist/api/ui-tool.d.ts.map +1 -0
  42. package/dist/api/watermark.d.ts +25 -0
  43. package/dist/api/watermark.d.ts.map +1 -0
  44. package/dist/index.d.ts +23 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +1061 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/index.umd.cjs +2 -0
  49. package/dist/index.umd.cjs.map +1 -0
  50. package/dist/tools/DocumentToolImpl.d.ts +27 -0
  51. package/dist/tools/DocumentToolImpl.d.ts.map +1 -0
  52. package/dist/tools/FindToolImpl.d.ts +10 -0
  53. package/dist/tools/FindToolImpl.d.ts.map +1 -0
  54. package/dist/tools/NetworkingToolImpl.d.ts +10 -0
  55. package/dist/tools/NetworkingToolImpl.d.ts.map +1 -0
  56. package/dist/tools/PageToolImpl.d.ts +31 -0
  57. package/dist/tools/PageToolImpl.d.ts.map +1 -0
  58. package/dist/tools/PdfFormFillerImpl.d.ts +13 -0
  59. package/dist/tools/PdfFormFillerImpl.d.ts.map +1 -0
  60. package/dist/tools/Phase1ToolPlaceholder.d.ts +5 -0
  61. package/dist/tools/Phase1ToolPlaceholder.d.ts.map +1 -0
  62. package/dist/tools/SDKValueObjects.d.ts +55 -0
  63. package/dist/tools/SDKValueObjects.d.ts.map +1 -0
  64. package/dist/tools/UIToolImpl.d.ts +31 -0
  65. package/dist/tools/UIToolImpl.d.ts.map +1 -0
  66. package/dist/tools/index.d.ts +9 -0
  67. package/dist/tools/index.d.ts.map +1 -0
  68. package/dist/viewer/AdapterProtocol.d.ts +78 -0
  69. package/dist/viewer/AdapterProtocol.d.ts.map +1 -0
  70. package/dist/viewer/BridgeToolAdapter.d.ts +23 -0
  71. package/dist/viewer/BridgeToolAdapter.d.ts.map +1 -0
  72. package/dist/viewer/DocumentSDK.d.ts +85 -0
  73. package/dist/viewer/DocumentSDK.d.ts.map +1 -0
  74. package/dist/viewer/ReaderBridgeClient.d.ts +31 -0
  75. package/dist/viewer/ReaderBridgeClient.d.ts.map +1 -0
  76. package/dist/viewer/ReaderConfiguration.d.ts +11 -0
  77. package/dist/viewer/ReaderConfiguration.d.ts.map +1 -0
  78. package/dist/viewer/ReaderScriptLoader.d.ts +10 -0
  79. package/dist/viewer/ReaderScriptLoader.d.ts.map +1 -0
  80. package/dist/viewer/ReaderStateStore.d.ts +21 -0
  81. package/dist/viewer/ReaderStateStore.d.ts.map +1 -0
  82. package/dist/viewer/SdkCallbackRegistry.d.ts +18 -0
  83. package/dist/viewer/SdkCallbackRegistry.d.ts.map +1 -0
  84. package/dist/viewer/index.d.ts +2 -0
  85. package/dist/viewer/index.d.ts.map +1 -0
  86. package/package.json +48 -0
  87. package/src/api/annotation-tool.ts +199 -0
  88. package/src/api/callbacks.ts +59 -0
  89. package/src/api/common.ts +117 -0
  90. package/src/api/crypto-tool.ts +10 -0
  91. package/src/api/digital-sign-environment.ts +411 -0
  92. package/src/api/document-sdk.ts +152 -0
  93. package/src/api/document-tool.ts +106 -0
  94. package/src/api/ekey-tool.ts +11 -0
  95. package/src/api/extension-tool.ts +5 -0
  96. package/src/api/find-tool.ts +7 -0
  97. package/src/api/menu-visibility.ts +17 -0
  98. package/src/api/networking-tool.ts +9 -0
  99. package/src/api/page-tool.ts +56 -0
  100. package/src/api/pdf-formfiller.ts +13 -0
  101. package/src/api/review-tool.ts +105 -0
  102. package/src/api/sign-server.ts +53 -0
  103. package/src/api/sign-tool.ts +50 -0
  104. package/src/api/symbology-tool.ts +11 -0
  105. package/src/api/template-sign.ts +102 -0
  106. package/src/api/ui-tool.ts +66 -0
  107. package/src/api/watermark.ts +35 -0
  108. package/src/index.ts +22 -0
  109. package/src/tools/DocumentToolImpl.ts +158 -0
  110. package/src/tools/FindToolImpl.ts +32 -0
  111. package/src/tools/NetworkingToolImpl.ts +36 -0
  112. package/src/tools/PageToolImpl.ts +181 -0
  113. package/src/tools/PdfFormFillerImpl.ts +67 -0
  114. package/src/tools/Phase1ToolPlaceholder.ts +35 -0
  115. package/src/tools/SDKValueObjects.ts +172 -0
  116. package/src/tools/UIToolImpl.ts +145 -0
  117. package/src/tools/index.ts +8 -0
  118. package/src/viewer/AdapterProtocol.ts +114 -0
  119. package/src/viewer/BridgeToolAdapter.ts +137 -0
  120. package/src/viewer/DocumentSDK.ts +688 -0
  121. package/src/viewer/ReaderBridgeClient.ts +216 -0
  122. package/src/viewer/ReaderConfiguration.ts +59 -0
  123. package/src/viewer/ReaderScriptLoader.ts +130 -0
  124. package/src/viewer/ReaderStateStore.ts +55 -0
  125. package/src/viewer/SdkCallbackRegistry.ts +89 -0
  126. package/src/viewer/index.ts +1 -0
@@ -0,0 +1,688 @@
1
+ import type { AnnotationTool } from '../api/annotation-tool';
2
+ import type { IDigitalAnnotationInfo } from '../api/annotation-tool';
3
+ import type { CryptoTool } from '../api/crypto-tool';
4
+ import type {
5
+ AnnotationEventCallback,
6
+ ExtensionStateChangedCallback,
7
+ ReaderReadyCallback,
8
+ ReaderUnloadCallback,
9
+ } from '../api/callbacks';
10
+ import type { IDocumentSDK, IReaderEmbedOptions } from '../api/document-sdk';
11
+ import type { DocumentTool } from '../api/document-tool';
12
+ import type { EkeyTool } from '../api/ekey-tool';
13
+ import type { ExtensionTool } from '../api/extension-tool';
14
+ import type { FindTool } from '../api/find-tool';
15
+ import type { NetworkingTool } from '../api/networking-tool';
16
+ import type { PageTool } from '../api/page-tool';
17
+ import type { PdfFormFiller } from '../api/pdf-formfiller';
18
+ import type { ReviewTool } from '../api/review-tool';
19
+ import type { SignServerTool } from '../api/sign-server';
20
+ import type { DigitalSignTool } from '../api/sign-tool';
21
+ import type { SymbologyTool } from '../api/symbology-tool';
22
+ import type { TemplateSignTool } from '../api/template-sign';
23
+ import type { UITool } from '../api/ui-tool';
24
+ import { DocumentToolImpl } from '../tools/DocumentToolImpl';
25
+ import { FindToolImpl } from '../tools/FindToolImpl';
26
+ import { NetworkingToolImpl } from '../tools/NetworkingToolImpl';
27
+ import { PageToolImpl } from '../tools/PageToolImpl';
28
+ import { PdfFormFillerImpl } from '../tools/PdfFormFillerImpl';
29
+ import { DigitalSignOptions, KVField } from '../tools/SDKValueObjects';
30
+ import { UIToolImpl } from '../tools/UIToolImpl';
31
+ import type { NormalizedReaderEmbedOptions } from './ReaderConfiguration';
32
+ import { normalizeAppUrl, normalizeReaderEmbedOptions } from './ReaderConfiguration';
33
+ import {
34
+ assertCompatibleReaderSource,
35
+ ensureReaderScriptLoaded,
36
+ READER_CUSTOM_ELEMENT_TAG,
37
+ } from './ReaderScriptLoader';
38
+ import {
39
+ RHC_OFFICE_ADAPTER_EVENT,
40
+ RHC_OFFICE_READER_ID_ATTRIBUTE,
41
+ type AdapterEvent,
42
+ } from './AdapterProtocol';
43
+ import { createBridgeToolAdapter, createNotImplementedBridgeTool } from './BridgeToolAdapter';
44
+ import { ReaderBridgeClient } from './ReaderBridgeClient';
45
+ import { ReaderStateStore } from './ReaderStateStore';
46
+ import { SdkCallbackRegistry } from './SdkCallbackRegistry';
47
+
48
+ type ReaderEventListener = Parameters<IDocumentSDK['setReaderEventListener']>[0];
49
+ type ReaderEventPayload = Parameters<NonNullable<ReaderEventListener>>[1];
50
+
51
+ interface DocumentSDKRuntimeOptions {
52
+ adapterReadyTimeoutMs?: number;
53
+ adapterRequestTimeoutMs?: number;
54
+ }
55
+
56
+ type NativeReaderEventName = 'documentLoaded' | 'documentStateChange' | 'documentError';
57
+ type ReaderThemeCleanup = () => void;
58
+ type CompatibleMediaQueryList = MediaQueryList & {
59
+ addListener?: (listener: (event: MediaQueryListEvent) => void) => void;
60
+ removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;
61
+ };
62
+
63
+ const NATIVE_READER_EVENT_NAMES: NativeReaderEventName[] = [
64
+ 'documentLoaded',
65
+ 'documentStateChange',
66
+ 'documentError',
67
+ ];
68
+
69
+ const READER_READY_EVENT_NAME = 'readerReady';
70
+ const READER_UNLOAD_EVENT_NAME = 'readerUnload';
71
+ const READER_ERROR_EVENT_NAME = 'readerError';
72
+
73
+ const createReaderId = (): string => {
74
+ if (typeof globalThis.crypto?.randomUUID === 'function') {
75
+ return globalThis.crypto.randomUUID();
76
+ }
77
+
78
+ return `rhc-reader-${Date.now()}-${Math.random().toString(36).slice(2)}`;
79
+ };
80
+
81
+ const createReaderPayload = (
82
+ readerElement: HTMLElement | null,
83
+ configuration: NormalizedReaderEmbedOptions | null,
84
+ ): Record<string, unknown> => {
85
+ return {
86
+ appUrl: configuration?.officeServer ?? null,
87
+ configuration,
88
+ element: readerElement,
89
+ };
90
+ };
91
+
92
+ const resolveContainerElement = (container: string | HTMLDivElement): HTMLDivElement => {
93
+ if (typeof container === 'string') {
94
+ const element = document.getElementById(container);
95
+ if (!element) {
96
+ throw new Error(`Reader container "${container}" was not found.`);
97
+ }
98
+
99
+ if (!(element instanceof HTMLDivElement)) {
100
+ throw new Error(`Reader container "${container}" must be a div element.`);
101
+ }
102
+
103
+ return element;
104
+ }
105
+
106
+ if (!(container instanceof HTMLDivElement)) {
107
+ throw new Error('Reader container must be a div element.');
108
+ }
109
+
110
+ return container;
111
+ };
112
+
113
+ const resolveSystemReaderTheme = (): 'light' | 'dark' | 'high-contrast' => {
114
+ const supportsMatchMedia = typeof globalThis.matchMedia === 'function';
115
+ const prefersHighContrast = supportsMatchMedia
116
+ ? globalThis.matchMedia('(prefers-contrast: more)').matches
117
+ : false;
118
+ if (prefersHighContrast) {
119
+ return 'high-contrast';
120
+ }
121
+
122
+ const prefersDark = supportsMatchMedia
123
+ ? globalThis.matchMedia('(prefers-color-scheme: dark)').matches
124
+ : false;
125
+ return prefersDark ? 'dark' : 'light';
126
+ };
127
+
128
+ const addMediaQueryListener = (
129
+ mediaQuery: MediaQueryList,
130
+ listener: (event: MediaQueryListEvent) => void,
131
+ ): void => {
132
+ const compatibleMediaQuery = mediaQuery as CompatibleMediaQueryList;
133
+ if (typeof compatibleMediaQuery.addEventListener === 'function') {
134
+ compatibleMediaQuery.addEventListener('change', listener);
135
+ return;
136
+ }
137
+
138
+ if (typeof compatibleMediaQuery.addListener === 'function') {
139
+ compatibleMediaQuery.addListener(listener);
140
+ }
141
+ };
142
+
143
+ const removeMediaQueryListener = (
144
+ mediaQuery: MediaQueryList,
145
+ listener: (event: MediaQueryListEvent) => void,
146
+ ): void => {
147
+ const compatibleMediaQuery = mediaQuery as CompatibleMediaQueryList;
148
+ if (typeof compatibleMediaQuery.removeEventListener === 'function') {
149
+ compatibleMediaQuery.removeEventListener('change', listener);
150
+ return;
151
+ }
152
+
153
+ if (typeof compatibleMediaQuery.removeListener === 'function') {
154
+ compatibleMediaQuery.removeListener(listener);
155
+ }
156
+ };
157
+
158
+ const applyReaderElementLayout = (
159
+ readerElement: HTMLElement,
160
+ configuration: NormalizedReaderEmbedOptions,
161
+ ): void => {
162
+ if (configuration.style) {
163
+ readerElement.style.cssText = configuration.style;
164
+ }
165
+
166
+ if (!readerElement.style.display) {
167
+ readerElement.style.display = 'block';
168
+ }
169
+
170
+ if (!readerElement.style.width) {
171
+ readerElement.style.width = configuration.width ?? '100%';
172
+ } else if (configuration.width) {
173
+ readerElement.style.width = configuration.width;
174
+ }
175
+
176
+ if (!readerElement.style.height) {
177
+ readerElement.style.height = configuration.height ?? '100%';
178
+ } else if (configuration.height) {
179
+ readerElement.style.height = configuration.height;
180
+ }
181
+ };
182
+
183
+ const bindReaderElementTheme = (
184
+ readerElement: HTMLElement,
185
+ configuration: NormalizedReaderEmbedOptions,
186
+ ): ReaderThemeCleanup | null => {
187
+ const configuredTheme = configuration.theme;
188
+ if (!configuredTheme) {
189
+ readerElement.removeAttribute('theme');
190
+ return null;
191
+ }
192
+
193
+ if (configuredTheme !== 'auto') {
194
+ readerElement.setAttribute('theme', configuredTheme);
195
+ return null;
196
+ }
197
+
198
+ const applySystemTheme = (): void => {
199
+ readerElement.setAttribute('theme', resolveSystemReaderTheme());
200
+ };
201
+
202
+ applySystemTheme();
203
+
204
+ if (typeof globalThis.matchMedia !== 'function') {
205
+ return null;
206
+ }
207
+
208
+ const colorSchemeMediaQuery = globalThis.matchMedia('(prefers-color-scheme: dark)');
209
+ const contrastMediaQuery = globalThis.matchMedia('(prefers-contrast: more)');
210
+ const handleThemeChange = (): void => {
211
+ applySystemTheme();
212
+ };
213
+
214
+ addMediaQueryListener(colorSchemeMediaQuery, handleThemeChange);
215
+ addMediaQueryListener(contrastMediaQuery, handleThemeChange);
216
+
217
+ return () => {
218
+ removeMediaQueryListener(colorSchemeMediaQuery, handleThemeChange);
219
+ removeMediaQueryListener(contrastMediaQuery, handleThemeChange);
220
+ };
221
+ };
222
+
223
+ export class DocumentSDK implements IDocumentSDK {
224
+ private readonly bridge = new ReaderBridgeClient();
225
+ private readonly callbacks = new SdkCallbackRegistry();
226
+ private readonly readerState = new ReaderStateStore();
227
+ private readonly bridgeToolContext = {
228
+ bridge: this.bridge,
229
+ callbacks: this.callbacks,
230
+ debug: () => this.debugEnabled,
231
+ onAsyncError: (error: unknown) => this.reportAdapterError(error),
232
+ state: this.readerState,
233
+ };
234
+ private readonly documentTool = new DocumentToolImpl(this.bridgeToolContext);
235
+ private readonly uiTool = new UIToolImpl(this.bridgeToolContext);
236
+ private readonly pageTool = new PageToolImpl(this.bridgeToolContext);
237
+ private readonly findTool = new FindToolImpl(this.bridgeToolContext);
238
+ private readonly signServerTool = createNotImplementedBridgeTool<SignServerTool>(
239
+ 'signServer',
240
+ this.bridgeToolContext,
241
+ );
242
+ private readonly digitalSignTool = createNotImplementedBridgeTool<DigitalSignTool>(
243
+ 'digitalSign',
244
+ this.bridgeToolContext,
245
+ );
246
+ private readonly reviewTool = createNotImplementedBridgeTool<ReviewTool>(
247
+ 'review',
248
+ this.bridgeToolContext,
249
+ );
250
+ private readonly ekeyTool = createNotImplementedBridgeTool<EkeyTool>(
251
+ 'ekey',
252
+ this.bridgeToolContext,
253
+ );
254
+ private readonly symbologyTool = createNotImplementedBridgeTool<SymbologyTool>(
255
+ 'symbology',
256
+ this.bridgeToolContext,
257
+ );
258
+ private readonly annotationTool = this.createAnnotationTool();
259
+ private readonly templateSignTool = createNotImplementedBridgeTool<TemplateSignTool>(
260
+ 'templateSign',
261
+ this.bridgeToolContext,
262
+ );
263
+ private readonly pdfFormFiller = new PdfFormFillerImpl(this.bridgeToolContext);
264
+ private readonly extensionTool = this.createExtensionTool();
265
+ private readonly networkingTool = new NetworkingToolImpl(this.bridgeToolContext);
266
+ private readonly cryptoTool = createNotImplementedBridgeTool<CryptoTool>(
267
+ 'crypto',
268
+ this.bridgeToolContext,
269
+ );
270
+
271
+ private readonly readyCallbacks: ReaderReadyCallback[] = [];
272
+ private readonly unloadCallbacks: ReaderUnloadCallback[] = [];
273
+
274
+ private debugEnabled = false;
275
+ private isReady = false;
276
+ private removed = false;
277
+ private mountToken = 0;
278
+
279
+ private readerEventListener?: ReaderEventListener;
280
+ private hostContainer: HTMLDivElement | null = null;
281
+ private readerElement: HTMLElement | null = null;
282
+ private readerId: string | null = null;
283
+ private normalizedConfiguration: NormalizedReaderEmbedOptions | null = null;
284
+ private sessionUser?: Parameters<IDocumentSDK['setSessionUser']>[0];
285
+ private sessionData?: string;
286
+ private license?: { license: string; feature: string };
287
+ private readonly nativeEventCleanupCallbacks: Array<() => void> = [];
288
+ private themeCleanup: ReaderThemeCleanup | null = null;
289
+
290
+ constructor(options?: DocumentSDKRuntimeOptions) {
291
+ this.bridge.configureTimeouts({
292
+ readyTimeoutMs: options?.adapterReadyTimeoutMs,
293
+ requestTimeoutMs: options?.adapterRequestTimeoutMs,
294
+ });
295
+ }
296
+
297
+ readonly enableDebug: IDocumentSDK['enableDebug'] = (debug): void => {
298
+ this.debugEnabled = debug;
299
+ };
300
+
301
+ readonly changeLanguage: IDocumentSDK['changeLanguage'] = (): void => {
302
+ // Phase 1: reserved for future reader language bridging.
303
+ };
304
+
305
+ readonly setLicense: IDocumentSDK['setLicense'] = (license, feature): void => {
306
+ this.license = { license, feature };
307
+ };
308
+
309
+ readonly setSessionUser: IDocumentSDK['setSessionUser'] = (userNameOrInfo): void => {
310
+ this.sessionUser = userNameOrInfo;
311
+ };
312
+
313
+ readonly setSessionUserId: IDocumentSDK['setSessionUserId'] = (userId): void => {
314
+ if (typeof this.sessionUser === 'string' || !this.sessionUser) {
315
+ this.sessionUser = {
316
+ userName: typeof this.sessionUser === 'string' ? this.sessionUser : '',
317
+ userId,
318
+ };
319
+ return;
320
+ }
321
+
322
+ this.sessionUser = {
323
+ ...this.sessionUser,
324
+ userId,
325
+ };
326
+ };
327
+
328
+ readonly setSessionData: IDocumentSDK['setSessionData'] = (sessionData): void => {
329
+ this.sessionData = sessionData;
330
+ };
331
+
332
+ readonly isReaderReady: IDocumentSDK['isReaderReady'] = (): boolean => {
333
+ return this.isReady;
334
+ };
335
+
336
+ readonly isReaderDestroyed: IDocumentSDK['isReaderDestroyed'] = (): boolean => {
337
+ return this.removed && !this.isReady;
338
+ };
339
+
340
+ readonly addReaderReadyCallback: IDocumentSDK['addReaderReadyCallback'] = (callback): void => {
341
+ this.readyCallbacks.push(callback);
342
+ };
343
+
344
+ readonly addReaderUnloadCallback: IDocumentSDK['addReaderUnloadCallback'] = (callback): void => {
345
+ this.unloadCallbacks.push(callback);
346
+ };
347
+
348
+ readonly setReaderEventListener: IDocumentSDK['setReaderEventListener'] = (callback): void => {
349
+ this.readerEventListener = callback;
350
+ };
351
+
352
+ readonly embedReader: IDocumentSDK['embedReader'] = (container, appUrl, configuration): void => {
353
+ const hostContainer = resolveContainerElement(container);
354
+ const normalizedAppUrl = normalizeAppUrl(appUrl);
355
+ assertCompatibleReaderSource(normalizedAppUrl);
356
+
357
+ const normalizedConfiguration = normalizeReaderEmbedOptions(normalizedAppUrl, configuration);
358
+ const mountToken = this.mountToken + 1;
359
+
360
+ this.removeReader();
361
+
362
+ this.mountToken = mountToken;
363
+ this.removed = false;
364
+ this.hostContainer = hostContainer;
365
+ this.normalizedConfiguration = normalizedConfiguration;
366
+
367
+ void this.mountReader(hostContainer, normalizedConfiguration, mountToken);
368
+ };
369
+
370
+ readonly removeReader: IDocumentSDK['removeReader'] = (): void => {
371
+ const hadMountedReader = Boolean(this.readerElement || this.hostContainer);
372
+
373
+ this.mountToken += 1;
374
+ this.cleanupNativeEventForwarders();
375
+ this.cleanupThemeBinding();
376
+
377
+ if (this.readerElement?.parentNode) {
378
+ this.readerElement.parentNode.removeChild(this.readerElement);
379
+ }
380
+
381
+ this.readerElement = null;
382
+ this.readerId = null;
383
+ this.bridge.setReaderId(null);
384
+ this.readerState.reset();
385
+ this.hostContainer = null;
386
+ this.normalizedConfiguration = null;
387
+ this.isReady = false;
388
+ this.removed = true;
389
+
390
+ if (!hadMountedReader) {
391
+ return;
392
+ }
393
+
394
+ const payload = createReaderPayload(null, null);
395
+ this.emitReaderEvent(READER_UNLOAD_EVENT_NAME, payload);
396
+ this.unloadCallbacks.forEach((callback) => callback());
397
+ };
398
+
399
+ readonly getDocumentTool: IDocumentSDK['getDocumentTool'] = (): DocumentTool => {
400
+ return this.documentTool;
401
+ };
402
+
403
+ readonly getUITool: IDocumentSDK['getUITool'] = (): UITool => {
404
+ return this.uiTool;
405
+ };
406
+
407
+ readonly getPageTool: IDocumentSDK['getPageTool'] = (): PageTool => {
408
+ return this.pageTool;
409
+ };
410
+
411
+ readonly getFindTool: IDocumentSDK['getFindTool'] = (): FindTool => {
412
+ return this.findTool;
413
+ };
414
+
415
+ readonly getSignServerTool: IDocumentSDK['getSignServerTool'] = (): SignServerTool => {
416
+ return this.signServerTool;
417
+ };
418
+
419
+ readonly getDigitalSignTool: IDocumentSDK['getDigitalSignTool'] = (): DigitalSignTool => {
420
+ return this.digitalSignTool;
421
+ };
422
+
423
+ readonly getReviewTool: IDocumentSDK['getReviewTool'] = (): ReviewTool => {
424
+ return this.reviewTool;
425
+ };
426
+
427
+ readonly getEkeyTool: IDocumentSDK['getEkeyTool'] = (): EkeyTool => {
428
+ return this.ekeyTool;
429
+ };
430
+
431
+ readonly getSymbologyTool: IDocumentSDK['getSymbologyTool'] = (): SymbologyTool => {
432
+ return this.symbologyTool;
433
+ };
434
+
435
+ readonly getAnnotationTool: IDocumentSDK['getAnnotationTool'] = (): AnnotationTool => {
436
+ return this.annotationTool;
437
+ };
438
+
439
+ readonly getTemplateSignTool: IDocumentSDK['getTemplateSignTool'] = (): TemplateSignTool => {
440
+ return this.templateSignTool;
441
+ };
442
+
443
+ readonly getPdfFormFiller: IDocumentSDK['getPdfFormFiller'] = (): PdfFormFiller => {
444
+ return this.pdfFormFiller;
445
+ };
446
+
447
+ readonly getExtensionTool: IDocumentSDK['getExtensionTool'] = (): ExtensionTool => {
448
+ return this.extensionTool;
449
+ };
450
+
451
+ readonly getNetworkingTool: IDocumentSDK['getNetworkingTool'] = (): NetworkingTool => {
452
+ return this.networkingTool;
453
+ };
454
+
455
+ readonly getCryptoTool: IDocumentSDK['getCryptoTool'] = (): CryptoTool => {
456
+ return this.cryptoTool;
457
+ };
458
+
459
+ readonly createDigitalSignOptions: IDocumentSDK['createDigitalSignOptions'] = () => {
460
+ return new DigitalSignOptions();
461
+ };
462
+
463
+ readonly createKVField: IDocumentSDK['createKVField'] = (key, value, description) => {
464
+ return new KVField(key, value, description);
465
+ };
466
+
467
+ private createAnnotationTool(): AnnotationTool {
468
+ return createBridgeToolAdapter<AnnotationTool>(
469
+ 'annotation',
470
+ {
471
+ addAnnotationEventCallback: {
472
+ kind: 'callbackRegister',
473
+ callback: (callbacks, args) => {
474
+ const callback = args[0];
475
+ if (typeof callback === 'function') {
476
+ callbacks.annotationEvents.push(callback as AnnotationEventCallback);
477
+ }
478
+ },
479
+ },
480
+ addAnnotationPersistCallback: {
481
+ kind: 'callbackRegister',
482
+ callback: (callbacks, args) => {
483
+ const callback = args[0];
484
+ if (typeof callback === 'function') {
485
+ callbacks.annotationPersist.push(callback as (event: unknown) => void);
486
+ }
487
+ },
488
+ },
489
+ addAnnotationRetrieveCallback: {
490
+ kind: 'callbackRegister',
491
+ callback: (callbacks, args) => {
492
+ const callback = args[0];
493
+ if (typeof callback === 'function') {
494
+ callbacks.annotationRetrieve.push(callback as (event: unknown) => void);
495
+ }
496
+ },
497
+ },
498
+ addDigitalAnnotationRetrieveCallback: {
499
+ kind: 'callbackRegister',
500
+ callback: (callbacks, args) => {
501
+ const callback = args[0];
502
+ if (typeof callback === 'function') {
503
+ callbacks.digitalAnnotationRetrieve.push(
504
+ callback as (annotations: IDigitalAnnotationInfo[]) => void,
505
+ );
506
+ }
507
+ },
508
+ },
509
+ isInAnnotationMode: {
510
+ kind: 'stateGetter',
511
+ state: (state) => state.annotationEnabled,
512
+ },
513
+ getAnnotations: { kind: 'stateGetter', state: () => [] },
514
+ getAnnotationsCount: { kind: 'stateGetter', state: () => 0 },
515
+ queryAnnotationsBy: { kind: 'stateGetter', state: () => [] },
516
+ setToolSource: { kind: 'command' },
517
+ openAnnotationView: { kind: 'command' },
518
+ closeAnnotationView: { kind: 'command' },
519
+ openTextAnnotationView: { kind: 'command' },
520
+ setTextAnnotationFontColor: { kind: 'command' },
521
+ setTextAnnotationFontSize: { kind: 'command' },
522
+ closeTextAnnotationView: { kind: 'command' },
523
+ createTextAnnotation: { kind: 'command' },
524
+ setPersistToDocument: { kind: 'command' },
525
+ saveAnnotations: { kind: 'callbackQuery' },
526
+ saveTextAnnotations: { kind: 'command' },
527
+ clearAnnotations: { kind: 'command' },
528
+ clearTextAnnotations: { kind: 'command' },
529
+ undoAnnotation: { kind: 'command' },
530
+ redoAnnotation: { kind: 'command' },
531
+ selectAnnotationTool: { kind: 'command' },
532
+ showAnnotationColorPicker: { kind: 'command' },
533
+ setAnnotationPenType: { kind: 'command' },
534
+ appendAnnotations: { kind: 'callbackQuery' },
535
+ batchAppendAnnotations: { kind: 'callbackQuery' },
536
+ setAnnotationPenColor: { kind: 'command' },
537
+ setAnnotationPenWidth: { kind: 'command' },
538
+ setAnnotationPenThickness: { kind: 'command' },
539
+ enableAnnotationsInfoView: { kind: 'command' },
540
+ enableAnnotationsDeletion: { kind: 'command' },
541
+ enableAnnotationsDeletionOnlyByAuthor: { kind: 'command' },
542
+ listDigitalStamps: { kind: 'command' },
543
+ listAnnotations: { kind: 'command' },
544
+ deleteAnnotationsBy: { kind: 'command' },
545
+ deleteAnnotationsById: { kind: 'command' },
546
+ addDigitalAnnotation: { kind: 'command' },
547
+ addInkAnnotationCallback: { kind: 'callbackRegister' },
548
+ },
549
+ this.bridgeToolContext,
550
+ );
551
+ }
552
+
553
+ private createExtensionTool(): ExtensionTool {
554
+ return createBridgeToolAdapter<ExtensionTool>(
555
+ 'extension',
556
+ {
557
+ addExtensionStateChangedCallback: {
558
+ kind: 'callbackRegister',
559
+ callback: (callbacks, args) => {
560
+ const callback = args[0];
561
+ if (typeof callback === 'function') {
562
+ callbacks.extensionStateChanged.push(callback as ExtensionStateChangedCallback);
563
+ }
564
+ },
565
+ },
566
+ },
567
+ this.bridgeToolContext,
568
+ );
569
+ }
570
+
571
+ private readonly mountReader = async (
572
+ hostContainer: HTMLDivElement,
573
+ configuration: NormalizedReaderEmbedOptions,
574
+ mountToken: number,
575
+ ): Promise<void> => {
576
+ try {
577
+ await ensureReaderScriptLoaded(configuration.officeServer);
578
+ if (this.mountToken !== mountToken) {
579
+ return;
580
+ }
581
+
582
+ const readerElement = document.createElement(READER_CUSTOM_ELEMENT_TAG);
583
+ const readerId = createReaderId();
584
+ readerElement.setAttribute(RHC_OFFICE_READER_ID_ATTRIBUTE, readerId);
585
+ this.readerId = readerId;
586
+ this.bridge.setReaderId(readerId);
587
+ applyReaderElementLayout(readerElement, configuration);
588
+ this.themeCleanup = bindReaderElementTheme(readerElement, configuration);
589
+ this.bindNativeReaderEvents(readerElement);
590
+
591
+ hostContainer.replaceChildren(readerElement);
592
+ this.readerElement = readerElement;
593
+ await Promise.resolve();
594
+ if (this.mountToken !== mountToken) {
595
+ return;
596
+ }
597
+
598
+ if (configuration.scrollIntoView && typeof hostContainer.scrollIntoView === 'function') {
599
+ hostContainer.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
600
+ }
601
+
602
+ this.isReady = true;
603
+ const payload = createReaderPayload(readerElement, configuration);
604
+ this.emitReaderEvent(READER_READY_EVENT_NAME, payload);
605
+ this.readyCallbacks.forEach((callback) => callback());
606
+ } catch (error: unknown) {
607
+ if (this.mountToken !== mountToken) {
608
+ return;
609
+ }
610
+
611
+ this.reportReaderError(error);
612
+ }
613
+ };
614
+
615
+ private readonly bindNativeReaderEvents = (readerElement: HTMLElement): void => {
616
+ this.cleanupNativeEventForwarders();
617
+
618
+ const adapterEventListener = (event: Event): void => {
619
+ const detail = event instanceof CustomEvent ? (event.detail as AdapterEvent) : null;
620
+ if (!detail || detail.readerId !== this.readerId) {
621
+ return;
622
+ }
623
+
624
+ this.readerState.update(detail.statePatch);
625
+ this.callbacks.emit(detail.event, detail.payload);
626
+ this.emitReaderEvent(detail.event, detail.payload as ReaderEventPayload);
627
+ };
628
+ readerElement.addEventListener(RHC_OFFICE_ADAPTER_EVENT, adapterEventListener as EventListener);
629
+ this.nativeEventCleanupCallbacks.push(() => {
630
+ readerElement.removeEventListener(
631
+ RHC_OFFICE_ADAPTER_EVENT,
632
+ adapterEventListener as EventListener,
633
+ );
634
+ });
635
+
636
+ NATIVE_READER_EVENT_NAMES.forEach((eventName) => {
637
+ const listener = (event: Event): void => {
638
+ const payload = event instanceof CustomEvent ? event.detail : event;
639
+ if (eventName === 'documentLoaded') {
640
+ this.readerState.setDocumentOpened(true);
641
+ }
642
+ this.emitReaderEvent(eventName, payload);
643
+ if (eventName === 'documentError') {
644
+ this.emitReaderEvent(READER_ERROR_EVENT_NAME, payload);
645
+ }
646
+ };
647
+
648
+ readerElement.addEventListener(eventName, listener as EventListener);
649
+ this.nativeEventCleanupCallbacks.push(() => {
650
+ readerElement.removeEventListener(eventName, listener as EventListener);
651
+ });
652
+ });
653
+ };
654
+
655
+ private readonly cleanupNativeEventForwarders = (): void => {
656
+ this.nativeEventCleanupCallbacks.splice(0).forEach((callback) => callback());
657
+ };
658
+
659
+ private readonly cleanupThemeBinding = (): void => {
660
+ this.themeCleanup?.();
661
+ this.themeCleanup = null;
662
+ };
663
+
664
+ private readonly emitReaderEvent = (eventName: string, payload: unknown): void => {
665
+ this.readerEventListener?.(eventName, payload as ReaderEventPayload);
666
+ };
667
+
668
+ private readonly reportReaderError = (error: unknown): void => {
669
+ this.isReady = false;
670
+ if (this.debugEnabled) {
671
+ console.error('[RHC Office SDK] Reader mount failed', error);
672
+ }
673
+
674
+ this.emitReaderEvent(READER_ERROR_EVENT_NAME, error);
675
+ };
676
+
677
+ private readonly reportAdapterError = (error: unknown): void => {
678
+ if (this.debugEnabled) {
679
+ console.error('[RHC Office SDK] Adapter command failed', error);
680
+ }
681
+
682
+ this.emitReaderEvent(READER_ERROR_EVENT_NAME, error);
683
+ };
684
+ }
685
+
686
+ export const createNewDocumentSdk = (options?: DocumentSDKRuntimeOptions): IDocumentSDK => {
687
+ return new DocumentSDK(options);
688
+ };