web-doc 0.3.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 (308) hide show
  1. package/LICENSE-APACHE +201 -0
  2. package/LICENSE-MIT +21 -0
  3. package/README.md +148 -0
  4. package/THIRD_PARTY_NOTICES.md +20 -0
  5. package/bin/copy-assets.mjs +27 -0
  6. package/dist/abort.d.ts +1 -0
  7. package/dist/abort.js +18 -0
  8. package/dist/adapters/bitmap.d.ts +9 -0
  9. package/dist/adapters/bitmap.js +63 -0
  10. package/dist/adapters/csv-parser.d.ts +7 -0
  11. package/dist/adapters/csv-parser.js +124 -0
  12. package/dist/adapters/csv.d.ts +26 -0
  13. package/dist/adapters/csv.js +231 -0
  14. package/dist/adapters/image.d.ts +41 -0
  15. package/dist/adapters/image.js +198 -0
  16. package/dist/adapters/office.d.ts +211 -0
  17. package/dist/adapters/office.js +672 -0
  18. package/dist/adapters/pdf.d.ts +32 -0
  19. package/dist/adapters/pdf.js +429 -0
  20. package/dist/adapters/svg.d.ts +17 -0
  21. package/dist/adapters/svg.js +123 -0
  22. package/dist/assets/image/index.d.ts +75 -0
  23. package/dist/assets/image/index.js +289 -0
  24. package/dist/assets/image/index_bg.wasm +0 -0
  25. package/dist/assets/image/index_bg.wasm.d.ts +12 -0
  26. package/dist/assets/legacy/index.d.ts +54 -0
  27. package/dist/assets/legacy/index.js +306 -0
  28. package/dist/assets/legacy/index_bg.wasm +0 -0
  29. package/dist/assets/legacy/index_bg.wasm.d.ts +9 -0
  30. package/dist/assets/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  31. package/dist/assets/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  32. package/dist/assets/pdfjs/cmaps/78-H.bcmap +0 -0
  33. package/dist/assets/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  34. package/dist/assets/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  35. package/dist/assets/pdfjs/cmaps/78-V.bcmap +0 -0
  36. package/dist/assets/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  37. package/dist/assets/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  38. package/dist/assets/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  39. package/dist/assets/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  40. package/dist/assets/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  41. package/dist/assets/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  42. package/dist/assets/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  43. package/dist/assets/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  44. package/dist/assets/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  45. package/dist/assets/pdfjs/cmaps/Add-H.bcmap +0 -0
  46. package/dist/assets/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  47. package/dist/assets/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  48. package/dist/assets/pdfjs/cmaps/Add-V.bcmap +0 -0
  49. package/dist/assets/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  50. package/dist/assets/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  51. package/dist/assets/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  52. package/dist/assets/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  53. package/dist/assets/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  54. package/dist/assets/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  55. package/dist/assets/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  56. package/dist/assets/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  57. package/dist/assets/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  58. package/dist/assets/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  59. package/dist/assets/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  60. package/dist/assets/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  61. package/dist/assets/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  62. package/dist/assets/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  63. package/dist/assets/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  64. package/dist/assets/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  65. package/dist/assets/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  66. package/dist/assets/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  67. package/dist/assets/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  68. package/dist/assets/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  69. package/dist/assets/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  70. package/dist/assets/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  71. package/dist/assets/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  72. package/dist/assets/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  73. package/dist/assets/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  74. package/dist/assets/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  75. package/dist/assets/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  76. package/dist/assets/pdfjs/cmaps/B5-H.bcmap +0 -0
  77. package/dist/assets/pdfjs/cmaps/B5-V.bcmap +0 -0
  78. package/dist/assets/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  79. package/dist/assets/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  80. package/dist/assets/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  81. package/dist/assets/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  82. package/dist/assets/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  83. package/dist/assets/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  84. package/dist/assets/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  85. package/dist/assets/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  86. package/dist/assets/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  87. package/dist/assets/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  88. package/dist/assets/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  89. package/dist/assets/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  90. package/dist/assets/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  91. package/dist/assets/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  92. package/dist/assets/pdfjs/cmaps/EUC-H.bcmap +0 -0
  93. package/dist/assets/pdfjs/cmaps/EUC-V.bcmap +0 -0
  94. package/dist/assets/pdfjs/cmaps/Ext-H.bcmap +0 -0
  95. package/dist/assets/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  96. package/dist/assets/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  97. package/dist/assets/pdfjs/cmaps/Ext-V.bcmap +0 -0
  98. package/dist/assets/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  99. package/dist/assets/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  100. package/dist/assets/pdfjs/cmaps/GB-H.bcmap +4 -0
  101. package/dist/assets/pdfjs/cmaps/GB-V.bcmap +0 -0
  102. package/dist/assets/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  103. package/dist/assets/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  104. package/dist/assets/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  105. package/dist/assets/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  106. package/dist/assets/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  107. package/dist/assets/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  108. package/dist/assets/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  109. package/dist/assets/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  110. package/dist/assets/pdfjs/cmaps/GBT-H.bcmap +0 -0
  111. package/dist/assets/pdfjs/cmaps/GBT-V.bcmap +0 -0
  112. package/dist/assets/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  113. package/dist/assets/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  114. package/dist/assets/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  115. package/dist/assets/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  116. package/dist/assets/pdfjs/cmaps/H.bcmap +0 -0
  117. package/dist/assets/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  118. package/dist/assets/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  119. package/dist/assets/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  120. package/dist/assets/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  121. package/dist/assets/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  122. package/dist/assets/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  123. package/dist/assets/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  124. package/dist/assets/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  125. package/dist/assets/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  126. package/dist/assets/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  127. package/dist/assets/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  128. package/dist/assets/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  129. package/dist/assets/pdfjs/cmaps/Hankaku.bcmap +0 -0
  130. package/dist/assets/pdfjs/cmaps/Hiragana.bcmap +0 -0
  131. package/dist/assets/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  132. package/dist/assets/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  133. package/dist/assets/pdfjs/cmaps/KSC-H.bcmap +0 -0
  134. package/dist/assets/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  135. package/dist/assets/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  136. package/dist/assets/pdfjs/cmaps/KSC-V.bcmap +0 -0
  137. package/dist/assets/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  138. package/dist/assets/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  139. package/dist/assets/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  140. package/dist/assets/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  141. package/dist/assets/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  142. package/dist/assets/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  143. package/dist/assets/pdfjs/cmaps/Katakana.bcmap +0 -0
  144. package/dist/assets/pdfjs/cmaps/LICENSE +36 -0
  145. package/dist/assets/pdfjs/cmaps/NWP-H.bcmap +0 -0
  146. package/dist/assets/pdfjs/cmaps/NWP-V.bcmap +0 -0
  147. package/dist/assets/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  148. package/dist/assets/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  149. package/dist/assets/pdfjs/cmaps/Roman.bcmap +0 -0
  150. package/dist/assets/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  151. package/dist/assets/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  152. package/dist/assets/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  153. package/dist/assets/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  154. package/dist/assets/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  155. package/dist/assets/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  156. package/dist/assets/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  157. package/dist/assets/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  158. package/dist/assets/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  159. package/dist/assets/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  160. package/dist/assets/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  161. package/dist/assets/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  162. package/dist/assets/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  163. package/dist/assets/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  164. package/dist/assets/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  165. package/dist/assets/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  166. package/dist/assets/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  167. package/dist/assets/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  168. package/dist/assets/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  169. package/dist/assets/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  170. package/dist/assets/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  171. package/dist/assets/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  172. package/dist/assets/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  173. package/dist/assets/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  174. package/dist/assets/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  175. package/dist/assets/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  176. package/dist/assets/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  177. package/dist/assets/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  178. package/dist/assets/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  179. package/dist/assets/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  180. package/dist/assets/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  181. package/dist/assets/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  182. package/dist/assets/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  183. package/dist/assets/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  184. package/dist/assets/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  185. package/dist/assets/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  186. package/dist/assets/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  187. package/dist/assets/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  188. package/dist/assets/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  189. package/dist/assets/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  190. package/dist/assets/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  191. package/dist/assets/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  192. package/dist/assets/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  193. package/dist/assets/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  194. package/dist/assets/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  195. package/dist/assets/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  196. package/dist/assets/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  197. package/dist/assets/pdfjs/cmaps/V.bcmap +0 -0
  198. package/dist/assets/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  199. package/dist/assets/pdfjs/iccs/CGATS001Compat-v2-micro.icc +0 -0
  200. package/dist/assets/pdfjs/iccs/LICENSE +116 -0
  201. package/dist/assets/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  202. package/dist/assets/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  203. package/dist/assets/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  204. package/dist/assets/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  205. package/dist/assets/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  206. package/dist/assets/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  207. package/dist/assets/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  208. package/dist/assets/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  209. package/dist/assets/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  210. package/dist/assets/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  211. package/dist/assets/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  212. package/dist/assets/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  213. package/dist/assets/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  214. package/dist/assets/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  215. package/dist/assets/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  216. package/dist/assets/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  217. package/dist/assets/pdfjs/wasm/LICENSE_JBIG2 +196 -0
  218. package/dist/assets/pdfjs/wasm/LICENSE_OPENJPEG +39 -0
  219. package/dist/assets/pdfjs/wasm/LICENSE_PDFJS_JBIG2 +13 -0
  220. package/dist/assets/pdfjs/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
  221. package/dist/assets/pdfjs/wasm/LICENSE_PDFJS_QCMS +22 -0
  222. package/dist/assets/pdfjs/wasm/LICENSE_QCMS +21 -0
  223. package/dist/assets/pdfjs/wasm/jbig2.wasm +0 -0
  224. package/dist/assets/pdfjs/wasm/jbig2_nowasm_fallback.js +15 -0
  225. package/dist/assets/pdfjs/wasm/openjpeg.wasm +0 -0
  226. package/dist/assets/pdfjs/wasm/openjpeg_nowasm_fallback.js +17 -0
  227. package/dist/assets/pdfjs/wasm/qcms_bg.wasm +0 -0
  228. package/dist/assets/pdfjs/wasm/quickjs-eval.js +16 -0
  229. package/dist/assets/pdfjs/wasm/quickjs-eval.wasm +0 -0
  230. package/dist/client.d.ts +20 -0
  231. package/dist/client.js +82 -0
  232. package/dist/contracts.d.ts +379 -0
  233. package/dist/contracts.js +22 -0
  234. package/dist/csv-worker.d.ts +1 -0
  235. package/dist/csv-worker.js +17 -0
  236. package/dist/detect.d.ts +15 -0
  237. package/dist/detect.js +290 -0
  238. package/dist/errors.d.ts +14 -0
  239. package/dist/errors.js +40 -0
  240. package/dist/font-manifest.d.ts +11 -0
  241. package/dist/font-manifest.js +31 -0
  242. package/dist/fonts/OFL-1.1.txt +88 -0
  243. package/dist/fonts/THIRD_PARTY_NOTICES.md +10 -0
  244. package/dist/fonts/manifest.json +83 -0
  245. package/dist/fonts/noto-sans-arabic.woff2 +0 -0
  246. package/dist/fonts/noto-sans-bengali.woff2 +0 -0
  247. package/dist/fonts/noto-sans-cjk.woff2 +0 -0
  248. package/dist/fonts/noto-sans-devanagari.woff2 +0 -0
  249. package/dist/fonts/noto-sans-gujarati.woff2 +0 -0
  250. package/dist/fonts/noto-sans-gurmukhi.woff2 +0 -0
  251. package/dist/fonts/noto-sans-japanese.woff2 +0 -0
  252. package/dist/fonts/noto-sans-kannada.woff2 +0 -0
  253. package/dist/fonts/noto-sans-korean.woff2 +0 -0
  254. package/dist/fonts/noto-sans-latin-cyrillic.woff2 +0 -0
  255. package/dist/fonts/noto-sans-malayalam.woff2 +0 -0
  256. package/dist/fonts/noto-sans-odia.woff2 +0 -0
  257. package/dist/fonts/noto-sans-tamil.woff2 +0 -0
  258. package/dist/fonts/noto-sans-telugu.woff2 +0 -0
  259. package/dist/fonts.d.ts +20 -0
  260. package/dist/fonts.js +238 -0
  261. package/dist/format.d.ts +1 -0
  262. package/dist/format.js +1 -0
  263. package/dist/headless.d.ts +18 -0
  264. package/dist/headless.js +18 -0
  265. package/dist/i18n.d.ts +4 -0
  266. package/dist/i18n.js +55 -0
  267. package/dist/image-worker.d.ts +1 -0
  268. package/dist/image-worker.js +41 -0
  269. package/dist/index.d.ts +27 -0
  270. package/dist/index.js +29 -0
  271. package/dist/interaction.d.ts +24 -0
  272. package/dist/interaction.js +183 -0
  273. package/dist/legacy-converter-worker.d.ts +1 -0
  274. package/dist/legacy-converter-worker.js +19 -0
  275. package/dist/limits.d.ts +4 -0
  276. package/dist/limits.js +162 -0
  277. package/dist/registry.d.ts +8 -0
  278. package/dist/registry.js +35 -0
  279. package/dist/render-scheduler.d.ts +8 -0
  280. package/dist/render-scheduler.js +63 -0
  281. package/dist/source.d.ts +14 -0
  282. package/dist/source.js +116 -0
  283. package/dist/spreadsheet-viewport.d.ts +34 -0
  284. package/dist/spreadsheet-viewport.js +1035 -0
  285. package/dist/styles.css +137 -0
  286. package/dist/ui-styles.d.ts +1 -0
  287. package/dist/ui-styles.js +139 -0
  288. package/dist/ui.d.ts +8 -0
  289. package/dist/ui.js +390 -0
  290. package/dist/viewer.d.ts +52 -0
  291. package/dist/viewer.js +901 -0
  292. package/dist/viewport.d.ts +54 -0
  293. package/dist/viewport.js +907 -0
  294. package/dist/worker-adapter.d.ts +24 -0
  295. package/dist/worker-adapter.js +97 -0
  296. package/dist/worker-client.d.ts +23 -0
  297. package/dist/worker-client.js +105 -0
  298. package/dist/worker-endpoint.d.ts +13 -0
  299. package/dist/worker-endpoint.js +57 -0
  300. package/dist/worker-protocol.d.ts +48 -0
  301. package/dist/worker-protocol.js +14 -0
  302. package/dist/worker.d.ts +4 -0
  303. package/dist/worker.js +4 -0
  304. package/dist/workers/csv-worker.js +160 -0
  305. package/dist/workers/image-worker.js +41 -0
  306. package/dist/workers/legacy-converter-worker.js +19 -0
  307. package/dist/workers/pdf.worker.min.mjs +28 -0
  308. package/package.json +74 -0
package/dist/viewer.js ADDED
@@ -0,0 +1,901 @@
1
+ import { linkedAbortController } from "./abort.js";
2
+ import { detectFormat } from "./detect.js";
3
+ import { abortError, normalizeError, ViewerError } from "./errors.js";
4
+ import { cellRangeToTsv, cellRangesToTsv, findNormalizedMatches, normalizeCellRange, } from "./interaction.js";
5
+ import { enforceContainerLimits, resolveLimits } from "./limits.js";
6
+ import { loadDocumentSource } from "./source.js";
7
+ import { AdaptiveViewport } from "./viewport.js";
8
+ import { BasicViewerUi } from "./ui.js";
9
+ import { resolveTranslations } from "./i18n.js";
10
+ import { RenderScheduler } from "./render-scheduler.js";
11
+ const MIN_ZOOM = 0.1;
12
+ const MAX_ZOOM = 8;
13
+ const THUMBNAIL_BASE_WIDTH = 816;
14
+ const THUMBNAIL_BASE_HEIGHT = 1056;
15
+ export class DocumentViewer {
16
+ #options;
17
+ #runtime;
18
+ #listeners = new Map();
19
+ #operations = new Set();
20
+ #textMaps = new Map();
21
+ #viewport;
22
+ #ui;
23
+ #state;
24
+ #adapter;
25
+ #handle;
26
+ #info;
27
+ #original;
28
+ #originalFileName;
29
+ #activeLoad;
30
+ #activeSearch;
31
+ #selection = null;
32
+ #searchResult = null;
33
+ #generation = 0;
34
+ #searchGeneration = 0;
35
+ #viewEventScheduled = false;
36
+ #textMapBytes = 0;
37
+ constructor(options, runtime) {
38
+ this.#options = options;
39
+ this.#runtime = runtime;
40
+ this.#state = freezeState({
41
+ status: "idle",
42
+ pageIndex: 0,
43
+ pageCount: 0,
44
+ zoom: clampZoom(options.initialZoom ?? 1),
45
+ fit: options.fit ?? "none",
46
+ panX: 0,
47
+ panY: 0,
48
+ });
49
+ let viewportContainer = options.container;
50
+ if (options.container && options.ui) {
51
+ this.#ui = new BasicViewerUi(options.container, this, resolveTranslations(options.locale, options.translations));
52
+ this.#ui.root.lang = options.locale ?? "en";
53
+ viewportContainer = this.#ui.viewportContainer;
54
+ }
55
+ if (viewportContainer) {
56
+ const thisViewer = this;
57
+ this.#viewport = new AdaptiveViewport(viewportContainer, {
58
+ get state() {
59
+ return thisViewer.state;
60
+ },
61
+ renderPage: (pageIndex, target, renderOptions) => this.renderPage(pageIndex, target, renderOptions),
62
+ renderSheetViewport: (sheetIndex, target, range, renderOptions) => this.renderSheetViewport(sheetIndex, target, range, renderOptions),
63
+ getTextRuns: (pageIndex, signal) => this.#getTextRuns(pageIndex, signal),
64
+ getSearchMatches: (pageIndex) => this.#matchesForPage(pageIndex),
65
+ getActiveSearchMatch: () => this.#activeSearchMatch(),
66
+ onVisiblePage: (pageIndex) => this.#goToPage(pageIndex, false),
67
+ onPan: (panX, panY) => this.#setPan(panX, panY),
68
+ onZoom: (zoom) => this.setZoom(zoom),
69
+ onTextSelection: (range) => void this.selectText(range),
70
+ onCellSelection: (selection) => this.#applyInteractiveCellSelection(selection),
71
+ getSelectionText: () => this.#getCachedSelectionText(),
72
+ }, options);
73
+ }
74
+ }
75
+ get state() {
76
+ return this.#state;
77
+ }
78
+ async load(source, options = {}) {
79
+ this.#assertAlive();
80
+ const generation = ++this.#generation;
81
+ this.#abortOperations();
82
+ this.#activeLoad?.abort();
83
+ const controller = linkedAbortController(options.signal);
84
+ this.#activeLoad = controller;
85
+ await this.#closeDocument();
86
+ if (controller.signal.aborted || generation !== this.#generation)
87
+ throw abortError();
88
+ this.#update({
89
+ status: "loading",
90
+ pageIndex: 0,
91
+ pageCount: 0,
92
+ panX: 0,
93
+ panY: 0,
94
+ });
95
+ try {
96
+ const limits = resolveLimits(this.#runtime.limits, options.limits);
97
+ const loaded = await loadDocumentSource(source, {
98
+ fetch: this.#runtime.fetch,
99
+ signal: controller.signal,
100
+ maxBytes: limits.maxInputBytes,
101
+ reportProgress: (progress) => this.#emit("progress", progress),
102
+ });
103
+ this.#emit("progress", {
104
+ phase: "detecting",
105
+ loaded: loaded.bytes.byteLength,
106
+ });
107
+ const fileName = options.fileName ?? loaded.fileName;
108
+ const contentType = options.contentType ?? loaded.contentType;
109
+ const detection = detectFormat(loaded.bytes, {
110
+ ...(options.format ? { format: options.format } : {}),
111
+ ...(fileName ? { fileName } : {}),
112
+ ...(contentType ? { contentType } : {}),
113
+ });
114
+ for (const warning of detection.warnings)
115
+ this.#emit("warning", warning);
116
+ enforceContainerLimits(loaded.bytes, detection.format, limits);
117
+ const adapter = this.#runtime.registry.resolve(detection.format);
118
+ const handle = await adapter.open(loaded.bytes, {
119
+ format: detection.format,
120
+ signal: controller.signal,
121
+ limits,
122
+ reportProgress: (progress) => this.#emit("progress", progress),
123
+ reportWarning: (warning) => this.#emit("warning", warning),
124
+ ...(fileName ? { fileName } : {}),
125
+ ...(contentType ? { contentType } : {}),
126
+ ...(this.#runtime.assetBaseUrl
127
+ ? { assetBaseUrl: this.#runtime.assetBaseUrl }
128
+ : {}),
129
+ });
130
+ if (controller.signal.aborted || generation !== this.#generation) {
131
+ await adapter.close(handle);
132
+ throw abortError();
133
+ }
134
+ let backendInfo;
135
+ try {
136
+ backendInfo = await adapter.getInfo(handle);
137
+ }
138
+ catch (error) {
139
+ await adapter.close(handle);
140
+ throw error;
141
+ }
142
+ if (generation !== this.#generation) {
143
+ await adapter.close(handle);
144
+ throw abortError();
145
+ }
146
+ if (!Number.isInteger(backendInfo.pageCount) ||
147
+ backendInfo.pageCount < 1 ||
148
+ backendInfo.pageCount > limits.maxDocumentUnits) {
149
+ await adapter.close(handle);
150
+ throw new ViewerError("resource-limit", "Document unit count exceeds the configured limit", {
151
+ details: {
152
+ pageCount: backendInfo.pageCount,
153
+ limit: limits.maxDocumentUnits,
154
+ },
155
+ });
156
+ }
157
+ const info = immutableInfo({
158
+ ...backendInfo,
159
+ capabilities: {
160
+ textSelection: Boolean(adapter.getTextMap),
161
+ cellSelection: backendInfo.unit === "sheet",
162
+ search: Boolean(adapter.getTextMap),
163
+ thumbnails: backendInfo.unit !== "sheet",
164
+ },
165
+ });
166
+ this.#adapter = adapter;
167
+ this.#handle = handle;
168
+ this.#info = info;
169
+ this.#original = loaded.bytes;
170
+ this.#originalFileName = fileName;
171
+ this.#update({
172
+ status: "ready",
173
+ format: detection.format,
174
+ pageIndex: 0,
175
+ pageCount: info.pageCount,
176
+ });
177
+ for (const warning of info.warnings ?? [])
178
+ this.#emit("warning", warning);
179
+ this.#viewport?.setDocument(info);
180
+ this.#emit("ready", this.#state);
181
+ if (this.#options.fit === "width")
182
+ this.fitWidth();
183
+ else if (this.#options.fit === "page")
184
+ this.fitPage();
185
+ }
186
+ catch (cause) {
187
+ const error = normalizeError(cause, "invalid-file");
188
+ if (generation === this.#generation) {
189
+ this.#update({ status: "error" });
190
+ this.#emit("error", error.toJSON());
191
+ this.#runtime.logger?.error?.(error.message, { code: error.code });
192
+ }
193
+ throw error;
194
+ }
195
+ finally {
196
+ if (this.#activeLoad === controller)
197
+ this.#activeLoad = undefined;
198
+ }
199
+ }
200
+ open(source, options = {}) {
201
+ return this.load(source, options);
202
+ }
203
+ async close() {
204
+ if (this.#state.status === "destroyed")
205
+ return;
206
+ this.#generation += 1;
207
+ this.#activeLoad?.abort();
208
+ this.#activeLoad = undefined;
209
+ this.#abortOperations();
210
+ await this.#closeDocument();
211
+ const { format: _format, ...state } = this.#state;
212
+ this.#state = freezeState({
213
+ ...state,
214
+ status: "idle",
215
+ pageIndex: 0,
216
+ pageCount: 0,
217
+ panX: 0,
218
+ panY: 0,
219
+ });
220
+ this.#viewport?.setDocument(undefined);
221
+ this.#emit("statechange", this.#state);
222
+ this.#scheduleViewEvent();
223
+ }
224
+ setZoom(zoom) {
225
+ this.#assertAlive();
226
+ const next = clampZoom(zoom);
227
+ this.#update({ zoom: next, fit: "none" });
228
+ }
229
+ zoomIn() {
230
+ this.setZoom(this.#state.zoom * 1.2);
231
+ }
232
+ zoomOut() {
233
+ this.setZoom(this.#state.zoom / 1.2);
234
+ }
235
+ setFit(fit) {
236
+ this.#assertAlive();
237
+ if (fit === "width")
238
+ this.fitWidth();
239
+ else if (fit === "page")
240
+ this.fitPage();
241
+ else
242
+ this.#update({ fit: "none" });
243
+ }
244
+ fitWidth() {
245
+ this.#assertAlive();
246
+ const zoom = this.#viewport?.fitWidth() ?? this.#state.zoom;
247
+ this.#update({ zoom: clampZoom(zoom), fit: "width" });
248
+ }
249
+ fitPage() {
250
+ this.#assertAlive();
251
+ const zoom = this.#viewport?.fitPage() ?? this.#state.zoom;
252
+ this.#update({ zoom: clampZoom(zoom), fit: "page" });
253
+ }
254
+ panBy(deltaX, deltaY) {
255
+ this.#assertAlive();
256
+ if (!Number.isFinite(deltaX) || !Number.isFinite(deltaY))
257
+ return;
258
+ if (this.#viewport)
259
+ this.#viewport.panBy(deltaX, deltaY);
260
+ else
261
+ this.#setPan(this.#state.panX + deltaX, this.#state.panY + deltaY);
262
+ }
263
+ goToPage(pageIndex) {
264
+ this.#goToPage(pageIndex, true);
265
+ }
266
+ next() {
267
+ this.goToPage(this.#state.pageIndex + 1);
268
+ }
269
+ previous() {
270
+ this.goToPage(this.#state.pageIndex - 1);
271
+ }
272
+ setSheet(sheetIndex) {
273
+ this.#assertReady();
274
+ if (this.#info?.unit !== "sheet")
275
+ throw new ViewerError("lifecycle-error", "The current document has no sheets");
276
+ this.goToPage(sheetIndex);
277
+ }
278
+ async renderPage(pageIndex, target, options = {}) {
279
+ const { adapter, handle, info } = this.#assertReady();
280
+ assertPageIndex(pageIndex, info.pageCount);
281
+ const operation = this.#startOperation(options.signal);
282
+ const generation = this.#generation;
283
+ try {
284
+ await this.#runtime.renderScheduler.run(options.priority ?? "visible", operation.signal, async () => {
285
+ const zoom = clampZoom(options.zoom ?? this.#state.zoom);
286
+ const devicePixelRatio = positiveNumber(options.devicePixelRatio, globalThis.devicePixelRatio ?? 1);
287
+ assertRenderBudget(options.width ?? THUMBNAIL_BASE_WIDTH * zoom, options.height ?? THUMBNAIL_BASE_HEIGHT * zoom, devicePixelRatio, this.#runtime.limits.maxDecodedPixels);
288
+ this.#emit("progress", { phase: "rendering", loaded: 0, total: 1 });
289
+ if (adapter.getTextMap) {
290
+ const runs = await this.#getTextRuns(pageIndex, operation.signal);
291
+ await this.#runtime.fonts.ensureRuns(runs, (warning) => this.#emit("warning", warning), operation.signal);
292
+ }
293
+ await adapter.render(handle, target, {
294
+ pageIndex,
295
+ zoom,
296
+ devicePixelRatio,
297
+ ...(options.width === undefined ? {} : { width: options.width }),
298
+ ...(options.height === undefined
299
+ ? {}
300
+ : { height: options.height }),
301
+ }, operation.signal);
302
+ if (generation !== this.#generation || operation.signal.aborted)
303
+ throw abortError();
304
+ this.#emit("progress", {
305
+ phase: "rendering",
306
+ loaded: 1,
307
+ total: 1,
308
+ ratio: 1,
309
+ });
310
+ });
311
+ }
312
+ catch (error) {
313
+ throw normalizeError(error, "render-failed");
314
+ }
315
+ finally {
316
+ this.#finishOperation(operation);
317
+ }
318
+ }
319
+ async renderThumbnail(pageIndex, target, options = {}) {
320
+ const scale = Math.min(1, positiveNumber(options.maxWidth, 180) / THUMBNAIL_BASE_WIDTH, positiveNumber(options.maxHeight, 240) / THUMBNAIL_BASE_HEIGHT);
321
+ await this.renderPage(pageIndex, target, {
322
+ zoom: scale,
323
+ priority: "background",
324
+ ...(options.devicePixelRatio === undefined
325
+ ? {}
326
+ : { devicePixelRatio: options.devicePixelRatio }),
327
+ ...(options.signal ? { signal: options.signal } : {}),
328
+ });
329
+ }
330
+ async renderSheetViewport(sheetIndex, target, range, options = {}) {
331
+ const { adapter, handle, info } = this.#assertReady();
332
+ if (info.unit !== "sheet")
333
+ throw new ViewerError("lifecycle-error", "The current document has no sheets");
334
+ assertPageIndex(sheetIndex, info.pageCount);
335
+ const operation = this.#startOperation(options.signal);
336
+ const generation = this.#generation;
337
+ try {
338
+ await this.#runtime.renderScheduler.run(options.priority ?? "visible", operation.signal, async () => {
339
+ const zoom = clampZoom(options.zoom ?? this.#state.zoom);
340
+ const devicePixelRatio = positiveNumber(options.devicePixelRatio, globalThis.devicePixelRatio ?? 1);
341
+ assertRenderBudget(options.width ?? THUMBNAIL_BASE_WIDTH * zoom, options.height ?? THUMBNAIL_BASE_HEIGHT * zoom, devicePixelRatio, this.#runtime.limits.maxDecodedPixels);
342
+ if (adapter.getTextMap) {
343
+ const runs = await this.#getTextRuns(sheetIndex, operation.signal);
344
+ await this.#runtime.fonts.ensureRuns(runs, (warning) => this.#emit("warning", warning), operation.signal);
345
+ }
346
+ await adapter.render(handle, target, {
347
+ pageIndex: sheetIndex,
348
+ zoom,
349
+ devicePixelRatio,
350
+ sheetRange: normalizeSheetViewport(range),
351
+ ...(options.width === undefined ? {} : { width: options.width }),
352
+ ...(options.height === undefined
353
+ ? {}
354
+ : { height: options.height }),
355
+ ...(options.scrollOffsetX === undefined
356
+ ? {}
357
+ : { scrollOffsetX: options.scrollOffsetX }),
358
+ ...(options.scrollOffsetY === undefined
359
+ ? {}
360
+ : { scrollOffsetY: options.scrollOffsetY }),
361
+ ...(options.columnWidths === undefined
362
+ ? {}
363
+ : { columnWidths: options.columnWidths }),
364
+ }, operation.signal);
365
+ if (generation !== this.#generation || operation.signal.aborted)
366
+ throw abortError();
367
+ });
368
+ }
369
+ catch (error) {
370
+ throw normalizeError(error, "render-failed");
371
+ }
372
+ finally {
373
+ this.#finishOperation(operation);
374
+ }
375
+ }
376
+ async getPageText(pageIndex, signal) {
377
+ return (await this.#getTextRuns(pageIndex, signal))
378
+ .map((run) => run.text)
379
+ .join("");
380
+ }
381
+ getDocumentInfo() {
382
+ return this.#assertReady().info;
383
+ }
384
+ async search(query, options = {}) {
385
+ const { info } = this.#assertReady();
386
+ // Validated before the in-flight search is cancelled so a rejected range
387
+ // leaves the current result and highlights untouched.
388
+ const [firstPage, lastPage] = resolveSearchPageRange(info.pageCount, options.pageRange);
389
+ this.#activeSearch?.abort();
390
+ const controller = new AbortController();
391
+ this.#activeSearch = controller;
392
+ const generation = ++this.#searchGeneration;
393
+ const cleanQuery = query;
394
+ if (!cleanQuery) {
395
+ this.clearSearch();
396
+ return immutableSearchResult({ query, matches: [], activeIndex: -1 });
397
+ }
398
+ const matches = [];
399
+ try {
400
+ for (let pageIndex = firstPage; pageIndex <= lastPage; pageIndex += 1) {
401
+ if (controller.signal.aborted)
402
+ throw abortError();
403
+ const text = await this.getPageText(pageIndex, controller.signal);
404
+ matches.push(...findNormalizedMatches(text, cleanQuery, pageIndex, options.caseSensitive ?? false));
405
+ }
406
+ if (generation !== this.#searchGeneration)
407
+ throw abortError();
408
+ const result = immutableSearchResult({
409
+ query,
410
+ matches,
411
+ activeIndex: matches.length > 0 ? 0 : -1,
412
+ });
413
+ this.#searchResult = result;
414
+ if (result.activeIndex >= 0)
415
+ this.#goToPage(result.matches[result.activeIndex].pageIndex, true);
416
+ this.#emit("searchchange", result);
417
+ this.#viewport?.update();
418
+ return result;
419
+ }
420
+ finally {
421
+ if (this.#activeSearch === controller)
422
+ this.#activeSearch = undefined;
423
+ }
424
+ }
425
+ searchNext() {
426
+ return this.#moveSearch(1);
427
+ }
428
+ searchPrevious() {
429
+ return this.#moveSearch(-1);
430
+ }
431
+ clearSearch() {
432
+ this.#activeSearch?.abort();
433
+ this.#activeSearch = undefined;
434
+ this.#searchGeneration += 1;
435
+ this.#searchResult = null;
436
+ this.#emit("searchchange", null);
437
+ this.#viewport?.update();
438
+ }
439
+ getSelection() {
440
+ return this.#selection;
441
+ }
442
+ async selectText(range) {
443
+ const { info } = this.#assertReady();
444
+ if (!info.capabilities?.textSelection)
445
+ throw new ViewerError("lifecycle-error", "Text selection is unavailable");
446
+ const normalized = normalizeTextSelectionRange(range);
447
+ assertPageIndex(normalized.startPageIndex, info.pageCount);
448
+ assertPageIndex(normalized.endPageIndex, info.pageCount);
449
+ const selectedRuns = [];
450
+ const pageTexts = [];
451
+ for (let pageIndex = normalized.startPageIndex; pageIndex <= normalized.endPageIndex; pageIndex += 1) {
452
+ const runs = await this.#getTextRuns(pageIndex);
453
+ const text = runs.map((run) => run.text).join("");
454
+ const start = pageIndex === normalized.startPageIndex ? normalized.startOffset : 0;
455
+ const end = pageIndex === normalized.endPageIndex
456
+ ? normalized.endOffset
457
+ : text.length;
458
+ const safeStart = Math.max(0, Math.min(text.length, start));
459
+ const safeEnd = Math.max(safeStart, Math.min(text.length, end));
460
+ pageTexts.push(text.slice(safeStart, safeEnd));
461
+ selectedRuns.push(...sliceTextRuns(runs, safeStart, safeEnd));
462
+ }
463
+ const selection = Object.freeze({
464
+ pageIndex: normalized.startPageIndex,
465
+ ...(normalized.endPageIndex === normalized.startPageIndex
466
+ ? {}
467
+ : { endPageIndex: normalized.endPageIndex }),
468
+ startOffset: normalized.startOffset,
469
+ endOffset: normalized.endOffset,
470
+ text: pageTexts.join("\n"),
471
+ runs: Object.freeze(selectedRuns),
472
+ });
473
+ this.#selection = selection;
474
+ this.#emit("selectionchange", selection);
475
+ return selection;
476
+ }
477
+ selectCells(range) {
478
+ const { info } = this.#assertReady();
479
+ if (info.unit !== "sheet")
480
+ throw new ViewerError("lifecycle-error", "Cell selection is unavailable");
481
+ assertPageIndex(range.sheetIndex, info.pageCount);
482
+ const selection = Object.freeze(expandMergedRange(normalizeCellRange(range), info));
483
+ this.#selection = selection;
484
+ this.#emit("selectionchange", selection);
485
+ return selection;
486
+ }
487
+ selectCellRanges(ranges) {
488
+ const { info } = this.#assertReady();
489
+ if (info.unit !== "sheet")
490
+ throw new ViewerError("lifecycle-error", "Cell selection is unavailable");
491
+ if (ranges.length === 0)
492
+ throw new ViewerError("lifecycle-error", "At least one cell range is required");
493
+ const sheetIndex = ranges[0].sheetIndex;
494
+ assertPageIndex(sheetIndex, info.pageCount);
495
+ const normalized = ranges.map((range) => {
496
+ if (range.sheetIndex !== sheetIndex)
497
+ throw new ViewerError("lifecycle-error", "Cell ranges must belong to one sheet");
498
+ return Object.freeze(expandMergedRange(normalizeCellRange(range), info));
499
+ });
500
+ const selection = Object.freeze({
501
+ sheetIndex,
502
+ ranges: Object.freeze(normalized),
503
+ });
504
+ this.#selection = selection;
505
+ this.#emit("selectionchange", selection);
506
+ return selection;
507
+ }
508
+ clearSelection() {
509
+ this.#selection = null;
510
+ this.#emit("selectionchange", null);
511
+ }
512
+ async copySelection() {
513
+ const selection = this.#selection;
514
+ if (!selection)
515
+ return "";
516
+ let text = this.#getCachedSelectionText();
517
+ if (text === undefined) {
518
+ if ("text" in selection)
519
+ text = selection.text;
520
+ else {
521
+ const runs = await this.#getTextRuns(selection.sheetIndex);
522
+ text = cellSelectionToTsv(selection, runs);
523
+ }
524
+ }
525
+ try {
526
+ await globalThis.navigator?.clipboard?.writeText(text);
527
+ }
528
+ catch {
529
+ // Clipboard permission is host/browser controlled; returning text is deterministic.
530
+ }
531
+ return text;
532
+ }
533
+ #getCachedSelectionText() {
534
+ const selection = this.#selection;
535
+ if (!selection)
536
+ return undefined;
537
+ if ("text" in selection)
538
+ return selection.text;
539
+ const runs = this.#textMaps.get(selection.sheetIndex);
540
+ return runs ? cellSelectionToTsv(selection, runs) : undefined;
541
+ }
542
+ #applyInteractiveCellSelection(selection) {
543
+ if (!selection)
544
+ this.clearSelection();
545
+ else if ("ranges" in selection)
546
+ this.selectCellRanges(selection.ranges);
547
+ else
548
+ this.selectCells(selection);
549
+ }
550
+ getOriginalBytes() {
551
+ this.#assertAlive();
552
+ return this.#original?.slice();
553
+ }
554
+ downloadOriginal(fileName = this.#originalFileName ?? "document") {
555
+ this.#assertAlive();
556
+ if (!this.#original)
557
+ throw new ViewerError("lifecycle-error", "No document is open");
558
+ const blob = new Blob([this.#original.slice()], {
559
+ type: "application/octet-stream",
560
+ });
561
+ if (typeof document !== "undefined") {
562
+ const url = URL.createObjectURL(blob);
563
+ const link = document.createElement("a");
564
+ link.href = url;
565
+ link.download = fileName;
566
+ link.hidden = true;
567
+ document.body.append(link);
568
+ link.click();
569
+ link.remove();
570
+ queueMicrotask(() => URL.revokeObjectURL(url));
571
+ }
572
+ return blob;
573
+ }
574
+ on(type, listener) {
575
+ this.#assertAlive();
576
+ const listeners = this.#listeners.get(type) ?? new Set();
577
+ listeners.add(listener);
578
+ this.#listeners.set(type, listeners);
579
+ return () => listeners.delete(listener);
580
+ }
581
+ async destroy() {
582
+ if (this.#state.status === "destroyed")
583
+ return;
584
+ this.#generation += 1;
585
+ this.#activeLoad?.abort();
586
+ this.#activeLoad = undefined;
587
+ this.#abortOperations();
588
+ await this.#closeDocument();
589
+ this.#viewport?.destroy();
590
+ this.#ui?.destroy();
591
+ this.#state = freezeState({
592
+ ...this.#state,
593
+ status: "destroyed",
594
+ pageIndex: 0,
595
+ pageCount: 0,
596
+ panX: 0,
597
+ panY: 0,
598
+ });
599
+ this.#emit("statechange", this.#state);
600
+ this.#listeners.clear();
601
+ this.#runtime.release(this);
602
+ }
603
+ async #getTextRuns(pageIndex, signal) {
604
+ const { adapter, handle, info } = this.#assertReady();
605
+ assertPageIndex(pageIndex, info.pageCount);
606
+ if (signal?.aborted)
607
+ throw abortError();
608
+ const cached = this.#textMaps.get(pageIndex);
609
+ if (cached)
610
+ return cached;
611
+ if (!adapter.getTextMap)
612
+ return [];
613
+ const operation = this.#startOperation(signal);
614
+ const generation = this.#generation;
615
+ try {
616
+ const runs = await adapter.getTextMap(handle, pageIndex, operation.signal);
617
+ if (generation !== this.#generation || operation.signal.aborted)
618
+ throw abortError();
619
+ const immutableRuns = Object.freeze(runs.map((run) => Object.freeze({ ...run })));
620
+ const bytes = immutableRuns.reduce((total, run) => total + new TextEncoder().encode(run.text).byteLength + 96, 0);
621
+ if (this.#textMapBytes + bytes > this.#runtime.limits.maxTextMapBytes)
622
+ throw new ViewerError("resource-limit", "Document text maps exceed the configured memory limit", {
623
+ details: {
624
+ bytes: this.#textMapBytes + bytes,
625
+ limit: this.#runtime.limits.maxTextMapBytes,
626
+ },
627
+ });
628
+ this.#textMaps.set(pageIndex, immutableRuns);
629
+ this.#textMapBytes += bytes;
630
+ return immutableRuns;
631
+ }
632
+ catch (error) {
633
+ throw normalizeError(error, "render-failed");
634
+ }
635
+ finally {
636
+ this.#finishOperation(operation);
637
+ }
638
+ }
639
+ #matchesForPage(pageIndex) {
640
+ return (this.#searchResult?.matches.filter((match) => match.pageIndex === pageIndex) ?? []);
641
+ }
642
+ #activeSearchMatch() {
643
+ const result = this.#searchResult;
644
+ return result && result.activeIndex >= 0
645
+ ? result.matches[result.activeIndex]
646
+ : undefined;
647
+ }
648
+ #moveSearch(direction) {
649
+ const current = this.#searchResult;
650
+ if (!current || current.matches.length === 0)
651
+ return current;
652
+ const activeIndex = (current.activeIndex + direction + current.matches.length) %
653
+ current.matches.length;
654
+ const result = immutableSearchResult({ ...current, activeIndex });
655
+ this.#searchResult = result;
656
+ this.#goToPage(result.matches[activeIndex].pageIndex, true);
657
+ this.#emit("searchchange", result);
658
+ this.#viewport?.update();
659
+ return result;
660
+ }
661
+ #goToPage(pageIndex, scrollViewport) {
662
+ this.#assertAlive();
663
+ const upperBound = Math.max(0, this.#state.pageCount - 1);
664
+ const next = Math.min(Math.max(0, Math.trunc(pageIndex)), upperBound);
665
+ this.#update({ pageIndex: next });
666
+ if (scrollViewport)
667
+ this.#viewport?.goToPage(next);
668
+ }
669
+ #setPan(panX, panY) {
670
+ const x = Math.max(0, Number.isFinite(panX) ? panX : 0);
671
+ const y = Math.max(0, Number.isFinite(panY) ? panY : 0);
672
+ if (x === this.#state.panX && y === this.#state.panY)
673
+ return;
674
+ this.#update({ panX: x, panY: y });
675
+ }
676
+ async #closeDocument() {
677
+ const adapter = this.#adapter;
678
+ const handle = this.#handle;
679
+ this.#adapter = undefined;
680
+ this.#handle = undefined;
681
+ this.#info = undefined;
682
+ this.#original = undefined;
683
+ this.#originalFileName = undefined;
684
+ this.#activeSearch?.abort();
685
+ this.#activeSearch = undefined;
686
+ this.#searchResult = null;
687
+ this.#selection = null;
688
+ this.#textMaps.clear();
689
+ this.#textMapBytes = 0;
690
+ if (adapter && handle !== undefined)
691
+ await adapter.close(handle);
692
+ }
693
+ #assertReady() {
694
+ this.#assertAlive();
695
+ if (this.#state.status !== "ready" ||
696
+ !this.#adapter ||
697
+ this.#handle === undefined ||
698
+ !this.#info)
699
+ throw new ViewerError("lifecycle-error", "No document is ready");
700
+ return { adapter: this.#adapter, handle: this.#handle, info: this.#info };
701
+ }
702
+ #assertAlive() {
703
+ if (this.#state.status === "destroyed")
704
+ throw new ViewerError("lifecycle-error", "DocumentViewer is destroyed");
705
+ }
706
+ #startOperation(signal) {
707
+ const controller = linkedAbortController(signal);
708
+ this.#operations.add(controller);
709
+ return controller;
710
+ }
711
+ #finishOperation(controller) {
712
+ this.#operations.delete(controller);
713
+ }
714
+ #abortOperations() {
715
+ for (const controller of this.#operations)
716
+ controller.abort();
717
+ this.#operations.clear();
718
+ this.#activeSearch?.abort();
719
+ }
720
+ #update(patch) {
721
+ const previous = this.#state;
722
+ this.#state = freezeState({ ...this.#state, ...patch });
723
+ this.#emit("statechange", this.#state);
724
+ if (previous.pageIndex !== this.#state.pageIndex)
725
+ this.#emit("pagechange", {
726
+ pageIndex: this.#state.pageIndex,
727
+ pageCount: this.#state.pageCount,
728
+ });
729
+ if (previous.zoom !== this.#state.zoom || previous.fit !== this.#state.fit)
730
+ this.#emit("zoomchange", {
731
+ zoom: this.#state.zoom,
732
+ fit: this.#state.fit,
733
+ });
734
+ this.#viewport?.update();
735
+ this.#scheduleViewEvent();
736
+ }
737
+ #scheduleViewEvent() {
738
+ if (this.#viewEventScheduled)
739
+ return;
740
+ this.#viewEventScheduled = true;
741
+ const emit = () => {
742
+ this.#viewEventScheduled = false;
743
+ if (this.#state.status !== "destroyed")
744
+ this.#emit("viewchange", this.#state);
745
+ };
746
+ if (typeof requestAnimationFrame === "function")
747
+ requestAnimationFrame(emit);
748
+ else
749
+ queueMicrotask(emit);
750
+ }
751
+ #emit(type, event) {
752
+ for (const listener of this.#listeners.get(type) ?? [])
753
+ listener(event);
754
+ }
755
+ }
756
+ function clampZoom(value) {
757
+ if (!Number.isFinite(value))
758
+ return 1;
759
+ return Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, value));
760
+ }
761
+ function positiveNumber(value, fallback) {
762
+ return value !== undefined && Number.isFinite(value) && value > 0
763
+ ? value
764
+ : fallback;
765
+ }
766
+ function assertRenderBudget(cssWidth, cssHeight, devicePixelRatio, limit) {
767
+ const width = Math.max(1, Math.ceil(positiveNumber(cssWidth, 1) * devicePixelRatio));
768
+ const height = Math.max(1, Math.ceil(positiveNumber(cssHeight, 1) * devicePixelRatio));
769
+ const pixels = width * height;
770
+ if (!Number.isSafeInteger(pixels) || pixels > limit)
771
+ throw new ViewerError("resource-limit", "Render target exceeds the configured pixel limit", { details: { width, height, pixels, limit } });
772
+ }
773
+ /**
774
+ * Resolve the inclusive 0-based page window a search scans. Omitting the range
775
+ * searches the whole document; a reversed range is normalized so callers can
776
+ * pass either endpoint order.
777
+ */
778
+ function resolveSearchPageRange(pageCount, pageRange) {
779
+ if (!pageRange)
780
+ return [0, pageCount - 1];
781
+ const [first, last] = pageRange;
782
+ assertPageIndex(first, pageCount);
783
+ assertPageIndex(last, pageCount);
784
+ return first <= last ? [first, last] : [last, first];
785
+ }
786
+ function assertPageIndex(pageIndex, pageCount) {
787
+ if (!Number.isInteger(pageIndex) || pageIndex < 0 || pageIndex >= pageCount)
788
+ throw new ViewerError("render-failed", "Page index is out of range", {
789
+ details: { pageIndex, pageCount },
790
+ });
791
+ }
792
+ function normalizeSheetViewport(range) {
793
+ return {
794
+ row: Math.max(1, Math.trunc(range.row)),
795
+ column: Math.max(1, Math.trunc(range.column)),
796
+ rowCount: Math.max(1, Math.trunc(range.rowCount)),
797
+ columnCount: Math.max(1, Math.trunc(range.columnCount)),
798
+ };
799
+ }
800
+ function normalizeTextSelectionRange(range) {
801
+ const forward = range.startPageIndex < range.endPageIndex ||
802
+ (range.startPageIndex === range.endPageIndex &&
803
+ range.startOffset <= range.endOffset);
804
+ return forward
805
+ ? {
806
+ startPageIndex: Math.trunc(range.startPageIndex),
807
+ startOffset: Math.max(0, Math.trunc(range.startOffset)),
808
+ endPageIndex: Math.trunc(range.endPageIndex),
809
+ endOffset: Math.max(0, Math.trunc(range.endOffset)),
810
+ }
811
+ : {
812
+ startPageIndex: Math.trunc(range.endPageIndex),
813
+ startOffset: Math.max(0, Math.trunc(range.endOffset)),
814
+ endPageIndex: Math.trunc(range.startPageIndex),
815
+ endOffset: Math.max(0, Math.trunc(range.startOffset)),
816
+ };
817
+ }
818
+ function sliceTextRuns(runs, start, end) {
819
+ const selected = [];
820
+ let offset = 0;
821
+ for (const run of runs) {
822
+ const runStart = offset;
823
+ const runEnd = offset + run.text.length;
824
+ offset = runEnd;
825
+ const sliceStart = Math.max(start, runStart);
826
+ const sliceEnd = Math.min(end, runEnd);
827
+ if (sliceStart >= sliceEnd || run.text.length === 0)
828
+ continue;
829
+ const localStart = sliceStart - runStart;
830
+ const localEnd = sliceEnd - runStart;
831
+ const fractionStart = localStart / run.text.length;
832
+ const fractionWidth = (localEnd - localStart) / run.text.length;
833
+ selected.push({
834
+ ...run,
835
+ text: run.text.slice(localStart, localEnd),
836
+ x: run.x + run.width * fractionStart,
837
+ width: run.width * fractionWidth,
838
+ });
839
+ }
840
+ return selected;
841
+ }
842
+ function expandMergedRange(range, info) {
843
+ const sheet = info.sheets?.[range.sheetIndex];
844
+ if (!sheet)
845
+ return range;
846
+ let result = range;
847
+ let changed = true;
848
+ while (changed) {
849
+ changed = false;
850
+ for (const merged of sheet.mergedRanges) {
851
+ if (merged.endRow < result.startRow ||
852
+ merged.startRow > result.endRow ||
853
+ merged.endColumn < result.startColumn ||
854
+ merged.startColumn > result.endColumn)
855
+ continue;
856
+ const expanded = {
857
+ ...result,
858
+ startRow: Math.min(result.startRow, merged.startRow),
859
+ startColumn: Math.min(result.startColumn, merged.startColumn),
860
+ endRow: Math.max(result.endRow, merged.endRow),
861
+ endColumn: Math.max(result.endColumn, merged.endColumn),
862
+ };
863
+ changed =
864
+ expanded.startRow !== result.startRow ||
865
+ expanded.startColumn !== result.startColumn ||
866
+ expanded.endRow !== result.endRow ||
867
+ expanded.endColumn !== result.endColumn;
868
+ result = expanded;
869
+ }
870
+ }
871
+ return result;
872
+ }
873
+ function cellSelectionToTsv(selection, runs) {
874
+ const cells = new Map();
875
+ for (const run of runs)
876
+ if (run.row !== undefined && run.column !== undefined)
877
+ cells.set(`${run.row}:${run.column}`, run.text);
878
+ return "ranges" in selection
879
+ ? cellRangesToTsv(selection.ranges, cells)
880
+ : cellRangeToTsv(selection, cells);
881
+ }
882
+ function freezeState(state) {
883
+ return Object.freeze(state);
884
+ }
885
+ function immutableInfo(info) {
886
+ return deepFreeze(structuredClone(info));
887
+ }
888
+ function immutableSearchResult(result) {
889
+ return Object.freeze({
890
+ ...result,
891
+ matches: Object.freeze(result.matches.map((match) => Object.freeze({ ...match }))),
892
+ });
893
+ }
894
+ function deepFreeze(value) {
895
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
896
+ Object.freeze(value);
897
+ for (const child of Object.values(value))
898
+ deepFreeze(child);
899
+ }
900
+ return value;
901
+ }