@elabs-ai/components-viewer 4.2.0 → 5.0.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 (204) hide show
  1. package/dist/{code-adapter-ADZ4UOGN.js → adapters/code/code-adapter.js} +15 -64
  2. package/dist/adapters/code/code-adapter.js.map +1 -0
  3. package/dist/adapters/code/code-language.js +10 -0
  4. package/dist/adapters/code/code-language.js.map +1 -0
  5. package/dist/adapters/code/code-manifest.js +10 -0
  6. package/dist/adapters/code/code-manifest.js.map +1 -0
  7. package/dist/adapters/code/code-theme.js +8 -0
  8. package/dist/adapters/code/code-theme.js.map +1 -0
  9. package/dist/{csv-adapter-7HOFZ5Z6.js → adapters/csv/csv-adapter.js} +13 -9
  10. package/dist/adapters/csv/csv-adapter.js.map +1 -0
  11. package/dist/adapters/csv/csv-manifest.js +9 -0
  12. package/dist/adapters/csv/csv-manifest.js.map +1 -0
  13. package/dist/{docx-adapter-5CQDHWTD.js → adapters/docx/docx-adapter.js} +17 -175
  14. package/dist/adapters/docx/docx-adapter.js.map +1 -0
  15. package/dist/adapters/docx/docx-manifest.js +9 -0
  16. package/dist/adapters/docx/docx-manifest.js.map +1 -0
  17. package/dist/adapters/docx/docx-model.js +21 -0
  18. package/dist/adapters/docx/docx-model.js.map +1 -0
  19. package/dist/{image-adapter-WOHZR24J.js → adapters/image/image-adapter.js} +4 -3
  20. package/dist/adapters/image/image-adapter.js.map +1 -0
  21. package/dist/adapters/image/image-manifest.js +9 -0
  22. package/dist/adapters/image/image-manifest.js.map +1 -0
  23. package/dist/adapters/index.js +56 -0
  24. package/dist/adapters/index.js.map +1 -0
  25. package/dist/{json-adapter-ZUW5GQHE.js → adapters/json/json-adapter.js} +4 -3
  26. package/dist/adapters/json/json-adapter.js.map +1 -0
  27. package/dist/adapters/json/json-manifest.js +9 -0
  28. package/dist/adapters/json/json-manifest.js.map +1 -0
  29. package/dist/{markdown-adapter-YC6WTBS4.js → adapters/markdown/markdown-adapter.js} +14 -36
  30. package/dist/adapters/markdown/markdown-adapter.js.map +1 -0
  31. package/dist/adapters/markdown/markdown-manifest.js +9 -0
  32. package/dist/adapters/markdown/markdown-manifest.js.map +1 -0
  33. package/dist/adapters/markdown/markdown-marks.js +10 -0
  34. package/dist/adapters/markdown/markdown-marks.js.map +1 -0
  35. package/dist/{media-adapter-MCTB4GBH.js → adapters/media/media-adapter.js} +4 -3
  36. package/dist/adapters/media/media-adapter.js.map +1 -0
  37. package/dist/adapters/media/media-manifest.js +9 -0
  38. package/dist/adapters/media/media-manifest.js.map +1 -0
  39. package/dist/{pdf-adapter-5PMKEXUD.js → adapters/pdf/pdf-adapter.js} +31 -81
  40. package/dist/adapters/pdf/pdf-adapter.js.map +1 -0
  41. package/dist/adapters/pdf/pdf-engine.js +14 -0
  42. package/dist/adapters/pdf/pdf-engine.js.map +1 -0
  43. package/dist/adapters/pdf/pdf-manifest.js +9 -0
  44. package/dist/adapters/pdf/pdf-manifest.js.map +1 -0
  45. package/dist/adapters/pdf/pdf-text.js +20 -0
  46. package/dist/adapters/pdf/pdf-text.js.map +1 -0
  47. package/dist/{pptx-adapter-BONWFHYT.js → adapters/pptx/pptx-adapter.js} +34 -135
  48. package/dist/adapters/pptx/pptx-adapter.js.map +1 -0
  49. package/dist/adapters/pptx/pptx-manifest.js +9 -0
  50. package/dist/adapters/pptx/pptx-manifest.js.map +1 -0
  51. package/dist/adapters/pptx/pptx-model.js +37 -0
  52. package/dist/adapters/pptx/pptx-model.js.map +1 -0
  53. package/dist/{text-adapter-NFNWB5W3.js → adapters/text/text-adapter.js} +8 -5
  54. package/dist/adapters/text/text-adapter.js.map +1 -0
  55. package/dist/adapters/text/text-manifest.js +9 -0
  56. package/dist/adapters/text/text-manifest.js.map +1 -0
  57. package/dist/{xlsx-adapter-O3XIVLFC.js → adapters/xlsx/xlsx-adapter.js} +12 -8
  58. package/dist/adapters/xlsx/xlsx-adapter.js.map +1 -0
  59. package/dist/adapters/xlsx/xlsx-manifest.js +9 -0
  60. package/dist/adapters/xlsx/xlsx-manifest.js.map +1 -0
  61. package/dist/chunk-3HKQFFZW.js +31 -0
  62. package/dist/chunk-3HKQFFZW.js.map +1 -0
  63. package/dist/chunk-5VJWILZ7.js +182 -0
  64. package/dist/chunk-5VJWILZ7.js.map +1 -0
  65. package/dist/{chunk-UL43NGUG.js → chunk-5YE2MUS2.js} +1 -1
  66. package/dist/{chunk-5OMONA2G.js → chunk-6FVJ4D7W.js} +3 -15
  67. package/dist/chunk-6FVJ4D7W.js.map +1 -0
  68. package/dist/{chunk-RGWDIQJR.js → chunk-7EASJBQM.js} +2 -2
  69. package/dist/chunk-7PGGKQVY.js +26 -0
  70. package/dist/chunk-7PGGKQVY.js.map +1 -0
  71. package/dist/{chunk-XBOR2YXS.js → chunk-AK7F3IZE.js} +9 -30
  72. package/dist/chunk-AK7F3IZE.js.map +1 -0
  73. package/dist/chunk-AOYEL7O3.js +34 -0
  74. package/dist/chunk-AOYEL7O3.js.map +1 -0
  75. package/dist/chunk-BDUFH66C.js +61 -0
  76. package/dist/chunk-BDUFH66C.js.map +1 -0
  77. package/dist/chunk-BWMXMHVZ.js +107 -0
  78. package/dist/chunk-BWMXMHVZ.js.map +1 -0
  79. package/dist/chunk-CIT2HHRI.js +9 -0
  80. package/dist/chunk-CIT2HHRI.js.map +1 -0
  81. package/dist/chunk-CLOI4HBA.js +18 -0
  82. package/dist/chunk-CLOI4HBA.js.map +1 -0
  83. package/dist/chunk-CMYBLW7D.js +21 -0
  84. package/dist/chunk-CMYBLW7D.js.map +1 -0
  85. package/dist/chunk-CO2VJRSU.js +18 -0
  86. package/dist/chunk-CO2VJRSU.js.map +1 -0
  87. package/dist/{chunk-3U3MESBU.js → chunk-EA72HA4I.js} +2 -2
  88. package/dist/{chunk-KOMDRWOU.js → chunk-FDT4QOIG.js} +2 -2
  89. package/dist/chunk-FQHZEQUH.js +90 -0
  90. package/dist/chunk-FQHZEQUH.js.map +1 -0
  91. package/dist/chunk-G27UJZWH.js +82 -0
  92. package/dist/chunk-G27UJZWH.js.map +1 -0
  93. package/dist/{chunk-BCF3RWRL.js → chunk-GH4UBYST.js} +2 -2
  94. package/dist/{chunk-2NQ4RSJ3.js → chunk-GNBD53AT.js} +2 -2
  95. package/dist/{chunk-VO2273Z2.js → chunk-HOQZ7OPH.js} +2 -18
  96. package/dist/chunk-HOQZ7OPH.js.map +1 -0
  97. package/dist/{chunk-GGR7BNW4.js → chunk-HUUJIFFT.js} +2 -2
  98. package/dist/{chunk-FELIAGKI.js → chunk-I5XD2NJ6.js} +2 -2
  99. package/dist/chunk-IB4N72FA.js +21 -0
  100. package/dist/chunk-IB4N72FA.js.map +1 -0
  101. package/dist/{chunk-4OFQYALG.js → chunk-IQ6Z4X3K.js} +8 -68
  102. package/dist/chunk-IQ6Z4X3K.js.map +1 -0
  103. package/dist/{chunk-AORNMH77.js → chunk-JHFC2KBI.js} +1 -5
  104. package/dist/chunk-JHFC2KBI.js.map +1 -0
  105. package/dist/chunk-LRPZ373O.js +93 -0
  106. package/dist/chunk-LRPZ373O.js.map +1 -0
  107. package/dist/chunk-M77ICVWP.js +24 -0
  108. package/dist/chunk-M77ICVWP.js.map +1 -0
  109. package/dist/chunk-MJUH32ZK.js +24 -0
  110. package/dist/chunk-MJUH32ZK.js.map +1 -0
  111. package/dist/chunk-PAIVK4N6.js +162 -0
  112. package/dist/chunk-PAIVK4N6.js.map +1 -0
  113. package/dist/chunk-PKYDKXCO.js +129 -0
  114. package/dist/chunk-PKYDKXCO.js.map +1 -0
  115. package/dist/chunk-QIPKBOZJ.js +59 -0
  116. package/dist/chunk-QIPKBOZJ.js.map +1 -0
  117. package/dist/chunk-SASY77ZL.js +29 -0
  118. package/dist/chunk-SASY77ZL.js.map +1 -0
  119. package/dist/{chunk-SLXRUYT3.js → chunk-SBG7WPGO.js} +2 -44
  120. package/dist/chunk-SBG7WPGO.js.map +1 -0
  121. package/dist/chunk-T4Y4YRHJ.js +733 -0
  122. package/dist/chunk-T4Y4YRHJ.js.map +1 -0
  123. package/dist/chunk-TLCNGQKL.js +37 -0
  124. package/dist/chunk-TLCNGQKL.js.map +1 -0
  125. package/dist/chunk-US5KT3TR.js +141 -0
  126. package/dist/chunk-US5KT3TR.js.map +1 -0
  127. package/dist/{chunk-HMG2ERXH.js → chunk-YA72QE57.js} +2 -2
  128. package/dist/{chunk-H3OAON3D.js → chunk-YWHFMCS4.js} +2 -2
  129. package/dist/{chunk-UJIJECEF.js → chunk-ZAVXZRIO.js} +2 -2
  130. package/dist/components/grid-text.js +19 -0
  131. package/dist/components/grid-text.js.map +1 -0
  132. package/dist/components/marked-text.js +10 -0
  133. package/dist/components/marked-text.js.map +1 -0
  134. package/dist/components/sheet-table.js +14 -0
  135. package/dist/components/sheet-table.js.map +1 -0
  136. package/dist/core/errors.js +18 -0
  137. package/dist/core/errors.js.map +1 -0
  138. package/dist/core/highlight-marks.js +10 -0
  139. package/dist/core/highlight-marks.js.map +1 -0
  140. package/dist/core/highlight-resolve.js +10 -0
  141. package/dist/core/highlight-resolve.js.map +1 -0
  142. package/dist/core/highlight.js +12 -0
  143. package/dist/core/highlight.js.map +1 -0
  144. package/dist/core/registry.js +12 -0
  145. package/dist/core/registry.js.map +1 -0
  146. package/dist/core/scroll-host.js +10 -0
  147. package/dist/core/scroll-host.js.map +1 -0
  148. package/dist/core/text-index.js +14 -0
  149. package/dist/core/text-index.js.map +1 -0
  150. package/dist/core/types.js +8 -0
  151. package/dist/core/types.js.map +1 -0
  152. package/dist/core/use-highlight-scroll.js +11 -0
  153. package/dist/core/use-highlight-scroll.js.map +1 -0
  154. package/dist/core/use-page-control.js +9 -0
  155. package/dist/core/use-page-control.js.map +1 -0
  156. package/dist/core/use-paged-scroll.js +10 -0
  157. package/dist/core/use-paged-scroll.js.map +1 -0
  158. package/dist/core/use-viewport-size.js +10 -0
  159. package/dist/core/use-viewport-size.js.map +1 -0
  160. package/dist/core/zoom.js +16 -0
  161. package/dist/core/zoom.js.map +1 -0
  162. package/dist/file-viewer/file-viewer-context.js +11 -0
  163. package/dist/file-viewer/file-viewer-context.js.map +1 -0
  164. package/dist/file-viewer/file-viewer-find.js +13 -0
  165. package/dist/file-viewer/file-viewer-find.js.map +1 -0
  166. package/dist/file-viewer/file-viewer-pager.js +10 -0
  167. package/dist/file-viewer/file-viewer-pager.js.map +1 -0
  168. package/dist/file-viewer/file-viewer-zoom.js +13 -0
  169. package/dist/file-viewer/file-viewer-zoom.js.map +1 -0
  170. package/dist/file-viewer/file-viewer.js +48 -0
  171. package/dist/file-viewer/file-viewer.js.map +1 -0
  172. package/dist/index.js +78 -1274
  173. package/dist/index.js.map +1 -1
  174. package/package.json +5 -5
  175. package/src/file-viewer/file-viewer-recipes.stories.tsx +406 -0
  176. package/src/file-viewer/file-viewer.stories.tsx +2 -2
  177. package/dist/chunk-4OFQYALG.js.map +0 -1
  178. package/dist/chunk-5OMONA2G.js.map +0 -1
  179. package/dist/chunk-AORNMH77.js.map +0 -1
  180. package/dist/chunk-SLXRUYT3.js.map +0 -1
  181. package/dist/chunk-VO2273Z2.js.map +0 -1
  182. package/dist/chunk-XBOR2YXS.js.map +0 -1
  183. package/dist/code-adapter-ADZ4UOGN.js.map +0 -1
  184. package/dist/csv-adapter-7HOFZ5Z6.js.map +0 -1
  185. package/dist/docx-adapter-5CQDHWTD.js.map +0 -1
  186. package/dist/image-adapter-WOHZR24J.js.map +0 -1
  187. package/dist/json-adapter-ZUW5GQHE.js.map +0 -1
  188. package/dist/markdown-adapter-YC6WTBS4.js.map +0 -1
  189. package/dist/media-adapter-MCTB4GBH.js.map +0 -1
  190. package/dist/pdf-adapter-5PMKEXUD.js.map +0 -1
  191. package/dist/pptx-adapter-BONWFHYT.js.map +0 -1
  192. package/dist/text-adapter-NFNWB5W3.js.map +0 -1
  193. package/dist/xlsx-adapter-O3XIVLFC.js.map +0 -1
  194. /package/dist/{chunk-UL43NGUG.js.map → chunk-5YE2MUS2.js.map} +0 -0
  195. /package/dist/{chunk-RGWDIQJR.js.map → chunk-7EASJBQM.js.map} +0 -0
  196. /package/dist/{chunk-3U3MESBU.js.map → chunk-EA72HA4I.js.map} +0 -0
  197. /package/dist/{chunk-KOMDRWOU.js.map → chunk-FDT4QOIG.js.map} +0 -0
  198. /package/dist/{chunk-BCF3RWRL.js.map → chunk-GH4UBYST.js.map} +0 -0
  199. /package/dist/{chunk-2NQ4RSJ3.js.map → chunk-GNBD53AT.js.map} +0 -0
  200. /package/dist/{chunk-GGR7BNW4.js.map → chunk-HUUJIFFT.js.map} +0 -0
  201. /package/dist/{chunk-FELIAGKI.js.map → chunk-I5XD2NJ6.js.map} +0 -0
  202. /package/dist/{chunk-HMG2ERXH.js.map → chunk-YA72QE57.js.map} +0 -0
  203. /package/dist/{chunk-H3OAON3D.js.map → chunk-YWHFMCS4.js.map} +0 -0
  204. /package/dist/{chunk-UJIJECEF.js.map → chunk-ZAVXZRIO.js.map} +0 -0
@@ -1,149 +1,48 @@
1
1
  "use client";
2
2
  "use client";
3
3
  import {
4
- pptxManifest
5
- } from "./chunk-KOMDRWOU.js";
4
+ PPTX_NOTES_LINE,
5
+ PPTX_TITLE_LINE,
6
+ notesTarget,
7
+ orderSlidePaths,
8
+ parseNotes,
9
+ parseSlide,
10
+ slidesToTextWithMap
11
+ } from "../../chunk-US5KT3TR.js";
12
+ import {
13
+ usePageControl
14
+ } from "../../chunk-MJUH32ZK.js";
15
+ import {
16
+ usePagedScroll
17
+ } from "../../chunk-IQ6Z4X3K.js";
6
18
  import {
7
- usePageControl,
8
- usePagedScroll,
9
19
  useViewportSize
10
- } from "./chunk-4OFQYALG.js";
20
+ } from "../../chunk-3HKQFFZW.js";
21
+ import "../../chunk-7PGGKQVY.js";
22
+ import {
23
+ pptxManifest
24
+ } from "../../chunk-FDT4QOIG.js";
11
25
  import {
12
26
  MarkedText
13
- } from "./chunk-2NQ4RSJ3.js";
27
+ } from "../../chunk-GNBD53AT.js";
14
28
  import {
15
- createTextIndexBuilder,
16
29
  spanAt
17
- } from "./chunk-UL43NGUG.js";
30
+ } from "../../chunk-5YE2MUS2.js";
18
31
  import {
19
- toMarkRanges,
20
32
  useScrollActiveHighlightIntoView
21
- } from "./chunk-VO2273Z2.js";
33
+ } from "../../chunk-IB4N72FA.js";
34
+ import {
35
+ toMarkRanges
36
+ } from "../../chunk-HOQZ7OPH.js";
22
37
  import {
23
38
  ViewerError,
24
39
  toViewerError
25
- } from "./chunk-AORNMH77.js";
40
+ } from "../../chunk-JHFC2KBI.js";
41
+ import "../../chunk-CIT2HHRI.js";
26
42
 
27
43
  // src/adapters/pptx/pptx-adapter.tsx
28
44
  import { cn, ProseHeading, useLocale } from "@elabs-ai/components-ui";
29
45
  import { useCallback, useEffect, useMemo, useRef } from "react";
30
-
31
- // src/adapters/pptx/pptx-model.ts
32
- var DRAWING_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
33
- var PRESENTATION_NS = "http://schemas.openxmlformats.org/presentationml/2006/main";
34
- function orderSlidePaths(paths) {
35
- return paths.filter((path) => /^ppt\/slides\/slide\d+\.xml$/.test(path)).sort((left, right) => slideNumber(left) - slideNumber(right));
36
- }
37
- function slideNumber(path) {
38
- const match = /(\d+)\.xml$/.exec(path);
39
- return match?.[1] ? Number(match[1]) : 0;
40
- }
41
- function textOf(node) {
42
- const runs = node.getElementsByTagNameNS(DRAWING_NS, "t");
43
- let text = "";
44
- for (const run of Array.from(runs)) text += run.textContent ?? "";
45
- return text.trim();
46
- }
47
- function linesOf(shape) {
48
- const lines = [];
49
- for (const paragraph of Array.from(shape.getElementsByTagNameNS(DRAWING_NS, "p"))) {
50
- const text = textOf(paragraph);
51
- if (!text) continue;
52
- const properties = paragraph.getElementsByTagNameNS(DRAWING_NS, "pPr")[0];
53
- const level = Number(properties?.getAttribute("lvl") ?? 0);
54
- lines.push({ text, level: Number.isFinite(level) ? level : 0 });
55
- }
56
- return lines;
57
- }
58
- function placeholderType(shape) {
59
- const placeholder = shape.getElementsByTagNameNS(PRESENTATION_NS, "ph")[0];
60
- return placeholder?.getAttribute("type") ?? void 0;
61
- }
62
- function tableLines(frame) {
63
- const lines = [];
64
- for (const row of Array.from(frame.getElementsByTagNameNS(DRAWING_NS, "tr"))) {
65
- const cells = Array.from(row.getElementsByTagNameNS(DRAWING_NS, "tc")).map(textOf);
66
- const text = cells.join(" ").trim();
67
- if (text) lines.push({ text, level: 0 });
68
- }
69
- return lines;
70
- }
71
- function parseSlide(document, index) {
72
- const tree = document.getElementsByTagNameNS(PRESENTATION_NS, "spTree")[0];
73
- const slide = { index, lines: [] };
74
- if (!tree) return slide;
75
- for (const node of Array.from(tree.children)) {
76
- if (node.namespaceURI !== PRESENTATION_NS) continue;
77
- if (node.localName === "sp") {
78
- const type = placeholderType(node);
79
- const lines = linesOf(node);
80
- if ((type === "title" || type === "ctrTitle") && !slide.title) {
81
- const title = lines.map((line) => line.text).join(" ");
82
- if (title) slide.title = title;
83
- continue;
84
- }
85
- slide.lines.push(...lines);
86
- continue;
87
- }
88
- if (node.localName === "graphicFrame") slide.lines.push(...tableLines(node));
89
- }
90
- return slide;
91
- }
92
- function parseNotes(document) {
93
- const tree = document.getElementsByTagNameNS(PRESENTATION_NS, "spTree")[0];
94
- if (!tree) return void 0;
95
- const lines = [];
96
- for (const shape of Array.from(tree.getElementsByTagNameNS(PRESENTATION_NS, "sp"))) {
97
- if (placeholderType(shape) !== "body") continue;
98
- for (const line of linesOf(shape)) lines.push(line.text);
99
- }
100
- const notes = lines.join("\n").trim();
101
- return notes || void 0;
102
- }
103
- var RELATIONSHIP_NS = "http://schemas.openxmlformats.org/package/2006/relationships";
104
- function resolveRelative(fromPart, target) {
105
- if (target.startsWith("/")) return target.slice(1);
106
- const segments = fromPart.split("/").slice(0, -1);
107
- for (const segment of target.split("/")) {
108
- if (segment === "." || segment === "") continue;
109
- if (segment === "..") segments.pop();
110
- else segments.push(segment);
111
- }
112
- return segments.join("/");
113
- }
114
- function notesTarget(rels, slidePath) {
115
- for (const relationship of Array.from(
116
- rels.getElementsByTagNameNS(RELATIONSHIP_NS, "Relationship")
117
- )) {
118
- if (!relationship.getAttribute("Type")?.endsWith("/notesSlide")) continue;
119
- const target = relationship.getAttribute("Target");
120
- if (target) return resolveRelative(slidePath, target);
121
- }
122
- return void 0;
123
- }
124
- var PPTX_LINE_SEPARATOR = "\n";
125
- var PPTX_SLIDE_SEPARATOR = "\n\n";
126
- var PPTX_TITLE_LINE = -1;
127
- var PPTX_NOTES_LINE = -2;
128
- function slidesToTextWithMap(slides) {
129
- const builder = createTextIndexBuilder({ separator: PPTX_LINE_SEPARATOR });
130
- slides.forEach((slide, index) => {
131
- let separator = index === 0 ? void 0 : PPTX_SLIDE_SEPARATOR;
132
- const push = (chunk, line) => {
133
- if (!chunk) return;
134
- builder.push(chunk, { slide: slide.index, line }, separator);
135
- separator = void 0;
136
- };
137
- push(slide.title, PPTX_TITLE_LINE);
138
- slide.lines.forEach((line, lineIndex) => {
139
- push(line.text, lineIndex);
140
- });
141
- push(slide.notes, PPTX_NOTES_LINE);
142
- });
143
- return builder.build();
144
- }
145
-
146
- // src/adapters/pptx/pptx-adapter.tsx
147
46
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
148
47
  var LEVEL_INDENT = ["ps-0", "ps-4", "ps-8", "ps-12"];
149
48
  var SLIDE_MAX_WIDTH = 768;
@@ -209,7 +108,7 @@ function PptxRenderer({
209
108
  onPageChange
210
109
  }) {
211
110
  const deck = doc;
212
- const [slideNumber2, goToSlide] = usePageControl(pageNumber, onPageChange, deck.slides.length);
111
+ const [slideNumber, goToSlide] = usePageControl(pageNumber, onPageChange, deck.slides.length);
213
112
  const listRef = useRef(null);
214
113
  const viewport = useViewportSize(listRef);
215
114
  const marks = useMemo(
@@ -224,7 +123,7 @@ function PptxRenderer({
224
123
  const virtualizer = usePagedScroll({
225
124
  count: deck.slides.length,
226
125
  listRef,
227
- pageNumber: slideNumber2,
126
+ pageNumber: slideNumber,
228
127
  goToPage: goToSlide,
229
128
  estimateSize,
230
129
  sizeKey: frameWidth
@@ -250,7 +149,7 @@ function PptxRenderer({
250
149
  const position = deck.slides.findIndex((candidate) => candidate.index === activeSlide);
251
150
  if (position >= 0) goToSlide(position + 1);
252
151
  }, [activeSlide, deck.slides, goToSlide]);
253
- useScrollActiveHighlightIntoView(listRef, activeHighlightId, slideNumber2);
152
+ useScrollActiveHighlightIntoView(listRef, activeHighlightId, slideNumber);
254
153
  return (
255
154
  // No viewport of its own: the slide chrome moved to the shell (ADR 0026), so
256
155
  // there is no fixed control above a scrolling body and `FileViewerContent`
@@ -295,7 +194,7 @@ function PptxRenderer({
295
194
  }
296
195
  function PptxSlideView({
297
196
  slide,
298
- slideNumber: slideNumber2,
197
+ slideNumber,
299
198
  baseHeadingLevel,
300
199
  marks,
301
200
  starts
@@ -308,9 +207,9 @@ function PptxSlideView({
308
207
  {
309
208
  tabIndex: 0,
310
209
  "data-slot": "pptx-slide",
311
- "data-page": slideNumber2,
210
+ "data-page": slideNumber,
312
211
  "aria-label": t("viewer.pptx.slide", {
313
- slide: formatNumber(slideNumber2)
212
+ slide: formatNumber(slideNumber)
314
213
  }),
315
214
  className: "border-border bg-card focus-ring mx-auto flex aspect-video w-full max-w-3xl flex-col gap-3 overflow-auto rounded-md border p-6 shadow-sm",
316
215
  children: [
@@ -348,4 +247,4 @@ var pptx_adapter_default = adapterModule;
348
247
  export {
349
248
  pptx_adapter_default as default
350
249
  };
351
- //# sourceMappingURL=pptx-adapter-BONWFHYT.js.map
250
+ //# sourceMappingURL=pptx-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/pptx/pptx-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * PowerPoint adapter — a deck becomes a slide outline you can page through.\n *\n * A `.pptx` is a zip of XML, so there is no PowerPoint library here: jszip opens\n * the container and the platform's own `DOMParser` reads the parts. What is\n * extracted, and why it is an outline rather than a reproduction of the slide\n * canvas, is argued in `pptx-model.ts`.\n *\n * The deck is one continuous column of slides, virtualized over the shell's\n * viewport — the same treatment the PDF pages get, for the same reason: reading\n * a deck end to end is scrolling, not clicking \"next\" 60 times. The slide number\n * follows the scroll, and the pager scrolls.\n */\n\nimport type { ProseHeadingLevel, ResolvedFileSource } from \"@elabs-ai/components-ui\";\nimport { cn, ProseHeading, useLocale } from \"@elabs-ai/components-ui\";\nimport { useCallback, useEffect, useMemo, useRef } from \"react\";\n\nimport { MarkedText } from \"../../components/marked-text\";\nimport { ViewerError, toViewerError } from \"../../core/errors\";\nimport { toMarkRanges, type MarkRanges } from \"../../core/highlight-marks\";\nimport { spanAt, type TextIndex } from \"../../core/text-index\";\nimport { useScrollActiveHighlightIntoView } from \"../../core/use-highlight-scroll\";\nimport { usePageControl } from \"../../core/use-page-control\";\nimport { usePagedScroll } from \"../../core/use-paged-scroll\";\nimport { useViewportSize } from \"../../core/use-viewport-size\";\nimport type {\n AdapterDocument,\n AdapterLoadContext,\n AdapterModule,\n AdapterRendererProps,\n FileAdapter,\n} from \"../../core/types\";\nimport { pptxManifest } from \"./pptx-manifest\";\nimport {\n notesTarget,\n orderSlidePaths,\n parseNotes,\n parseSlide,\n slidesToTextWithMap,\n PPTX_NOTES_LINE,\n PPTX_TITLE_LINE,\n type PptxRef,\n type PptxSlide,\n} from \"./pptx-model\";\n\nexport interface PptxDocument extends AdapterDocument {\n kind: \"pptx\";\n slides: PptxSlide[];\n pageCount: number;\n /** Which slide and line each stretch of `text` came from. */\n textIndex?: TextIndex<PptxRef>;\n}\n\n/** Indent per outline level. Four rungs is as deep as a readable slide ever goes. */\nconst LEVEL_INDENT = [\"ps-0\", \"ps-4\", \"ps-8\", \"ps-12\"] as const;\n\n/** The slide column's own cap, matching the `max-w-3xl` on the frame. */\nconst SLIDE_MAX_WIDTH = 768;\n\n/** Space between two slides in the column, in CSS pixels. */\nconst SLIDE_GAP = 16;\n\n/** Room reserved for a slide's speaker notes before they are measured. */\nconst NOTES_ESTIMATE = 72;\n\nclass PptxAdapter implements FileAdapter {\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<PptxDocument> {\n let buffer: ArrayBuffer;\n try {\n buffer = await source.bytes(context.signal);\n } catch (error) {\n throw toViewerError(error, \"read-failed\", { fileName: source.name });\n }\n\n // Dynamic: the ONLY edge to the optional peer (heavy-deps:check).\n const JSZip = (await import(\"jszip\")).default;\n\n try {\n const zip = await JSZip.loadAsync(buffer);\n const parser = new DOMParser();\n const parse = (xml: string) => parser.parseFromString(xml, \"application/xml\");\n\n const slidePaths = orderSlidePaths(Object.keys(zip.files));\n if (slidePaths.length === 0) {\n throw new ViewerError(\"parse-failed\", \"The presentation contains no slides.\", {\n fileName: source.name,\n });\n }\n\n const slides: PptxSlide[] = [];\n for (const [position, path] of slidePaths.entries()) {\n if (context.signal?.aborted) break;\n const xml = await zip.file(path)?.async(\"string\");\n if (!xml) continue;\n const slide = parseSlide(parse(xml), position + 1);\n\n // Notes are best-effort: a deck with no notes part, or one whose\n // relationships do not resolve, is a complete deck — not a failure.\n const relsXml = await zip\n .file(`${dirOf(path)}/_rels/${baseOf(path)}.rels`)\n ?.async(\"string\");\n const notesPath = relsXml ? notesTarget(parse(relsXml), path) : undefined;\n const notesXml = notesPath ? await zip.file(notesPath)?.async(\"string\") : undefined;\n if (notesXml) slide.notes = parseNotes(parse(notesXml));\n\n slides.push(slide);\n }\n\n const textIndex = slidesToTextWithMap(slides);\n return {\n kind: \"pptx\",\n slides,\n pageCount: slides.length,\n text: textIndex.text,\n textIndex,\n };\n } catch (error) {\n throw toViewerError(error, \"parse-failed\", { fileName: source.name });\n }\n }\n}\n\nfunction dirOf(path: string): string {\n return path.slice(0, path.lastIndexOf(\"/\"));\n}\n\nfunction baseOf(path: string): string {\n return path.slice(path.lastIndexOf(\"/\") + 1);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Renderer */\n/* -------------------------------------------------------------------------- */\n\nfunction PptxRenderer({\n document: doc,\n className,\n baseHeadingLevel = 2,\n highlights,\n activeHighlightId,\n pageNumber,\n onPageChange,\n}: AdapterRendererProps) {\n const deck = doc as PptxDocument;\n // One pager for every paginated format, so a deck's slides and a PDF's pages\n // are driven by the same shell control (ADR 0026). 1-based on the wire; this\n // renderer's array is 0-based, and the conversion stays local.\n const [slideNumber, goToSlide] = usePageControl(pageNumber, onPageChange, deck.slides.length);\n const listRef = useRef<HTMLDivElement>(null);\n const viewport = useViewportSize(listRef);\n\n const marks = useMemo(\n () => toMarkRanges(highlights, deck.text?.length ?? 0),\n [highlights, deck.text],\n );\n\n // A slide frame is 16:9 inside a capped column, so its height follows from the\n // pane's width — no measurement of the slide itself is needed for the first\n // frame. `measureElement` corrects a slide whose outline overflows the ratio,\n // and whose notes are longer than the estimate.\n const frameWidth = Math.min(SLIDE_MAX_WIDTH, (viewport?.width ?? SLIDE_MAX_WIDTH) - SLIDE_GAP);\n const estimateSize = useCallback(\n (index: number) =>\n Math.round((frameWidth * 9) / 16) +\n SLIDE_GAP +\n (deck.slides[index]?.notes ? NOTES_ESTIMATE : 0),\n [frameWidth, deck.slides],\n );\n\n const virtualizer = usePagedScroll({\n count: deck.slides.length,\n listRef,\n pageNumber: slideNumber,\n goToPage: goToSlide,\n estimateSize,\n sizeKey: frameWidth,\n });\n\n // Where each line of the deck begins in the projection, keyed by slide. Built\n // once for the whole deck rather than per slide: several slides are on screen\n // at a time now, and one pass over the spans is cheaper than one pass per\n // visible slide on every scroll.\n const starts = useMemo(() => {\n const map = new Map<number, Map<number, number>>();\n for (const span of deck.textIndex?.spans ?? []) {\n const slide = map.get(span.ref.slide) ?? new Map<number, number>();\n slide.set(span.ref.line, span.start);\n map.set(span.ref.slide, slide);\n }\n return map;\n }, [deck.textIndex]);\n\n // Scrolling to the cited slide is this format's half of \"take me there\". Keyed\n // on the slide NUMBER, so a reader who scrolls away while the same citation is\n // still active is not dragged back (the same trade the PDF column makes).\n const activeSlide = useMemo(() => {\n const active = highlights?.find((highlight) => highlight.id === activeHighlightId);\n if (!active || active.status !== \"resolved\" || !active.range || !deck.textIndex) {\n return undefined;\n }\n return spanAt(deck.textIndex, active.range[0])?.ref.slide;\n }, [highlights, activeHighlightId, deck.textIndex]);\n useEffect(() => {\n if (activeSlide === undefined) return;\n const position = deck.slides.findIndex((candidate) => candidate.index === activeSlide);\n if (position >= 0) goToSlide(position + 1);\n }, [activeSlide, deck.slides, goToSlide]);\n\n // The mark only exists once the cited slide is mounted, so the scroll waits\n // for the slide as well as for the id.\n useScrollActiveHighlightIntoView(listRef, activeHighlightId, slideNumber);\n\n return (\n // No viewport of its own: the slide chrome moved to the shell (ADR 0026), so\n // there is no fixed control above a scrolling body and `FileViewerContent`\n // is the one scroll boundary (`viewer-components.md`).\n <div\n ref={listRef}\n data-slot=\"pptx-slides\"\n className={cn(\"relative w-full\", className)}\n style={{ height: virtualizer.getTotalSize() }}\n >\n {virtualizer.getVirtualItems().map((item) => {\n const slide = deck.slides[item.index];\n if (!slide) return null;\n return (\n <div\n key={item.key}\n data-index={item.index}\n ref={virtualizer.measureElement}\n className=\"absolute inset-x-0 top-0\"\n style={{\n paddingBottom: SLIDE_GAP,\n transform: `translateY(${item.start - virtualizer.options.scrollMargin}px)`,\n }}\n >\n <PptxSlideView\n slide={slide}\n slideNumber={item.index + 1}\n baseHeadingLevel={baseHeadingLevel}\n marks={marks}\n starts={starts.get(slide.index)}\n />\n </div>\n );\n })}\n </div>\n );\n}\n\ninterface PptxSlideViewProps {\n slide: PptxSlide;\n /** 1-based position in the deck, which is what the reader is shown. */\n slideNumber: number;\n baseHeadingLevel: ProseHeadingLevel;\n marks: MarkRanges;\n /** Where each of this slide's lines begins in the projection. */\n starts?: Map<number, number>;\n}\n\n/** One slide: the 16:9 frame, its outline, and any speaker notes beneath it. */\nfunction PptxSlideView({\n slide,\n slideNumber,\n baseHeadingLevel,\n marks,\n starts,\n}: PptxSlideViewProps) {\n const { t, formatNumber } = useLocale();\n const isEmpty = !slide.title && slide.lines.length === 0;\n\n return (\n <>\n {/* The slide surface: `bg-card` above the pane's ground, `aspect-video`\n so a deck still reads as a deck — this is the shape of the thing,\n which is the one part of the layout an outline can honestly keep. */}\n {/* A slide that overflows its 16:9 frame scrolls, and a scrollable\n region with no focusable content cannot be reached by keyboard\n (WCAG 2.1.1). `tabIndex={0}` makes the slide itself the stop that\n arrow keys and Page Up/Down drive. This is the one nested scroller the\n rule allows: a fixed-ratio frame whose content may not fit it. */}\n <section\n tabIndex={0}\n data-slot=\"pptx-slide\"\n data-page={slideNumber}\n aria-label={t(\"viewer.pptx.slide\", {\n slide: formatNumber(slideNumber),\n })}\n className=\"border-border bg-card focus-ring mx-auto flex aspect-video w-full max-w-3xl flex-col gap-3 overflow-auto rounded-md border p-6 shadow-sm\"\n >\n {/* A slide title is the deck's top rung, so it sits at the host's base.\n The stand-in for an untitled slide is OUR text, not the deck's, so\n it is not in the projection and cannot be cited. */}\n <ProseHeading level={baseHeadingLevel}>\n {slide.title === undefined ? (\n t(\"viewer.pptx.untitled\")\n ) : (\n <MarkedText text={slide.title} marks={marks} start={starts?.get(PPTX_TITLE_LINE)} />\n )}\n </ProseHeading>\n {isEmpty ? (\n <p className=\"text-muted-foreground text-body\">{t(\"viewer.pptx.empty\")}</p>\n ) : (\n <ul className=\"text-body space-y-1.5\">\n {slide.lines.map((line, lineIndex) => (\n <li\n key={lineIndex}\n className={cn(\"whitespace-pre-wrap\", LEVEL_INDENT[Math.min(line.level, 3)])}\n >\n <MarkedText text={line.text} marks={marks} start={starts?.get(lineIndex)} />\n </li>\n ))}\n </ul>\n )}\n </section>\n\n {slide.notes && (\n <section\n aria-label={t(\"viewer.pptx.notes\")}\n className=\"mx-auto mt-3 w-full max-w-3xl space-y-1\"\n >\n <h3 className=\"text-meta text-muted-foreground\">{t(\"viewer.pptx.notes\")}</h3>\n <p className=\"text-body text-muted-foreground whitespace-pre-wrap\">\n <MarkedText text={slide.notes} marks={marks} start={starts?.get(PPTX_NOTES_LINE)} />\n </p>\n </section>\n )}\n </>\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: pptxManifest,\n create: () => new PptxAdapter(),\n Renderer: PptxRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ pptxManifest
4
+ } from "../../chunk-FDT4QOIG.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ pptxManifest
8
+ };
9
+ //# sourceMappingURL=pptx-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,37 @@
1
+ "use client";
2
+ import {
3
+ DRAWING_NS,
4
+ PPTX_LINE_SEPARATOR,
5
+ PPTX_NOTES_LINE,
6
+ PPTX_SLIDE_SEPARATOR,
7
+ PPTX_TITLE_LINE,
8
+ PRESENTATION_NS,
9
+ RELATIONSHIP_NS,
10
+ notesTarget,
11
+ orderSlidePaths,
12
+ parseNotes,
13
+ parseSlide,
14
+ resolveRelative,
15
+ slideNumber,
16
+ slidesToText,
17
+ slidesToTextWithMap
18
+ } from "../../chunk-US5KT3TR.js";
19
+ import "../../chunk-5YE2MUS2.js";
20
+ export {
21
+ DRAWING_NS,
22
+ PPTX_LINE_SEPARATOR,
23
+ PPTX_NOTES_LINE,
24
+ PPTX_SLIDE_SEPARATOR,
25
+ PPTX_TITLE_LINE,
26
+ PRESENTATION_NS,
27
+ RELATIONSHIP_NS,
28
+ notesTarget,
29
+ orderSlidePaths,
30
+ parseNotes,
31
+ parseSlide,
32
+ resolveRelative,
33
+ slideNumber,
34
+ slidesToText,
35
+ slidesToTextWithMap
36
+ };
37
+ //# sourceMappingURL=pptx-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -2,14 +2,17 @@
2
2
  "use client";
3
3
  import {
4
4
  textManifest
5
- } from "./chunk-UJIJECEF.js";
5
+ } from "../../chunk-ZAVXZRIO.js";
6
6
  import {
7
- toMarkRanges,
8
7
  useScrollActiveHighlightIntoView
9
- } from "./chunk-VO2273Z2.js";
8
+ } from "../../chunk-IB4N72FA.js";
9
+ import {
10
+ toMarkRanges
11
+ } from "../../chunk-HOQZ7OPH.js";
10
12
  import {
11
13
  toViewerError
12
- } from "./chunk-AORNMH77.js";
14
+ } from "../../chunk-JHFC2KBI.js";
15
+ import "../../chunk-CIT2HHRI.js";
13
16
 
14
17
  // src/adapters/text/text-adapter.tsx
15
18
  import { useMemo, useRef } from "react";
@@ -78,4 +81,4 @@ export {
78
81
  TEXT_CHARACTER_LIMIT,
79
82
  text_adapter_default as default
80
83
  };
81
- //# sourceMappingURL=text-adapter-NFNWB5W3.js.map
84
+ //# sourceMappingURL=text-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/text/text-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Plain-text adapter — the fallback for anything readable as UTF-8.\n *\n * Deliberately does NOT do SYNTAX highlighting — that is the separate `code`\n * adapter, registered at a higher priority for code extensions. Keeping them\n * apart means a 40 MB log file never drags a tokenizer into the bundle, and a\n * consumer can drop the tokenizer without losing plain text. (Citation and\n * find-in-document marks are a different thing entirely and DO render here.)\n *\n * Large files are truncated at load, not at render: putting ten million\n * characters into one `<pre>` locks the main thread with no way back. The cut is\n * reported so the UI can say so rather than silently lying about the content.\n */\n\nimport { useMemo, useRef } from \"react\";\n\nimport { MatchHighlight, cn, useLocale } from \"@elabs-ai/components-ui\";\nimport type { ResolvedFileSource } from \"@elabs-ai/components-ui\";\n\nimport { toViewerError } from \"../../core/errors\";\nimport { toMarkRanges } from \"../../core/highlight-marks\";\nimport { useScrollActiveHighlightIntoView } from \"../../core/use-highlight-scroll\";\nimport type {\n AdapterDocument,\n AdapterLoadContext,\n AdapterModule,\n AdapterRendererProps,\n FileAdapter,\n} from \"../../core/types\";\nimport { textManifest } from \"./text-manifest\";\n\n/**\n * Characters kept before truncation. ~2M is comfortably past any file a person\n * reads in a preview pane and still renders in one frame.\n */\nexport const TEXT_CHARACTER_LIMIT = 2_000_000;\n\nexport interface TextDocument extends AdapterDocument {\n kind: \"text\";\n text: string;\n /** Total characters in the file, when more than what is shown. */\n totalCharacters?: number;\n}\n\nclass TextAdapter implements FileAdapter {\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<TextDocument> {\n let raw: string;\n try {\n raw = await source.text(context.signal);\n } catch (error) {\n throw toViewerError(error, \"read-failed\", { fileName: source.name });\n }\n\n if (raw.length <= TEXT_CHARACTER_LIMIT) return { kind: \"text\", text: raw };\n return {\n kind: \"text\",\n text: raw.slice(0, TEXT_CHARACTER_LIMIT),\n totalCharacters: raw.length,\n // So a passage the shell cannot find is reported as \"past the part we\n // previewed\" rather than \"not in this document\" — different news.\n textTruncated: true,\n };\n }\n}\n\nfunction TextRenderer({\n document: doc,\n className,\n highlights,\n activeHighlightId,\n}: AdapterRendererProps) {\n const text = doc as TextDocument;\n const { t, formatNumber } = useLocale();\n const container = useRef<HTMLDivElement>(null);\n const { ranges, activeIndex } = useMemo(\n () => toMarkRanges(highlights, text.text.length),\n [highlights, text.text.length],\n );\n useScrollActiveHighlightIntoView(container, activeHighlightId);\n\n return (\n // No `overflow-auto` here: `FileViewerContent` is the scroll boundary, and\n // nesting a second one clips the text above the outer pane's own padding.\n <div ref={container} className={cn(\"flex flex-col gap-2\", className)}>\n {text.totalCharacters !== undefined && (\n // Not an error — the file is fine, we are showing part of it. A status\n // region, so AT hears it once rather than on every scroll.\n <p role=\"status\" className=\"text-meta text-muted-foreground\">\n {t(\"viewer.text.truncated\", {\n shown: formatNumber(text.text.length),\n total: formatNumber(text.totalCharacters),\n })}\n </p>\n )}\n <pre className=\"text-code font-mono break-words whitespace-pre-wrap\">\n {ranges.length === 0 ? (\n text.text\n ) : (\n // `MatchHighlight` renders the WHOLE string with the matches wrapped,\n // so nothing is lost when a highlight is present — a screen reader\n // still reads the file continuously.\n <MatchHighlight text={text.text} ranges={ranges} activeIndex={activeIndex} />\n )}\n </pre>\n </div>\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: textManifest,\n create: () => new TextAdapter(),\n Renderer: TextRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":";;;;;;;;;;;;;;;;;AAgBA,SAAS,SAAS,cAAc;AAEhC,SAAS,gBAAgB,IAAI,iBAAiB;AAmE1C,SAII,KAJJ;AAhDG,IAAM,uBAAuB;AASpC,IAAM,cAAN,MAAyC;AAAA,EACvC,MAAM,KAAK,QAA4B,SAAoD;AACzF,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,OAAO,KAAK,QAAQ,MAAM;AAAA,IACxC,SAAS,OAAO;AACd,YAAM,cAAc,OAAO,eAAe,EAAE,UAAU,OAAO,KAAK,CAAC;AAAA,IACrE;AAEA,QAAI,IAAI,UAAU,qBAAsB,QAAO,EAAE,MAAM,QAAQ,MAAM,IAAI;AACzE,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM,IAAI,MAAM,GAAG,oBAAoB;AAAA,MACvC,iBAAiB,IAAI;AAAA;AAAA;AAAA,MAGrB,eAAe;AAAA,IACjB;AAAA,EACF;AACF;AAEA,SAAS,aAAa;AAAA,EACpB,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,OAAO;AACb,QAAM,EAAE,GAAG,aAAa,IAAI,UAAU;AACtC,QAAM,YAAY,OAAuB,IAAI;AAC7C,QAAM,EAAE,QAAQ,YAAY,IAAI;AAAA,IAC9B,MAAM,aAAa,YAAY,KAAK,KAAK,MAAM;AAAA,IAC/C,CAAC,YAAY,KAAK,KAAK,MAAM;AAAA,EAC/B;AACA,mCAAiC,WAAW,iBAAiB;AAE7D;AAAA;AAAA;AAAA,IAGE,qBAAC,SAAI,KAAK,WAAW,WAAW,GAAG,uBAAuB,SAAS,GAChE;AAAA,WAAK,oBAAoB;AAAA;AAAA,MAGxB,oBAAC,OAAE,MAAK,UAAS,WAAU,mCACxB,YAAE,yBAAyB;AAAA,QAC1B,OAAO,aAAa,KAAK,KAAK,MAAM;AAAA,QACpC,OAAO,aAAa,KAAK,eAAe;AAAA,MAC1C,CAAC,GACH;AAAA,MAEF,oBAAC,SAAI,WAAU,uDACZ,iBAAO,WAAW,IACjB,KAAK;AAAA;AAAA;AAAA;AAAA,QAKL,oBAAC,kBAAe,MAAM,KAAK,MAAM,QAAgB,aAA0B;AAAA,SAE/E;AAAA,OACF;AAAA;AAEJ;AAEA,IAAM,gBAA+B;AAAA,EACnC,UAAU;AAAA,EACV,QAAQ,MAAM,IAAI,YAAY;AAAA,EAC9B,UAAU;AACZ;AAEA,IAAO,uBAAQ;","names":[]}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ textManifest
4
+ } from "../../chunk-ZAVXZRIO.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ textManifest
8
+ };
9
+ //# sourceMappingURL=text-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -2,22 +2,26 @@
2
2
  "use client";
3
3
  import {
4
4
  xlsxManifest
5
- } from "./chunk-RGWDIQJR.js";
5
+ } from "../../chunk-7EASJBQM.js";
6
+ import {
7
+ SheetTable
8
+ } from "../../chunk-AK7F3IZE.js";
6
9
  import {
7
- SheetTable,
8
10
  gridToText
9
- } from "./chunk-XBOR2YXS.js";
10
- import "./chunk-2NQ4RSJ3.js";
11
+ } from "../../chunk-TLCNGQKL.js";
12
+ import "../../chunk-GNBD53AT.js";
11
13
  import {
12
14
  spanAt
13
- } from "./chunk-UL43NGUG.js";
15
+ } from "../../chunk-5YE2MUS2.js";
16
+ import "../../chunk-IB4N72FA.js";
14
17
  import {
15
18
  toMarkRanges
16
- } from "./chunk-VO2273Z2.js";
19
+ } from "../../chunk-HOQZ7OPH.js";
17
20
  import {
18
21
  ViewerError,
19
22
  toViewerError
20
- } from "./chunk-AORNMH77.js";
23
+ } from "../../chunk-JHFC2KBI.js";
24
+ import "../../chunk-CIT2HHRI.js";
21
25
 
22
26
  // src/adapters/xlsx/xlsx-adapter.tsx
23
27
  import { cn, Tabs, TabsContent, TabsList, TabsTrigger, useLocale } from "@elabs-ai/components-ui";
@@ -164,4 +168,4 @@ export {
164
168
  xlsx_adapter_default as default,
165
169
  looksLikeWorkbook
166
170
  };
167
- //# sourceMappingURL=xlsx-adapter-O3XIVLFC.js.map
171
+ //# sourceMappingURL=xlsx-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/xlsx/xlsx-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Spreadsheet adapter — a workbook becomes sheets of rows, and rows become a\n * real `Table`.\n *\n * SheetJS is only ever asked for the DATA. Its `sheet_to_html` helper exists and\n * is not used: it returns a markup string with its own inline styling, which is\n * exactly the \"adapter emits HTML\" failure this package was built to avoid\n * (ADR 0024 §3). `sheet_to_json({ header: 1 })` gives raw cell values, which the\n * shared `SheetTable` renders with brand-ui components — so a spreadsheet\n * inherits the theme, the density dial and the keyboard semantics.\n *\n * **`xlsx` is an optional peer with two known advisories.** The npm build\n * (`0.18.5`) carries a prototype-pollution and a ReDoS advisory, both fixed only\n * in SheetJS's self-hosted CDN builds, which are not published to npm. That is a\n * documented, deliberate trade (`docs/CONSUMING.md` §6): a consumer who never\n * opens a spreadsheet never installs it and is never exposed. Treat any workbook\n * opened here as untrusted input.\n */\n\nimport type { ResolvedFileSource } from \"@elabs-ai/components-ui\";\nimport { cn, Tabs, TabsContent, TabsList, TabsTrigger, useLocale } from \"@elabs-ai/components-ui\";\nimport { useEffect, useMemo, useState } from \"react\";\n\nimport { gridToText, type GridRef } from \"../../components/grid-text\";\nimport { SheetTable } from \"../../components/sheet-table\";\nimport { ViewerError, toViewerError } from \"../../core/errors\";\nimport { toMarkRanges } from \"../../core/highlight-marks\";\nimport { spanAt, type TextIndex } from \"../../core/text-index\";\nimport type {\n AdapterDocument,\n AdapterLoadContext,\n AdapterModule,\n AdapterRendererProps,\n FileAdapter,\n} from \"../../core/types\";\nimport { xlsxManifest } from \"./xlsx-manifest\";\n\n/**\n * Rows rendered per sheet before truncation. Same bound, same reason, as the CSV\n * adapter: a preview pane is for looking, and a real analysis grid is\n * `DataTable` in `@elabs-ai/components-data`.\n */\nexport const XLSX_ROW_LIMIT = 5_000;\n\nexport interface SheetModel {\n /** The tab's own name, as authored in the workbook. */\n name: string;\n /** Header cells, taken from the sheet's first row. */\n columns: string[];\n /** Body rows, already capped at {@link XLSX_ROW_LIMIT}. */\n rows: string[][];\n /** Total body rows in the sheet, when more than what is shown. */\n totalRows?: number;\n}\n\nexport interface XlsxDocument extends AdapterDocument {\n kind: \"xlsx\";\n sheets: SheetModel[];\n /** Which sheet and row each stretch of `text` came from. */\n textIndex?: TextIndex<GridRef>;\n}\n\n/**\n * Does this look like a workbook container at all?\n *\n * SheetJS sniffs its input and will happily read arbitrary text as a one-column\n * CSV — so a damaged `.xlsx` comes back as a sheet holding one junk cell instead\n * of failing. That is worse than an error: it looks like the file opened. Both\n * containers this adapter claims have a fixed signature — OOXML/ODS is a zip\n * (`PK\\x03\\x04`), legacy `.xls` is a CFB compound file — so anything else is\n * rejected before SheetJS gets a chance to be helpful.\n */\nexport function looksLikeWorkbook(bytes: Uint8Array): boolean {\n const zip = [0x50, 0x4b, 0x03, 0x04];\n const cfb = [0xd0, 0xcf, 0x11, 0xe0];\n return [zip, cfb].some((signature) => signature.every((byte, index) => bytes[index] === byte));\n}\n\n/** SheetJS returns whatever the cell held — a date, a number, a formula result. */\nfunction toCellText(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (value instanceof Date) return value.toISOString().slice(0, 10);\n return String(value);\n}\n\nclass XlsxAdapter implements FileAdapter {\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<XlsxDocument> {\n let buffer: ArrayBuffer;\n try {\n buffer = await source.bytes(context.signal);\n } catch (error) {\n throw toViewerError(error, \"read-failed\", { fileName: source.name });\n }\n\n const bytes = new Uint8Array(buffer);\n if (!looksLikeWorkbook(bytes)) {\n throw new ViewerError(\"parse-failed\", \"The file is not a spreadsheet container.\", {\n fileName: source.name,\n });\n }\n\n // Dynamic: the ONLY edge to the optional peer (heavy-deps:check).\n const XLSX = await import(\"xlsx\");\n\n try {\n // `cellDates` so a date column reads as a date rather than as Excel's\n // serial day number, which is meaningless to a person looking at it.\n const workbook = XLSX.read(bytes, { type: \"array\", cellDates: true });\n const sheets = workbook.SheetNames.map((name) => {\n const sheet = workbook.Sheets[name];\n const grid: unknown[][] = sheet\n ? XLSX.utils.sheet_to_json(sheet, { header: 1, blankrows: false, defval: \"\" })\n : [];\n const [header = [], ...body] = grid;\n const columns = header.map(toCellText);\n const rows = body.slice(0, XLSX_ROW_LIMIT).map((row) => row.map(toCellText));\n return body.length > XLSX_ROW_LIMIT\n ? { name, columns, rows, totalRows: body.length }\n : { name, columns, rows };\n });\n\n if (sheets.length === 0) {\n throw new ViewerError(\"parse-failed\", \"The workbook contains no sheets.\", {\n fileName: source.name,\n });\n }\n\n // The projection is built by the shared grid builder rather than joined by\n // hand, so the text a citation is addressed against and the map back into\n // the cells cannot drift apart (`core/text-index.ts`).\n const textIndex = gridToText(sheets);\n return {\n kind: \"xlsx\",\n sheets,\n pageCount: sheets.length,\n text: textIndex.text,\n textIndex,\n };\n } catch (error) {\n throw toViewerError(error, \"parse-failed\", { fileName: source.name });\n }\n }\n}\n\nfunction XlsxRenderer({\n document: doc,\n className,\n highlights,\n activeHighlightId,\n}: AdapterRendererProps) {\n const workbook = doc as XlsxDocument;\n const { t } = useLocale();\n const [first] = workbook.sheets;\n\n const marks = useMemo(\n () => toMarkRanges(highlights, workbook.text?.length ?? 0),\n [highlights, workbook.text],\n );\n\n // Where each row of each sheet begins in the projection. Built once per\n // document rather than per tab, because switching sheets must not re-walk the\n // spans of every OTHER sheet to answer a question about this one.\n const starts = useMemo(() => {\n const bySheet = new Map<number, Map<number, number>>();\n for (const span of workbook.textIndex?.spans ?? []) {\n let rows = bySheet.get(span.ref.sheet);\n if (!rows) {\n rows = new Map<number, number>();\n bySheet.set(span.ref.sheet, rows);\n }\n rows.set(span.ref.row, span.start);\n }\n return bySheet;\n }, [workbook.textIndex]);\n const rowStartFor = (sheet: number) => (row: number) => starts.get(sheet)?.get(row);\n\n // Turning to the cited SHEET is this format's half of \"take me there\" — the\n // row scroll inside it belongs to `SheetTable`. Keyed on the sheet NAME, so a\n // reader who switches tabs while the same citation stays active is not\n // dragged back (the PDF pager makes the same trade).\n const activeSheet = useMemo(() => {\n const active = highlights?.find((highlight) => highlight.id === activeHighlightId);\n if (!active || active.status !== \"resolved\" || !active.range || !workbook.textIndex) {\n return undefined;\n }\n return spanAt(workbook.textIndex, active.range[0])?.ref.sheet;\n }, [highlights, activeHighlightId, workbook.textIndex]);\n const activeSheetName =\n activeSheet === undefined ? undefined : workbook.sheets[activeSheet]?.name;\n\n const [pinned, setPinned] = useState<string>();\n useEffect(() => {\n if (activeSheetName !== undefined) setPinned(activeSheetName);\n }, [activeSheetName]);\n\n // A one-sheet workbook is the common case, and a tab strip holding a single\n // tab is chrome that decides nothing — so it is not rendered.\n if (!first) return null;\n if (workbook.sheets.length === 1) {\n return (\n <SheetTable\n columns={first.columns}\n rows={first.rows}\n totalRows={first.totalRows}\n className={className}\n marks={marks}\n rowStart={rowStartFor(0)}\n activeHighlightId={activeHighlightId}\n />\n );\n }\n\n return (\n <Tabs\n value={pinned ?? first.name}\n onValueChange={setPinned}\n className={cn(\"flex h-full min-h-0 flex-col gap-2\", className)}\n >\n <TabsList aria-label={t(\"viewer.sheet.tabs\")} className=\"shrink-0 self-start\">\n {workbook.sheets.map((sheet) => (\n <TabsTrigger key={sheet.name} value={sheet.name}>\n {sheet.name}\n </TabsTrigger>\n ))}\n </TabsList>\n {workbook.sheets.map((sheet, index) => (\n <TabsContent key={sheet.name} value={sheet.name} className=\"mt-0 min-h-0 flex-1\">\n <SheetTable\n columns={sheet.columns}\n rows={sheet.rows}\n totalRows={sheet.totalRows}\n marks={marks}\n rowStart={rowStartFor(index)}\n activeHighlightId={activeHighlightId}\n />\n </TabsContent>\n ))}\n </Tabs>\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: xlsxManifest,\n create: () => new XlsxAdapter(),\n Renderer: XlsxRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ xlsxManifest
4
+ } from "../../chunk-7EASJBQM.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ xlsxManifest
8
+ };
9
+ //# sourceMappingURL=xlsx-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import {
3
+ findScrollHost
4
+ } from "./chunk-7PGGKQVY.js";
5
+
6
+ // src/core/use-viewport-size.ts
7
+ import { useEffect, useState } from "react";
8
+ function useViewportSize(ref) {
9
+ const [size, setSize] = useState();
10
+ useEffect(() => {
11
+ const host = findScrollHost(ref.current) ?? ref.current?.parentElement ?? ref.current;
12
+ if (!host || typeof ResizeObserver === "undefined") return;
13
+ const measure = () => {
14
+ const { clientWidth: width, clientHeight: height } = host;
15
+ if (width === 0 || height === 0) return;
16
+ setSize(
17
+ (current) => current && Math.abs(current.width - width) < 1 && Math.abs(current.height - height) < 1 ? current : { width, height }
18
+ );
19
+ };
20
+ measure();
21
+ const observer = new ResizeObserver(measure);
22
+ observer.observe(host);
23
+ return () => observer.disconnect();
24
+ }, [ref]);
25
+ return size;
26
+ }
27
+
28
+ export {
29
+ useViewportSize
30
+ };
31
+ //# sourceMappingURL=chunk-3HKQFFZW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/use-viewport-size.ts"],"sourcesContent":["\"use client\";\n\n/**\n * The size of the box a renderer scrolls inside, kept current.\n *\n * Needed because a fit-to-width scale is a function of the VIEWPORT, not of the\n * document: only the renderer can compute it, and only by measuring. Measures\n * the container rather than the window (`window.innerWidth` would be wrong the\n * moment a viewer sits in a resizable pane, a dialog or a split workspace).\n */\n\nimport { useEffect, useState, type RefObject } from \"react\";\n\nimport { findScrollHost } from \"./scroll-host\";\n\nexport interface ViewportSize {\n width: number;\n height: number;\n}\n\n/**\n * @param ref An element inside the scrolling box — typically the renderer's root.\n * @returns The scroll host's content size, or `undefined` until it is measured.\n */\nexport function useViewportSize(ref: RefObject<HTMLElement | null>): ViewportSize | undefined {\n const [size, setSize] = useState<ViewportSize>();\n\n useEffect(() => {\n const host = findScrollHost(ref.current) ?? ref.current?.parentElement ?? ref.current;\n if (!host || typeof ResizeObserver === \"undefined\") return;\n\n const measure = () => {\n const { clientWidth: width, clientHeight: height } = host;\n // A hidden pane measures zero. Re-fitting to a zero-width viewport would\n // rasterize a zero-width page and clear the canvas — and nothing would\n // measure again when the pane is shown, because its size did not change\n // from the observer's point of view. Ignoring the reading keeps the last\n // good one. (The guard extend-hq/ui's `useElementWidth` carries too.)\n if (width === 0 || height === 0) return;\n setSize((current) =>\n current && Math.abs(current.width - width) < 1 && Math.abs(current.height - height) < 1\n ? current\n : { width, height },\n );\n };\n\n measure();\n const observer = new ResizeObserver(measure);\n observer.observe(host);\n return () => observer.disconnect();\n }, [ref]);\n\n return size;\n}\n"],"mappings":";;;;;;AAWA,SAAS,WAAW,gBAAgC;AAa7C,SAAS,gBAAgB,KAA8D;AAC5F,QAAM,CAAC,MAAM,OAAO,IAAI,SAAuB;AAE/C,YAAU,MAAM;AACd,UAAM,OAAO,eAAe,IAAI,OAAO,KAAK,IAAI,SAAS,iBAAiB,IAAI;AAC9E,QAAI,CAAC,QAAQ,OAAO,mBAAmB,YAAa;AAEpD,UAAM,UAAU,MAAM;AACpB,YAAM,EAAE,aAAa,OAAO,cAAc,OAAO,IAAI;AAMrD,UAAI,UAAU,KAAK,WAAW,EAAG;AACjC;AAAA,QAAQ,CAAC,YACP,WAAW,KAAK,IAAI,QAAQ,QAAQ,KAAK,IAAI,KAAK,KAAK,IAAI,QAAQ,SAAS,MAAM,IAAI,IAClF,UACA,EAAE,OAAO,OAAO;AAAA,MACtB;AAAA,IACF;AAEA,YAAQ;AACR,UAAM,WAAW,IAAI,eAAe,OAAO;AAC3C,aAAS,QAAQ,IAAI;AACrB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AACT;","names":[]}