omni-viewer-core 0.1.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 (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/THIRD_PARTY_NOTICES.md +49 -0
  4. package/dist/assets/audio-engine/audio_engine.mjs +2 -0
  5. package/dist/assets/audio-engine/audio_engine.wasm +0 -0
  6. package/dist/assets/pdfjs/pdf.worker.min.mjs +21 -0
  7. package/dist/host/index.d.ts +133 -0
  8. package/dist/host/index.js +10 -0
  9. package/dist/i18n/catalog.en.d.ts +1 -0
  10. package/dist/i18n/catalog.en.js +411 -0
  11. package/dist/i18n/catalog.ko.d.ts +1 -0
  12. package/dist/i18n/catalog.ko.js +68 -0
  13. package/dist/i18n/index.d.ts +18 -0
  14. package/dist/i18n/index.js +41 -0
  15. package/dist/licenses/emscripten.txt +101 -0
  16. package/dist/licenses/kissfft.txt +28 -0
  17. package/dist/licenses/pdfjs-dist.txt +177 -0
  18. package/dist/parsers/a2l/index.d.ts +1 -0
  19. package/dist/parsers/a2l/index.js +1 -0
  20. package/dist/parsers/archive/index.d.ts +22 -0
  21. package/dist/parsers/archive/index.js +46 -0
  22. package/dist/parsers/archive/model.d.ts +29 -0
  23. package/dist/parsers/archive/model.js +1 -0
  24. package/dist/parsers/archive/worker.d.ts +21 -0
  25. package/dist/parsers/archive/worker.js +1 -0
  26. package/dist/parsers/arxml/index.d.ts +1 -0
  27. package/dist/parsers/arxml/index.js +1 -0
  28. package/dist/parsers/asc/index.d.ts +1 -0
  29. package/dist/parsers/asc/index.js +1 -0
  30. package/dist/parsers/audio/index.d.ts +9 -0
  31. package/dist/parsers/audio/index.js +46 -0
  32. package/dist/parsers/automotive/index.d.ts +33 -0
  33. package/dist/parsers/automotive/index.js +973 -0
  34. package/dist/parsers/blf/index.d.ts +1 -0
  35. package/dist/parsers/blf/index.js +1 -0
  36. package/dist/parsers/csv/delimiter.d.ts +31 -0
  37. package/dist/parsers/csv/delimiter.js +151 -0
  38. package/dist/parsers/csv/index.d.ts +30 -0
  39. package/dist/parsers/csv/index.js +108 -0
  40. package/dist/parsers/csv/parseText.d.ts +20 -0
  41. package/dist/parsers/csv/parseText.js +108 -0
  42. package/dist/parsers/csv/sort.d.ts +26 -0
  43. package/dist/parsers/csv/sort.js +224 -0
  44. package/dist/parsers/csv/statistics.d.ts +49 -0
  45. package/dist/parsers/csv/statistics.js +150 -0
  46. package/dist/parsers/dbc/index.d.ts +56 -0
  47. package/dist/parsers/dbc/index.js +94 -0
  48. package/dist/parsers/doc-binary/index.d.ts +35 -0
  49. package/dist/parsers/doc-binary/index.js +267 -0
  50. package/dist/parsers/doc-binary/vscode-parser.d.ts +142 -0
  51. package/dist/parsers/doc-binary/vscode-parser.js +3747 -0
  52. package/dist/parsers/excel/index.d.ts +17 -0
  53. package/dist/parsers/excel/index.js +406 -0
  54. package/dist/parsers/excel/model.d.ts +80 -0
  55. package/dist/parsers/excel/model.js +48 -0
  56. package/dist/parsers/excel/serialize.d.ts +3 -0
  57. package/dist/parsers/excel/serialize.js +78 -0
  58. package/dist/parsers/hdf5/index.d.ts +75 -0
  59. package/dist/parsers/hdf5/index.js +658 -0
  60. package/dist/parsers/hdf5/node.d.ts +21 -0
  61. package/dist/parsers/hdf5/node.js +95 -0
  62. package/dist/parsers/json/index.d.ts +15 -0
  63. package/dist/parsers/json/index.js +102 -0
  64. package/dist/parsers/json/model.d.ts +42 -0
  65. package/dist/parsers/json/model.js +140 -0
  66. package/dist/parsers/json/parse.d.ts +22 -0
  67. package/dist/parsers/json/parse.js +279 -0
  68. package/dist/parsers/json/tokenizer.d.ts +17 -0
  69. package/dist/parsers/json/tokenizer.js +175 -0
  70. package/dist/parsers/jsonl/index.d.ts +14 -0
  71. package/dist/parsers/jsonl/index.js +18 -0
  72. package/dist/parsers/jsonl/model.d.ts +23 -0
  73. package/dist/parsers/jsonl/model.js +1 -0
  74. package/dist/parsers/jsonl/parse.d.ts +7 -0
  75. package/dist/parsers/jsonl/parse.js +34 -0
  76. package/dist/parsers/markdown/index.d.ts +37 -0
  77. package/dist/parsers/markdown/index.js +59 -0
  78. package/dist/parsers/mat/index.d.ts +31 -0
  79. package/dist/parsers/mat/index.js +426 -0
  80. package/dist/parsers/mermaid/index.d.ts +5 -0
  81. package/dist/parsers/mermaid/index.js +3 -0
  82. package/dist/parsers/mf4/index.d.ts +1 -0
  83. package/dist/parsers/mf4/index.js +1 -0
  84. package/dist/parsers/parquet/index.d.ts +21 -0
  85. package/dist/parsers/parquet/index.js +68 -0
  86. package/dist/parsers/pcap/index.d.ts +1 -0
  87. package/dist/parsers/pcap/index.js +1 -0
  88. package/dist/parsers/pcapng/index.d.ts +1 -0
  89. package/dist/parsers/pcapng/index.js +1 -0
  90. package/dist/parsers/plantuml/index.d.ts +5 -0
  91. package/dist/parsers/plantuml/index.js +4 -0
  92. package/dist/parsers/ppt-binary/index.d.ts +5 -0
  93. package/dist/parsers/ppt-binary/index.js +62 -0
  94. package/dist/parsers/ppt-binary/pptBinaryBuildContext.d.ts +12 -0
  95. package/dist/parsers/ppt-binary/pptBinaryBuildContext.js +40 -0
  96. package/dist/parsers/ppt-binary/pptBinaryContainer.d.ts +4 -0
  97. package/dist/parsers/ppt-binary/pptBinaryContainer.js +174 -0
  98. package/dist/parsers/ppt-binary/pptBinaryTypes.d.ts +125 -0
  99. package/dist/parsers/ppt-binary/pptBinaryTypes.js +1 -0
  100. package/dist/parsers/ppt-binary/pptSlideLayouts.d.ts +9 -0
  101. package/dist/parsers/ppt-binary/pptSlideLayouts.js +510 -0
  102. package/dist/parsers/ppt-binary/vscode-parser.d.ts +116 -0
  103. package/dist/parsers/ppt-binary/vscode-parser.js +2853 -0
  104. package/dist/parsers/ppt-binary/vscode.d.ts +4 -0
  105. package/dist/parsers/ppt-binary/vscode.js +12 -0
  106. package/dist/parsers/pptx/index.d.ts +15 -0
  107. package/dist/parsers/pptx/index.js +88 -0
  108. package/dist/parsers/pptx/vscode-parser.d.ts +167 -0
  109. package/dist/parsers/pptx/vscode-parser.js +1503 -0
  110. package/dist/parsers/pptx/vscode.d.ts +4 -0
  111. package/dist/parsers/pptx/vscode.js +18 -0
  112. package/dist/parsers/pptx/zip-reader.d.ts +3 -0
  113. package/dist/parsers/pptx/zip-reader.js +20 -0
  114. package/dist/parsers/proto/index.d.ts +90 -0
  115. package/dist/parsers/proto/index.js +197 -0
  116. package/dist/parsers/psd/index.d.ts +16 -0
  117. package/dist/parsers/psd/index.js +10 -0
  118. package/dist/parsers/shapefile/dbf.d.ts +23 -0
  119. package/dist/parsers/shapefile/dbf.js +112 -0
  120. package/dist/parsers/shapefile/index.d.ts +44 -0
  121. package/dist/parsers/shapefile/index.js +119 -0
  122. package/dist/parsers/shapefile/reproject.d.ts +10 -0
  123. package/dist/parsers/shapefile/reproject.js +41 -0
  124. package/dist/parsers/slide-model.d.ts +106 -0
  125. package/dist/parsers/slide-model.js +1 -0
  126. package/dist/parsers/toml/index.d.ts +15 -0
  127. package/dist/parsers/toml/index.js +18 -0
  128. package/dist/parsers/toml/model.d.ts +15 -0
  129. package/dist/parsers/toml/model.js +1 -0
  130. package/dist/parsers/toml/parse.d.ts +16 -0
  131. package/dist/parsers/toml/parse.js +266 -0
  132. package/dist/parsers/types.d.ts +103 -0
  133. package/dist/parsers/types.js +106 -0
  134. package/dist/parsers/video/index.d.ts +6 -0
  135. package/dist/parsers/video/index.js +2 -0
  136. package/dist/parsers/yaml/index.d.ts +16 -0
  137. package/dist/parsers/yaml/index.js +58 -0
  138. package/dist/parsers/yaml/model.d.ts +22 -0
  139. package/dist/parsers/yaml/model.js +1 -0
  140. package/dist/parsers/yaml/self-loading.d.ts +3 -0
  141. package/dist/parsers/yaml/self-loading.js +19 -0
  142. package/dist/parsers/zip-scan.d.ts +8 -0
  143. package/dist/parsers/zip-scan.js +80 -0
  144. package/dist/registry/container.d.ts +17 -0
  145. package/dist/registry/container.js +49 -0
  146. package/dist/registry/index.d.ts +133 -0
  147. package/dist/registry/index.js +348 -0
  148. package/dist/registry/probe.d.ts +3 -0
  149. package/dist/registry/probe.js +177 -0
  150. package/dist/registry/sniff.d.ts +17 -0
  151. package/dist/registry/sniff.js +57 -0
  152. package/dist/styles/archive.css +10 -0
  153. package/dist/styles/audio.css +66 -0
  154. package/dist/styles/automotive.css +1 -0
  155. package/dist/styles/csv.css +262 -0
  156. package/dist/styles/excel.css +212 -0
  157. package/dist/styles/fallback.css +48 -0
  158. package/dist/styles/hdf5.css +3 -0
  159. package/dist/styles/hwp.css +12 -0
  160. package/dist/styles/image.css +115 -0
  161. package/dist/styles/json.css +342 -0
  162. package/dist/styles/jsonl.css +1 -0
  163. package/dist/styles/markdown.css +10 -0
  164. package/dist/styles/mat.css +2 -0
  165. package/dist/styles/mermaid.css +1 -0
  166. package/dist/styles/parquet.css +2 -0
  167. package/dist/styles/pdf.css +551 -0
  168. package/dist/styles/plantuml.css +1 -0
  169. package/dist/styles/ppt.css +1 -0
  170. package/dist/styles/proto.css +2 -0
  171. package/dist/styles/psd.css +1 -0
  172. package/dist/styles/shapefile.css +25 -0
  173. package/dist/styles/toml.css +1 -0
  174. package/dist/styles/video.css +74 -0
  175. package/dist/styles/word.css +685 -0
  176. package/dist/styles/yaml.css +1 -0
  177. package/dist/viewers/a2l/index.d.ts +15 -0
  178. package/dist/viewers/a2l/index.js +5 -0
  179. package/dist/viewers/archive/archive-preview-decoder.d.ts +4 -0
  180. package/dist/viewers/archive/archive-preview-decoder.js +223 -0
  181. package/dist/viewers/archive/controller.d.ts +24 -0
  182. package/dist/viewers/archive/controller.js +18 -0
  183. package/dist/viewers/archive/index.d.ts +25 -0
  184. package/dist/viewers/archive/index.js +230 -0
  185. package/dist/viewers/archive/preview.d.ts +2 -0
  186. package/dist/viewers/archive/preview.js +2 -0
  187. package/dist/viewers/archive/styles.d.ts +1 -0
  188. package/dist/viewers/archive/styles.js +11 -0
  189. package/dist/viewers/arxml/index.d.ts +15 -0
  190. package/dist/viewers/arxml/index.js +5 -0
  191. package/dist/viewers/asc/index.d.ts +15 -0
  192. package/dist/viewers/asc/index.js +5 -0
  193. package/dist/viewers/audio/controller.d.ts +33 -0
  194. package/dist/viewers/audio/controller.js +49 -0
  195. package/dist/viewers/audio/engine.d.ts +44 -0
  196. package/dist/viewers/audio/engine.js +108 -0
  197. package/dist/viewers/audio/index.d.ts +92 -0
  198. package/dist/viewers/audio/index.js +448 -0
  199. package/dist/viewers/audio/self-loading.d.ts +7 -0
  200. package/dist/viewers/audio/self-loading.js +42 -0
  201. package/dist/viewers/audio/styles.d.ts +1 -0
  202. package/dist/viewers/audio/styles.js +73 -0
  203. package/dist/viewers/automotive/index.d.ts +8 -0
  204. package/dist/viewers/automotive/index.js +152 -0
  205. package/dist/viewers/automotive/styles.d.ts +1 -0
  206. package/dist/viewers/automotive/styles.js +1 -0
  207. package/dist/viewers/avro/index.d.ts +15 -0
  208. package/dist/viewers/avro/index.js +5 -0
  209. package/dist/viewers/bag/index.d.ts +15 -0
  210. package/dist/viewers/bag/index.js +5 -0
  211. package/dist/viewers/blf/index.d.ts +15 -0
  212. package/dist/viewers/blf/index.js +5 -0
  213. package/dist/viewers/csv/controller.d.ts +126 -0
  214. package/dist/viewers/csv/controller.js +598 -0
  215. package/dist/viewers/csv/index.d.ts +48 -0
  216. package/dist/viewers/csv/index.js +846 -0
  217. package/dist/viewers/csv/styles.d.ts +1 -0
  218. package/dist/viewers/csv/styles.js +267 -0
  219. package/dist/viewers/db3/index.d.ts +15 -0
  220. package/dist/viewers/db3/index.js +5 -0
  221. package/dist/viewers/dbc/index.d.ts +15 -0
  222. package/dist/viewers/dbc/index.js +5 -0
  223. package/dist/viewers/diagram.d.ts +14 -0
  224. package/dist/viewers/diagram.js +95 -0
  225. package/dist/viewers/excel/controller.d.ts +108 -0
  226. package/dist/viewers/excel/controller.js +548 -0
  227. package/dist/viewers/excel/grid.d.ts +28 -0
  228. package/dist/viewers/excel/grid.js +99 -0
  229. package/dist/viewers/excel/index.d.ts +37 -0
  230. package/dist/viewers/excel/index.js +620 -0
  231. package/dist/viewers/excel/self-loading.d.ts +6 -0
  232. package/dist/viewers/excel/self-loading.js +13 -0
  233. package/dist/viewers/excel/styles.d.ts +1 -0
  234. package/dist/viewers/excel/styles.js +216 -0
  235. package/dist/viewers/fallback/index.d.ts +17 -0
  236. package/dist/viewers/fallback/index.js +130 -0
  237. package/dist/viewers/fallback/styles.d.ts +1 -0
  238. package/dist/viewers/fallback/styles.js +49 -0
  239. package/dist/viewers/hdf5/index.d.ts +19 -0
  240. package/dist/viewers/hdf5/index.js +170 -0
  241. package/dist/viewers/hdf5/styles.d.ts +1 -0
  242. package/dist/viewers/hdf5/styles.js +4 -0
  243. package/dist/viewers/hwp/controller.d.ts +19 -0
  244. package/dist/viewers/hwp/controller.js +22 -0
  245. package/dist/viewers/hwp/index.d.ts +39 -0
  246. package/dist/viewers/hwp/index.js +271 -0
  247. package/dist/viewers/hwp/self-loading.d.ts +2 -0
  248. package/dist/viewers/hwp/self-loading.js +6 -0
  249. package/dist/viewers/hwp/styles.d.ts +1 -0
  250. package/dist/viewers/hwp/styles.js +13 -0
  251. package/dist/viewers/image/controller.d.ts +210 -0
  252. package/dist/viewers/image/controller.js +336 -0
  253. package/dist/viewers/image/decode.d.ts +54 -0
  254. package/dist/viewers/image/decode.js +150 -0
  255. package/dist/viewers/image/index.d.ts +38 -0
  256. package/dist/viewers/image/index.js +749 -0
  257. package/dist/viewers/image/limits.d.ts +18 -0
  258. package/dist/viewers/image/limits.js +20 -0
  259. package/dist/viewers/image/styles.d.ts +1 -0
  260. package/dist/viewers/image/styles.js +119 -0
  261. package/dist/viewers/json/controller.d.ts +89 -0
  262. package/dist/viewers/json/controller.js +411 -0
  263. package/dist/viewers/json/index.d.ts +25 -0
  264. package/dist/viewers/json/index.js +503 -0
  265. package/dist/viewers/json/styles.d.ts +1 -0
  266. package/dist/viewers/json/styles.js +346 -0
  267. package/dist/viewers/json/transforms.d.ts +27 -0
  268. package/dist/viewers/json/transforms.js +253 -0
  269. package/dist/viewers/jsonl/controller.d.ts +48 -0
  270. package/dist/viewers/jsonl/controller.js +136 -0
  271. package/dist/viewers/jsonl/index.d.ts +22 -0
  272. package/dist/viewers/jsonl/index.js +184 -0
  273. package/dist/viewers/jsonl/styles.d.ts +1 -0
  274. package/dist/viewers/jsonl/styles.js +1 -0
  275. package/dist/viewers/markdown/controller.d.ts +50 -0
  276. package/dist/viewers/markdown/controller.js +62 -0
  277. package/dist/viewers/markdown/index.d.ts +64 -0
  278. package/dist/viewers/markdown/index.js +425 -0
  279. package/dist/viewers/markdown/math.d.ts +21 -0
  280. package/dist/viewers/markdown/math.js +100 -0
  281. package/dist/viewers/markdown/self-loading.d.ts +5 -0
  282. package/dist/viewers/markdown/self-loading.js +48 -0
  283. package/dist/viewers/markdown/styles.d.ts +1 -0
  284. package/dist/viewers/markdown/styles.js +11 -0
  285. package/dist/viewers/mat/index.d.ts +19 -0
  286. package/dist/viewers/mat/index.js +113 -0
  287. package/dist/viewers/mat/styles.d.ts +1 -0
  288. package/dist/viewers/mat/styles.js +3 -0
  289. package/dist/viewers/media.d.ts +9 -0
  290. package/dist/viewers/media.js +77 -0
  291. package/dist/viewers/mermaid/index.d.ts +17 -0
  292. package/dist/viewers/mermaid/index.js +6 -0
  293. package/dist/viewers/mermaid/self-loading.d.ts +2 -0
  294. package/dist/viewers/mermaid/self-loading.js +2 -0
  295. package/dist/viewers/mf4/index.d.ts +15 -0
  296. package/dist/viewers/mf4/index.js +5 -0
  297. package/dist/viewers/parquet/controller.d.ts +37 -0
  298. package/dist/viewers/parquet/controller.js +26 -0
  299. package/dist/viewers/parquet/index.d.ts +23 -0
  300. package/dist/viewers/parquet/index.js +134 -0
  301. package/dist/viewers/parquet/styles.d.ts +1 -0
  302. package/dist/viewers/parquet/styles.js +3 -0
  303. package/dist/viewers/pcap/index.d.ts +15 -0
  304. package/dist/viewers/pcap/index.js +5 -0
  305. package/dist/viewers/pcapng/index.d.ts +15 -0
  306. package/dist/viewers/pcapng/index.js +5 -0
  307. package/dist/viewers/pdf/controller.d.ts +120 -0
  308. package/dist/viewers/pdf/controller.js +191 -0
  309. package/dist/viewers/pdf/editing.d.ts +26 -0
  310. package/dist/viewers/pdf/editing.js +265 -0
  311. package/dist/viewers/pdf/index.d.ts +88 -0
  312. package/dist/viewers/pdf/index.js +1400 -0
  313. package/dist/viewers/pdf/self-loading.d.ts +6 -0
  314. package/dist/viewers/pdf/self-loading.js +14 -0
  315. package/dist/viewers/pdf/styles.d.ts +1 -0
  316. package/dist/viewers/pdf/styles.js +555 -0
  317. package/dist/viewers/plantuml/index.d.ts +17 -0
  318. package/dist/viewers/plantuml/index.js +6 -0
  319. package/dist/viewers/plantuml/self-loading.d.ts +2 -0
  320. package/dist/viewers/plantuml/self-loading.js +2 -0
  321. package/dist/viewers/ppt/chart.d.ts +8 -0
  322. package/dist/viewers/ppt/chart.js +83 -0
  323. package/dist/viewers/ppt/controller.d.ts +34 -0
  324. package/dist/viewers/ppt/controller.js +27 -0
  325. package/dist/viewers/ppt/index.d.ts +33 -0
  326. package/dist/viewers/ppt/index.js +101 -0
  327. package/dist/viewers/ppt/render.d.ts +5 -0
  328. package/dist/viewers/ppt/render.js +144 -0
  329. package/dist/viewers/ppt/self-loading.d.ts +9 -0
  330. package/dist/viewers/ppt/self-loading.js +4 -0
  331. package/dist/viewers/ppt/styles.d.ts +1 -0
  332. package/dist/viewers/ppt/styles.js +1 -0
  333. package/dist/viewers/proto/index.d.ts +17 -0
  334. package/dist/viewers/proto/index.js +170 -0
  335. package/dist/viewers/proto/styles.d.ts +1 -0
  336. package/dist/viewers/proto/styles.js +2 -0
  337. package/dist/viewers/psd/index.d.ts +27 -0
  338. package/dist/viewers/psd/index.js +39 -0
  339. package/dist/viewers/psd/self-loading.d.ts +10 -0
  340. package/dist/viewers/psd/self-loading.js +20 -0
  341. package/dist/viewers/psd/styles.d.ts +1 -0
  342. package/dist/viewers/psd/styles.js +1 -0
  343. package/dist/viewers/reqif/index.d.ts +15 -0
  344. package/dist/viewers/reqif/index.js +5 -0
  345. package/dist/viewers/shapefile/index.d.ts +35 -0
  346. package/dist/viewers/shapefile/index.js +336 -0
  347. package/dist/viewers/shapefile/self-loading.d.ts +7 -0
  348. package/dist/viewers/shapefile/self-loading.js +32 -0
  349. package/dist/viewers/shapefile/styles.d.ts +1 -0
  350. package/dist/viewers/shapefile/styles.js +28 -0
  351. package/dist/viewers/stp/index.d.ts +15 -0
  352. package/dist/viewers/stp/index.js +5 -0
  353. package/dist/viewers/structured-styles.d.ts +1 -0
  354. package/dist/viewers/structured-styles.js +1 -0
  355. package/dist/viewers/structured.d.ts +36 -0
  356. package/dist/viewers/structured.js +138 -0
  357. package/dist/viewers/toml/controller.d.ts +38 -0
  358. package/dist/viewers/toml/controller.js +61 -0
  359. package/dist/viewers/toml/index.d.ts +18 -0
  360. package/dist/viewers/toml/index.js +34 -0
  361. package/dist/viewers/types.d.ts +36 -0
  362. package/dist/viewers/types.js +9 -0
  363. package/dist/viewers/video/controller.d.ts +29 -0
  364. package/dist/viewers/video/controller.js +54 -0
  365. package/dist/viewers/video/index.d.ts +18 -0
  366. package/dist/viewers/video/index.js +305 -0
  367. package/dist/viewers/video/styles.d.ts +1 -0
  368. package/dist/viewers/video/styles.js +79 -0
  369. package/dist/viewers/word/controller.d.ts +19 -0
  370. package/dist/viewers/word/controller.js +22 -0
  371. package/dist/viewers/word/docx-preprocess.d.ts +63 -0
  372. package/dist/viewers/word/docx-preprocess.js +136 -0
  373. package/dist/viewers/word/index.d.ts +32 -0
  374. package/dist/viewers/word/index.js +187 -0
  375. package/dist/viewers/word/normalize-docx.d.ts +2 -0
  376. package/dist/viewers/word/normalize-docx.js +50 -0
  377. package/dist/viewers/word/paginate.d.ts +1 -0
  378. package/dist/viewers/word/paginate.js +1035 -0
  379. package/dist/viewers/word/self-loading.d.ts +2 -0
  380. package/dist/viewers/word/self-loading.js +7 -0
  381. package/dist/viewers/word/styles.d.ts +1 -0
  382. package/dist/viewers/word/styles.js +686 -0
  383. package/dist/viewers/yaml/controller.d.ts +42 -0
  384. package/dist/viewers/yaml/controller.js +41 -0
  385. package/dist/viewers/yaml/index.d.ts +21 -0
  386. package/dist/viewers/yaml/index.js +20 -0
  387. package/package.json +375 -0
@@ -0,0 +1,37 @@
1
+ import type { ClipboardService, FileSaveService, HostContext } from '../../host/index.js';
2
+ import { type MountOptions, type ViewerHandle, type ViewerInput } from '../types.js';
3
+ import { type ResourceLimits } from '../../parsers/types.js';
4
+ import { type ExcelParseDeps } from '../../parsers/excel/index.js';
5
+ export { createExcelController, EXCEL_DEFAULT_PAGE_SIZE } from './controller.js';
6
+ export { buildGridView } from './grid.js';
7
+ export type { GridView, GridCell, GridRow } from './grid.js';
8
+ export type { ExcelController, ExcelViewState, ExcelAction, ExcelControllerOptions } from './controller.js';
9
+ export { excelViewerCss } from './styles.js';
10
+ /** Viewer metadata — single source for the registry codegen (DESIGN.md §7). */
11
+ export declare const EXCEL_VIEWER_META: {
12
+ id: string;
13
+ displayNameKey: string;
14
+ extensions: string[];
15
+ priority: number;
16
+ requiredServices: readonly [];
17
+ optionalServices: readonly ["clipboard", "save"];
18
+ inputOwnership: "consumes";
19
+ };
20
+ export type ExcelViewerContext = HostContext & {
21
+ clipboard?: ClipboardService;
22
+ save?: FileSaveService;
23
+ };
24
+ /** SheetJS module, injected by the adapter (ADR 14). Same shape the parser
25
+ * consumes, so the loaded module flows straight into parseExcel. */
26
+ export interface ExcelViewerDeps {
27
+ loadXlsx(): Promise<ExcelParseDeps['xlsx']>;
28
+ }
29
+ export interface ExcelMountOptions extends MountOptions {
30
+ /** Parser resource limits (docs/viewers/excel.md §4); adapters may tighten. */
31
+ limits?: ResourceLimits;
32
+ pageSize?: number;
33
+ }
34
+ export type ExcelViewerHandle = ViewerHandle;
35
+ /** Clipboard copy guard (docs/viewers/excel.md §3, X7): larger payloads refused. */
36
+ export declare const EXCEL_COPY_PAYLOAD_LIMIT_BYTES: number;
37
+ export declare function mountExcelViewer(input: ViewerInput, container: HTMLElement, ctx: ExcelViewerContext, deps: ExcelViewerDeps, options?: ExcelMountOptions): Promise<ExcelViewerHandle>;
@@ -0,0 +1,620 @@
1
+ // Excel viewer — DOM renderer consuming ExcelController (DESIGN.md §3-②,
2
+ // docs/viewers/excel.md §3).
3
+ //
4
+ // Base entry rule (ADR 14): no runtime `import 'xlsx'` here. SheetJS is
5
+ // injected through `ExcelViewerDeps.loadXlsx`; `viewers/excel/self-loading`
6
+ // supplies the dynamic-import loader. If loading fails the viewer renders a
7
+ // visible missing-dependency reason (degraded, ADR 24) — never a blank frame.
8
+ //
9
+ // CSP rules: no eval, no inline handlers, no innerHTML — createElement /
10
+ // textContent only. Mount is async and renders inside a shadow root by default
11
+ // (§6 reverse-contamination contract).
12
+ //
13
+ // Optional services: `clipboard`. Without it the copy buttons render disabled
14
+ // with an explanatory tooltip (degraded mode, ADR 24) — never hidden.
15
+ import { MountAbortedError, VIEWER_ROOT_CLASS } from '../types.js';
16
+ import { utf8ByteLength } from '../../parsers/types.js';
17
+ import { parseExcel, serializeWorkbook } from '../../parsers/excel/index.js';
18
+ import { createExcelController } from './controller.js';
19
+ import { excelViewerCss } from './styles.js';
20
+ export { createExcelController, EXCEL_DEFAULT_PAGE_SIZE } from './controller.js';
21
+ export { buildGridView } from './grid.js';
22
+ export { excelViewerCss } from './styles.js';
23
+ /** Viewer metadata — single source for the registry codegen (DESIGN.md §7). */
24
+ export const EXCEL_VIEWER_META = {
25
+ id: 'excel',
26
+ displayNameKey: 'excel.tableView',
27
+ extensions: ['xlsx', 'xlsm', 'xlsb', 'ods', 'xls'],
28
+ priority: 15,
29
+ requiredServices: [],
30
+ optionalServices: ['clipboard', 'save'],
31
+ inputOwnership: 'consumes'
32
+ };
33
+ /** Clipboard copy guard (docs/viewers/excel.md §3, X7): larger payloads refused. */
34
+ export const EXCEL_COPY_PAYLOAD_LIMIT_BYTES = 1024 * 1024;
35
+ const EXCEL_MIME_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
36
+ const MIN_COLUMN_WIDTH = 40;
37
+ const FALLBACK_COLUMN_WIDTH = 120;
38
+ /** Header single-click sort is deferred briefly so a double-click can win and
39
+ * open the rename editor instead (matches the CSV viewer). */
40
+ const SORT_CLICK_DELAY_MS = 250;
41
+ export async function mountExcelViewer(input, container, ctx, deps, options = {}) {
42
+ if (options.signal?.aborted)
43
+ throw new MountAbortedError();
44
+ // Load SheetJS + parse (both async) before we own any DOM.
45
+ let result;
46
+ let xlsx = null;
47
+ try {
48
+ xlsx = await deps.loadXlsx();
49
+ if (options.signal?.aborted)
50
+ throw new MountAbortedError();
51
+ const parseOptions = options.limits !== undefined ? { limits: options.limits } : {};
52
+ result = parseExcel(input.data, { xlsx }, parseOptions).result;
53
+ }
54
+ catch (err) {
55
+ if (err instanceof MountAbortedError)
56
+ throw err;
57
+ ctx.logger.log('error', `excel: xlsx load failed: ${String(err)}`);
58
+ // Missing dependency is a visible, uniform degraded state (ADR 24) —
59
+ // the adapter's fallback chain (§7) sits above this.
60
+ result = {
61
+ status: 'failed',
62
+ failure: {
63
+ code: 'missing-dependency',
64
+ retryable: false,
65
+ messageKey: 'diag.excel.missing-dependency'
66
+ },
67
+ diagnostics: []
68
+ };
69
+ }
70
+ const controllerOptions = options.pageSize !== undefined ? { pageSize: options.pageSize } : {};
71
+ const controller = createExcelController(result, controllerOptions);
72
+ const isolation = options.styleIsolation ?? 'shadow';
73
+ let root;
74
+ if (isolation === 'shadow' && typeof container.attachShadow === 'function') {
75
+ root = container.shadowRoot ?? container.attachShadow({ mode: 'open' });
76
+ const style = document.createElement('style');
77
+ style.textContent = excelViewerCss;
78
+ root.appendChild(style);
79
+ }
80
+ else {
81
+ container.classList.add(VIEWER_ROOT_CLASS, 'omni-viewer--excel');
82
+ root = container;
83
+ }
84
+ const t = ctx.i18n.t.bind(ctx.i18n);
85
+ const disposers = [];
86
+ let toastTimer = null;
87
+ /** Session-scoped widths for the displayed sheet; null means auto width. */
88
+ let columnWidths = null;
89
+ let activeResizeCleanup = null;
90
+ let pendingSortTimer = null;
91
+ let contextMenuCleanup = null;
92
+ const el = (tag, className, text) => {
93
+ const node = document.createElement(tag);
94
+ if (className)
95
+ node.className = className;
96
+ if (text !== undefined)
97
+ node.textContent = text;
98
+ return node;
99
+ };
100
+ const on = (target, type, handler) => {
101
+ target.addEventListener(type, handler);
102
+ disposers.push(() => target.removeEventListener(type, handler));
103
+ };
104
+ // --- static frame -------------------------------------------------------
105
+ const frame = el('div', 'omni-excel');
106
+ frame.style.position = 'relative';
107
+ const toolbar = el('div', 'omni-excel__toolbar');
108
+ const sheetLabel = el('label', undefined, t('excel.sheet'));
109
+ const sheetSelect = el('select');
110
+ sheetSelect.setAttribute('aria-label', t('excel.sheet'));
111
+ sheetLabel.appendChild(sheetSelect);
112
+ on(sheetSelect, 'change', () => controller.dispatch({ type: 'switch-sheet', index: Number(sheetSelect.value) }));
113
+ const searchInput = el('input', 'omni-excel__search');
114
+ searchInput.type = 'search';
115
+ searchInput.placeholder = t('excel.search');
116
+ searchInput.setAttribute('aria-label', t('excel.search'));
117
+ on(searchInput, 'input', () => controller.dispatch({ type: 'set-search', search: searchInput.value }));
118
+ // Three view modes (X3): Table (editable data), Grid (read-only WYSIWYG),
119
+ // Raw (JSON). A select keeps all three reachable in one control.
120
+ const viewModeSelect = el('select');
121
+ viewModeSelect.setAttribute('aria-label', t('excel.viewMode'));
122
+ for (const [value, key] of [
123
+ ['table', 'excel.tableViewLabel'],
124
+ ['grid', 'excel.gridView'],
125
+ ['raw', 'excel.rawView']
126
+ ]) {
127
+ const opt = el('option', undefined, t(key));
128
+ opt.value = value;
129
+ viewModeSelect.appendChild(opt);
130
+ }
131
+ on(viewModeSelect, 'change', () => controller.dispatch({
132
+ type: 'set-view-mode',
133
+ mode: viewModeSelect.value
134
+ }));
135
+ const copyTsvBtn = el('button', undefined, t('excel.copyTsv'));
136
+ copyTsvBtn.type = 'button';
137
+ const copyJsonBtn = el('button', undefined, t('excel.copyJson'));
138
+ copyJsonBtn.type = 'button';
139
+ const clipboard = ctx.clipboard;
140
+ if (clipboard) {
141
+ on(copyTsvBtn, 'click', () => void copy(clipboard, controller.toTsv()));
142
+ on(copyJsonBtn, 'click', () => void copy(clipboard, controller.toJson()));
143
+ }
144
+ else {
145
+ for (const btn of [copyTsvBtn, copyJsonBtn]) {
146
+ btn.disabled = true;
147
+ btn.title = t('common.noClipboard');
148
+ }
149
+ }
150
+ // Export re-serializes the original parsed model with cell types preserved
151
+ // (parsers/excel serializeWorkbook), not the display strings — so numbers,
152
+ // dates, and booleans survive the round-trip. Read-only: this is save-as, no
153
+ // editing / writeback (docs/viewers/excel.md §1, X7).
154
+ const exportBtn = el('button', undefined, t('excel.export'));
155
+ exportBtn.type = 'button';
156
+ const save = ctx.save;
157
+ if (!save || !xlsx) {
158
+ // Degraded mode (ADR 24): export needs both a save service and SheetJS.
159
+ exportBtn.disabled = true;
160
+ exportBtn.title = t('common.noFileSave');
161
+ }
162
+ else {
163
+ on(exportBtn, 'click', () => void exportWorkbook(save));
164
+ }
165
+ function exportFileName(fileName) {
166
+ const stem = fileName.replace(/\.[^./\\]+$/, '') || 'spreadsheet';
167
+ return `${stem}.xlsx`;
168
+ }
169
+ async function exportWorkbook(service) {
170
+ if (!xlsx || controller.state.status === 'failed')
171
+ return;
172
+ try {
173
+ const data = serializeWorkbook(controller.getWorkbook(), xlsx);
174
+ const name = exportFileName(input.fileName);
175
+ await service.saveFile(name, data, EXCEL_MIME_TYPE);
176
+ // Exported bytes now match the in-session edits — clear the dirty flag.
177
+ controller.markSaved();
178
+ showToast(t('common.saved', { name }));
179
+ }
180
+ catch (error) {
181
+ ctx.logger.log('error', `excel export failed: ${String(error)}`);
182
+ showToast(t('common.saveFailed'));
183
+ }
184
+ }
185
+ // Editing controls (X-편집): shown once editing has started (docs §3).
186
+ const undoBtn = el('button', undefined, '↶');
187
+ undoBtn.type = 'button';
188
+ undoBtn.setAttribute('aria-label', t('excel.undo'));
189
+ on(undoBtn, 'click', () => controller.dispatch({ type: 'undo' }));
190
+ const redoBtn = el('button', undefined, '↷');
191
+ redoBtn.type = 'button';
192
+ redoBtn.setAttribute('aria-label', t('excel.redo'));
193
+ on(redoBtn, 'click', () => controller.dispatch({ type: 'redo' }));
194
+ const dirtyBadge = el('span', 'omni-excel__dirty');
195
+ const meta = el('span', 'omni-excel__meta');
196
+ toolbar.append(sheetLabel, searchInput, viewModeSelect, undoBtn, redoBtn, copyTsvBtn, copyJsonBtn, exportBtn, el('span', 'omni-excel__spacer'), dirtyBadge, meta);
197
+ const diagnosticsBar = el('div', 'omni-excel__diagnostics');
198
+ const body = el('div', 'omni-excel__body');
199
+ const footer = el('div', 'omni-excel__footer');
200
+ const prevBtn = el('button', undefined, '‹');
201
+ prevBtn.type = 'button';
202
+ prevBtn.setAttribute('aria-label', t('common.prevPage'));
203
+ const nextBtn = el('button', undefined, '›');
204
+ nextBtn.type = 'button';
205
+ nextBtn.setAttribute('aria-label', t('common.nextPage'));
206
+ const pageInfo = el('span', 'omni-excel__meta');
207
+ on(prevBtn, 'click', () => controller.dispatch({ type: 'prev-page' }));
208
+ on(nextBtn, 'click', () => controller.dispatch({ type: 'next-page' }));
209
+ footer.append(prevBtn, pageInfo, nextBtn);
210
+ frame.append(toolbar, diagnosticsBar, body, footer);
211
+ root.appendChild(frame);
212
+ function showToast(message) {
213
+ frame.querySelector('.omni-excel__toast')?.remove();
214
+ const toast = el('div', 'omni-excel__toast', message);
215
+ frame.appendChild(toast);
216
+ if (toastTimer)
217
+ clearTimeout(toastTimer);
218
+ toastTimer = setTimeout(() => toast.remove(), 1500);
219
+ }
220
+ async function copy(service, payload) {
221
+ const payloadBytes = utf8ByteLength(payload);
222
+ if (payloadBytes > EXCEL_COPY_PAYLOAD_LIMIT_BYTES) {
223
+ showToast(t('common.copyTooLarge', { size: payloadBytes }));
224
+ return;
225
+ }
226
+ try {
227
+ await service.writeText(payload);
228
+ showToast(t('common.copied'));
229
+ }
230
+ catch (error) {
231
+ ctx.logger.log('error', `excel copy failed: ${String(error)}`);
232
+ }
233
+ }
234
+ function closeContextMenu() {
235
+ contextMenuCleanup?.();
236
+ contextMenuCleanup = null;
237
+ }
238
+ /** Right-click row menu: insert below / delete (docs §3, CSV parity). */
239
+ function openRowContextMenu(event, rowId) {
240
+ closeContextMenu();
241
+ const menu = el('div', 'omni-excel__menu');
242
+ menu.setAttribute('role', 'menu');
243
+ const item = (label, action) => {
244
+ const btn = el('button', undefined, label);
245
+ btn.type = 'button';
246
+ btn.setAttribute('role', 'menuitem');
247
+ btn.addEventListener('click', () => {
248
+ closeContextMenu();
249
+ action();
250
+ });
251
+ menu.appendChild(btn);
252
+ };
253
+ item(t('excel.insertRowBelow'), () => controller.dispatch({ type: 'insert-row', afterRowId: rowId }));
254
+ item(t('excel.deleteRow'), () => controller.dispatch({ type: 'delete-row', rowId }));
255
+ const frameRect = frame.getBoundingClientRect();
256
+ menu.style.left = `${event.clientX - frameRect.left}px`;
257
+ menu.style.top = `${event.clientY - frameRect.top}px`;
258
+ frame.appendChild(menu);
259
+ // Events crossing the shadow boundary retarget to the host, so use
260
+ // composedPath to detect clicks inside the menu.
261
+ const onOutside = (e) => {
262
+ if (e.composedPath().includes(menu))
263
+ return;
264
+ closeContextMenu();
265
+ };
266
+ const onKey = (e) => {
267
+ if (e.key === 'Escape')
268
+ closeContextMenu();
269
+ };
270
+ window.addEventListener('pointerdown', onOutside, true);
271
+ window.addEventListener('keydown', onKey, true);
272
+ contextMenuCleanup = () => {
273
+ window.removeEventListener('pointerdown', onOutside, true);
274
+ window.removeEventListener('keydown', onKey, true);
275
+ menu.remove();
276
+ };
277
+ }
278
+ /** Swap a cell's content for a text input; Enter/blur commits, Esc cancels. */
279
+ function startInlineEdit(cell, current, commit) {
280
+ const inputEl = document.createElement('input');
281
+ inputEl.type = 'text';
282
+ inputEl.className = 'omni-excel__cell-input';
283
+ inputEl.value = current;
284
+ let done = false;
285
+ const finish = (commitValue) => {
286
+ if (done)
287
+ return;
288
+ done = true;
289
+ if (commitValue && inputEl.value !== current)
290
+ commit(inputEl.value);
291
+ else
292
+ render(controller.state);
293
+ };
294
+ inputEl.addEventListener('keydown', (e) => {
295
+ e.stopPropagation(); // keep typing out of sort/undo shortcuts
296
+ if (e.key === 'Enter') {
297
+ e.preventDefault();
298
+ finish(true);
299
+ }
300
+ else if (e.key === 'Escape') {
301
+ e.preventDefault();
302
+ finish(false);
303
+ }
304
+ });
305
+ inputEl.addEventListener('blur', () => finish(true));
306
+ inputEl.addEventListener('click', (e) => e.stopPropagation());
307
+ cell.replaceChildren(inputEl);
308
+ inputEl.focus();
309
+ if (typeof inputEl.select === 'function')
310
+ inputEl.select();
311
+ }
312
+ // --- state-driven rendering --------------------------------------------
313
+ function render(state) {
314
+ // Sheet options rebuild only when the set changes (stable identity).
315
+ if (sheetSelect.options.length !== state.sheetNames.length) {
316
+ sheetSelect.replaceChildren();
317
+ state.sheetNames.forEach((name, index) => {
318
+ const opt = el('option', undefined, name);
319
+ opt.value = String(index);
320
+ sheetSelect.appendChild(opt);
321
+ });
322
+ }
323
+ sheetSelect.value = String(state.sheetIndex);
324
+ sheetSelect.style.display = state.sheetNames.length > 1 ? '' : 'none';
325
+ sheetLabel.style.display = state.sheetNames.length > 1 ? '' : 'none';
326
+ if (searchInput.value !== state.search)
327
+ searchInput.value = state.search;
328
+ searchInput.disabled = state.viewMode === 'raw';
329
+ viewModeSelect.value = state.viewMode;
330
+ // Undo/redo surface once editing has started (docs §3); pure readers
331
+ // never see them. Dirty badge + save enablement track unsaved edits.
332
+ const editingActive = state.dirty || state.canUndo || state.canRedo;
333
+ for (const btn of [undoBtn, redoBtn])
334
+ btn.style.display = editingActive ? '' : 'none';
335
+ undoBtn.disabled = !state.canUndo;
336
+ redoBtn.disabled = !state.canRedo;
337
+ dirtyBadge.textContent = state.workbookDirty ? t('common.unsaved') : '';
338
+ // Search highlights in table (row filter) and grid (cell highlight);
339
+ // it is inactive in raw mode.
340
+ const term = state.viewMode !== 'raw' && state.search ? state.search.toLowerCase() : '';
341
+ const tableSearch = state.viewMode === 'table' && term !== '';
342
+ const rowSummary = tableSearch
343
+ ? t('common.rowsMatched', { matched: state.matchedRowCount, total: state.rowCount })
344
+ : t('common.rows', { count: state.rowCount });
345
+ let metaText = `${rowSummary} · ${t('common.columns', { count: state.columnCount })}`;
346
+ if (tableSearch) {
347
+ metaText += ` · ${t('excel.matchedCells', { count: state.matchedCellCount })}`;
348
+ }
349
+ meta.textContent = metaText;
350
+ diagnosticsBar.replaceChildren();
351
+ const hasNotices = state.diagnostics.length > 0 || state.failure !== null;
352
+ diagnosticsBar.style.display = hasNotices ? '' : 'none';
353
+ if (state.failure) {
354
+ diagnosticsBar.appendChild(el('div', 'omni-excel__diag-error', t(state.failure.messageKey, state.failure.args)));
355
+ }
356
+ for (const diag of state.diagnostics) {
357
+ diagnosticsBar.appendChild(el('div', undefined, t(diag.messageKey, diag.args)));
358
+ }
359
+ body.replaceChildren();
360
+ if (state.viewMode === 'raw') {
361
+ body.appendChild(el('pre', 'omni-excel__raw', controller.rawJson()));
362
+ }
363
+ else if (state.viewMode === 'grid') {
364
+ const grid = controller.getGrid();
365
+ if (!grid || grid.rows.length === 0) {
366
+ body.appendChild(el('div', 'omni-excel__empty', t('excel.empty')));
367
+ }
368
+ else {
369
+ if (grid.truncatedRows !== null) {
370
+ body.appendChild(el('div', 'omni-excel__diag-error', t('excel.gridTruncated', { count: grid.truncatedRows })));
371
+ }
372
+ body.appendChild(renderGrid(grid, term));
373
+ }
374
+ }
375
+ else if (state.rowCount === 0) {
376
+ body.appendChild(el('div', 'omni-excel__empty', t('excel.empty')));
377
+ }
378
+ else {
379
+ body.appendChild(renderTable(state, tableSearch));
380
+ }
381
+ const showPager = state.pageCount > 1 && state.viewMode === 'table';
382
+ footer.style.display = showPager ? '' : 'none';
383
+ if (showPager) {
384
+ pageInfo.textContent = t('common.page', {
385
+ page: state.page + 1,
386
+ pages: state.pageCount
387
+ });
388
+ prevBtn.disabled = state.page === 0;
389
+ nextBtn.disabled = state.page >= state.pageCount - 1;
390
+ }
391
+ }
392
+ function renderTable(state, searchActive) {
393
+ const table = el('table', 'omni-excel__table');
394
+ const term = searchActive ? state.search.toLowerCase() : '';
395
+ // A sheet with a different column count cannot share frozen widths.
396
+ if (columnWidths && columnWidths.length !== state.columnCount) {
397
+ columnWidths = null;
398
+ }
399
+ const colgroup = el('colgroup');
400
+ const dataCols = [];
401
+ for (let c = 0; c < state.columnCount; c++) {
402
+ const col = el('col');
403
+ const width = columnWidths?.[c];
404
+ if (width != null)
405
+ col.style.width = `${width}px`;
406
+ dataCols.push(col);
407
+ colgroup.appendChild(col);
408
+ }
409
+ table.appendChild(colgroup);
410
+ if (columnWidths)
411
+ applyFixedLayout();
412
+ const dataThs = [];
413
+ /** Keep a fixed total width while a boundary transfers width between
414
+ * adjacent columns, matching the CSV viewer interaction. */
415
+ function applyFixedLayout() {
416
+ if (!columnWidths)
417
+ return;
418
+ const width = columnWidths.reduce((total, columnWidth) => total + (columnWidth ?? 0), 0);
419
+ table.style.tableLayout = 'fixed';
420
+ table.style.width = `${width}px`;
421
+ table.style.minWidth = '0';
422
+ }
423
+ function freezeWidths() {
424
+ if (columnWidths)
425
+ return;
426
+ columnWidths = dataThs.map((th) => Math.max(th.offsetWidth || FALLBACK_COLUMN_WIDTH, MIN_COLUMN_WIDTH));
427
+ columnWidths.forEach((width, index) => {
428
+ const col = dataCols[index];
429
+ if (col && width != null)
430
+ col.style.width = `${width}px`;
431
+ });
432
+ applyFixedLayout();
433
+ }
434
+ function startResize(event, columnIndex) {
435
+ event.preventDefault();
436
+ event.stopPropagation();
437
+ activeResizeCleanup?.();
438
+ freezeWidths();
439
+ const adjacentColumnIndex = columnIndex + 1;
440
+ if (!columnWidths || adjacentColumnIndex >= columnWidths.length)
441
+ return;
442
+ const frozenWidths = columnWidths;
443
+ const startX = event.clientX;
444
+ const startWidth = frozenWidths[columnIndex] ?? FALLBACK_COLUMN_WIDTH;
445
+ const startAdjacentWidth = frozenWidths[adjacentColumnIndex] ?? FALLBACK_COLUMN_WIDTH;
446
+ const onMove = (ev) => {
447
+ const requestedDelta = Math.round(ev.clientX - startX);
448
+ const delta = Math.min(Math.max(requestedDelta, MIN_COLUMN_WIDTH - startWidth), startAdjacentWidth - MIN_COLUMN_WIDTH);
449
+ frozenWidths[columnIndex] = startWidth + delta;
450
+ frozenWidths[adjacentColumnIndex] = startAdjacentWidth - delta;
451
+ const col = dataCols[columnIndex];
452
+ const adjacentCol = dataCols[adjacentColumnIndex];
453
+ if (col)
454
+ col.style.width = `${frozenWidths[columnIndex]}px`;
455
+ if (adjacentCol) {
456
+ adjacentCol.style.width = `${frozenWidths[adjacentColumnIndex]}px`;
457
+ }
458
+ };
459
+ const onUp = () => activeResizeCleanup?.();
460
+ window.addEventListener('pointermove', onMove);
461
+ window.addEventListener('pointerup', onUp);
462
+ activeResizeCleanup = () => {
463
+ window.removeEventListener('pointermove', onMove);
464
+ window.removeEventListener('pointerup', onUp);
465
+ activeResizeCleanup = null;
466
+ };
467
+ }
468
+ const thead = el('thead');
469
+ const headRow = el('tr');
470
+ state.headers.forEach((header, columnIndex) => {
471
+ const th = el('th');
472
+ th.appendChild(el('span', undefined, header));
473
+ th.setAttribute('role', 'columnheader');
474
+ th.title = t('excel.sortHint');
475
+ dataThs.push(th);
476
+ const resizeHandle = el('span', 'omni-excel__resize-handle');
477
+ resizeHandle.title = t('excel.resizeColumn');
478
+ resizeHandle.addEventListener('pointerdown', (event) => startResize(event, columnIndex));
479
+ // Do not let a completed resize trigger header sorting.
480
+ resizeHandle.addEventListener('click', (event) => event.stopPropagation());
481
+ resizeHandle.addEventListener('dblclick', (event) => {
482
+ event.stopPropagation();
483
+ if (!columnWidths)
484
+ return;
485
+ columnWidths[columnIndex] = null;
486
+ if (columnWidths.every((width) => width == null))
487
+ columnWidths = null;
488
+ render(controller.state);
489
+ });
490
+ th.appendChild(resizeHandle);
491
+ if (state.sort.columnIndex === columnIndex && state.sort.direction) {
492
+ th.setAttribute('aria-sort', state.sort.direction === 'asc' ? 'ascending' : 'descending');
493
+ th.appendChild(el('span', 'omni-excel__sort-indicator', state.sort.direction === 'asc' ? '▲' : '▼'));
494
+ }
495
+ // Single click sorts (deferred so a double-click can win); double
496
+ // click renames the header when editable (docs §3, CSV parity).
497
+ th.addEventListener('click', () => {
498
+ if (th.querySelector('input'))
499
+ return;
500
+ if (pendingSortTimer)
501
+ clearTimeout(pendingSortTimer);
502
+ pendingSortTimer = setTimeout(() => {
503
+ pendingSortTimer = null;
504
+ controller.dispatch({ type: 'sort-column', columnIndex });
505
+ }, SORT_CLICK_DELAY_MS);
506
+ });
507
+ th.addEventListener('dblclick', () => {
508
+ if (pendingSortTimer) {
509
+ clearTimeout(pendingSortTimer);
510
+ pendingSortTimer = null;
511
+ }
512
+ if (th.querySelector('input') || !state.editable)
513
+ return;
514
+ startInlineEdit(th, state.headers[columnIndex] ?? '', (value) => controller.dispatch({ type: 'edit-header', columnIndex, value }));
515
+ });
516
+ headRow.appendChild(th);
517
+ });
518
+ thead.appendChild(headRow);
519
+ table.appendChild(thead);
520
+ const tbody = el('tbody');
521
+ state.visibleRows.forEach((row, rowOffset) => {
522
+ const rowId = state.visibleRowIds[rowOffset] ?? -1;
523
+ const tr = el('tr');
524
+ if (state.editable) {
525
+ // Row insert/delete live in a right-click menu (no ops column).
526
+ tr.addEventListener('contextmenu', (e) => {
527
+ e.preventDefault();
528
+ openRowContextMenu(e, rowId);
529
+ });
530
+ }
531
+ for (let c = 0; c < state.columnCount; c++) {
532
+ const columnIndex = c;
533
+ const text = row[columnIndex] ?? '';
534
+ const td = el('td', undefined, text);
535
+ if (term && text.toLowerCase().includes(term)) {
536
+ td.classList.add('omni-excel__hit');
537
+ }
538
+ if (state.editable) {
539
+ td.title = t('excel.editHint');
540
+ td.addEventListener('dblclick', () => {
541
+ if (td.querySelector('input'))
542
+ return;
543
+ startInlineEdit(td, controller.getRowById(rowId)[columnIndex] ?? '', (value) => controller.dispatch({ type: 'edit-cell', rowId, columnIndex, value }));
544
+ });
545
+ }
546
+ tr.appendChild(td);
547
+ }
548
+ tbody.appendChild(tr);
549
+ });
550
+ table.appendChild(tbody);
551
+ return table;
552
+ }
553
+ /** Read-only WYSIWYG grid (X3): file column widths / row heights, merged
554
+ * cells (rowspan/colspan), and per-cell inline styles from the source. */
555
+ function renderGrid(grid, term) {
556
+ const table = el('table', 'omni-excel__grid');
557
+ const colgroup = el('colgroup');
558
+ for (const width of grid.cols) {
559
+ const col = el('col');
560
+ col.style.width = `${width}px`;
561
+ colgroup.appendChild(col);
562
+ }
563
+ table.appendChild(colgroup);
564
+ const tbody = el('tbody');
565
+ for (const row of grid.rows) {
566
+ const tr = el('tr');
567
+ tr.style.height = `${row.heightPx}px`;
568
+ for (const cell of row.cells) {
569
+ const td = el('td', undefined, cell.text);
570
+ if (cell.rowSpan > 1)
571
+ td.rowSpan = cell.rowSpan;
572
+ if (cell.colSpan > 1)
573
+ td.colSpan = cell.colSpan;
574
+ // Inline style from file data — CSP allows the style attribute.
575
+ Object.assign(td.style, cell.style);
576
+ if (term && cell.text.toLowerCase().includes(term)) {
577
+ td.classList.add('omni-excel__hit');
578
+ }
579
+ tr.appendChild(td);
580
+ }
581
+ tbody.appendChild(tr);
582
+ }
583
+ table.appendChild(tbody);
584
+ return table;
585
+ }
586
+ // Undo/redo shortcuts while editing (frame-local, disposed with us).
587
+ on(frame, 'keydown', (e) => {
588
+ if (!(e.ctrlKey || e.metaKey) || e.key.toLowerCase() !== 'z')
589
+ return;
590
+ e.preventDefault();
591
+ controller.dispatch({ type: e.shiftKey ? 'redo' : 'undo' });
592
+ });
593
+ frame.tabIndex = -1;
594
+ const unsubscribe = controller.subscribe(render);
595
+ render(controller.state);
596
+ if (options.signal?.aborted) {
597
+ cleanup();
598
+ throw new MountAbortedError();
599
+ }
600
+ function cleanup() {
601
+ unsubscribe();
602
+ for (const dispose of disposers)
603
+ dispose();
604
+ disposers.length = 0;
605
+ if (toastTimer)
606
+ clearTimeout(toastTimer);
607
+ if (pendingSortTimer)
608
+ clearTimeout(pendingSortTimer);
609
+ activeResizeCleanup?.();
610
+ closeContextMenu();
611
+ if (root instanceof ShadowRoot) {
612
+ root.replaceChildren();
613
+ }
614
+ else {
615
+ root.replaceChildren();
616
+ root.classList.remove(VIEWER_ROOT_CLASS, 'omni-viewer--excel');
617
+ }
618
+ }
619
+ return { dispose: cleanup };
620
+ }
@@ -0,0 +1,6 @@
1
+ import type { ViewerInput, MountOptions } from '../types.js';
2
+ import { type ExcelMountOptions, type ExcelViewerContext, type ExcelViewerDeps, type ExcelViewerHandle } from './index.js';
3
+ export * from './index.js';
4
+ export declare const selfLoadingExcelDeps: ExcelViewerDeps;
5
+ /** mountExcelViewer with the core's own dynamic-import loader. */
6
+ export declare function mountSelfLoadingExcelViewer(input: ViewerInput, container: HTMLElement, ctx: ExcelViewerContext, options?: ExcelMountOptions & MountOptions): Promise<ExcelViewerHandle>;
@@ -0,0 +1,13 @@
1
+ // Opt-in self-loading entry (ADR 14): the only place in the core where the
2
+ // optional peer `xlsx` is actually imported. Platforms whose bundler resolves
3
+ // the peer use this; others import `viewers/excel` and inject their own loader
4
+ // (e.g. chrome wires its vendored xlsx UMD through resolveAssetUrl).
5
+ import { mountExcelViewer } from './index.js';
6
+ export * from './index.js';
7
+ export const selfLoadingExcelDeps = {
8
+ loadXlsx: () => import('xlsx')
9
+ };
10
+ /** mountExcelViewer with the core's own dynamic-import loader. */
11
+ export function mountSelfLoadingExcelViewer(input, container, ctx, options = {}) {
12
+ return mountExcelViewer(input, container, ctx, selfLoadingExcelDeps, options);
13
+ }