@elabs-ai/components-viewer 4.1.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 (207) 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 -1268
  173. package/dist/index.js.map +1 -1
  174. package/package.json +6 -6
  175. package/src/__contract__/file-viewer.contract.test.tsx +49 -0
  176. package/src/file-viewer/file-viewer-recipes.stories.tsx +406 -0
  177. package/src/file-viewer/file-viewer.stories.tsx +2 -2
  178. package/src/file-viewer/file-viewer.test.tsx +35 -1
  179. package/src/file-viewer/file-viewer.tsx +16 -3
  180. package/dist/chunk-4OFQYALG.js.map +0 -1
  181. package/dist/chunk-5OMONA2G.js.map +0 -1
  182. package/dist/chunk-AORNMH77.js.map +0 -1
  183. package/dist/chunk-SLXRUYT3.js.map +0 -1
  184. package/dist/chunk-VO2273Z2.js.map +0 -1
  185. package/dist/chunk-XBOR2YXS.js.map +0 -1
  186. package/dist/code-adapter-ADZ4UOGN.js.map +0 -1
  187. package/dist/csv-adapter-7HOFZ5Z6.js.map +0 -1
  188. package/dist/docx-adapter-5CQDHWTD.js.map +0 -1
  189. package/dist/image-adapter-WOHZR24J.js.map +0 -1
  190. package/dist/json-adapter-ZUW5GQHE.js.map +0 -1
  191. package/dist/markdown-adapter-YC6WTBS4.js.map +0 -1
  192. package/dist/media-adapter-MCTB4GBH.js.map +0 -1
  193. package/dist/pdf-adapter-5PMKEXUD.js.map +0 -1
  194. package/dist/pptx-adapter-BONWFHYT.js.map +0 -1
  195. package/dist/text-adapter-NFNWB5W3.js.map +0 -1
  196. package/dist/xlsx-adapter-O3XIVLFC.js.map +0 -1
  197. /package/dist/{chunk-UL43NGUG.js.map → chunk-5YE2MUS2.js.map} +0 -0
  198. /package/dist/{chunk-RGWDIQJR.js.map → chunk-7EASJBQM.js.map} +0 -0
  199. /package/dist/{chunk-3U3MESBU.js.map → chunk-EA72HA4I.js.map} +0 -0
  200. /package/dist/{chunk-KOMDRWOU.js.map → chunk-FDT4QOIG.js.map} +0 -0
  201. /package/dist/{chunk-BCF3RWRL.js.map → chunk-GH4UBYST.js.map} +0 -0
  202. /package/dist/{chunk-2NQ4RSJ3.js.map → chunk-GNBD53AT.js.map} +0 -0
  203. /package/dist/{chunk-GGR7BNW4.js.map → chunk-HUUJIFFT.js.map} +0 -0
  204. /package/dist/{chunk-FELIAGKI.js.map → chunk-I5XD2NJ6.js.map} +0 -0
  205. /package/dist/{chunk-HMG2ERXH.js.map → chunk-YA72QE57.js.map} +0 -0
  206. /package/dist/{chunk-H3OAON3D.js.map → chunk-YWHFMCS4.js.map} +0 -0
  207. /package/dist/{chunk-UJIJECEF.js.map → chunk-ZAVXZRIO.js.map} +0 -0
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import {
3
+ createDefaultRegistry
4
+ } from "../chunk-QIPKBOZJ.js";
5
+ import "../chunk-BWMXMHVZ.js";
6
+ import {
7
+ pptxManifest
8
+ } from "../chunk-FDT4QOIG.js";
9
+ import {
10
+ textManifest
11
+ } from "../chunk-ZAVXZRIO.js";
12
+ import {
13
+ xlsxManifest
14
+ } from "../chunk-7EASJBQM.js";
15
+ import {
16
+ mediaManifest
17
+ } from "../chunk-YA72QE57.js";
18
+ import {
19
+ pdfManifest
20
+ } from "../chunk-M77ICVWP.js";
21
+ import {
22
+ imageManifest
23
+ } from "../chunk-HUUJIFFT.js";
24
+ import {
25
+ jsonManifest
26
+ } from "../chunk-GH4UBYST.js";
27
+ import {
28
+ markdownManifest
29
+ } from "../chunk-YWHFMCS4.js";
30
+ import {
31
+ codeManifest
32
+ } from "../chunk-CMYBLW7D.js";
33
+ import "../chunk-6FVJ4D7W.js";
34
+ import {
35
+ csvManifest
36
+ } from "../chunk-EA72HA4I.js";
37
+ import {
38
+ docxManifest
39
+ } from "../chunk-I5XD2NJ6.js";
40
+ import "../chunk-JHFC2KBI.js";
41
+ import "../chunk-CIT2HHRI.js";
42
+ export {
43
+ codeManifest,
44
+ createDefaultRegistry,
45
+ csvManifest,
46
+ docxManifest,
47
+ imageManifest,
48
+ jsonManifest,
49
+ markdownManifest,
50
+ mediaManifest,
51
+ pdfManifest,
52
+ pptxManifest,
53
+ textManifest,
54
+ xlsxManifest
55
+ };
56
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -2,11 +2,12 @@
2
2
  "use client";
3
3
  import {
4
4
  jsonManifest
5
- } from "./chunk-BCF3RWRL.js";
5
+ } from "../../chunk-GH4UBYST.js";
6
6
  import {
7
7
  ViewerError,
8
8
  toViewerError
9
- } from "./chunk-AORNMH77.js";
9
+ } from "../../chunk-JHFC2KBI.js";
10
+ import "../../chunk-CIT2HHRI.js";
10
11
 
11
12
  // src/adapters/json/json-adapter.tsx
12
13
  import { cn, Tree, useLocale } from "@elabs-ai/components-ui";
@@ -87,4 +88,4 @@ export {
87
88
  json_adapter_default as default,
88
89
  toTreeNodes
89
90
  };
90
- //# sourceMappingURL=json-adapter-ZUW5GQHE.js.map
91
+ //# sourceMappingURL=json-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/json/json-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * JSON adapter — parses to a real value and renders it as a collapsible tree.\n *\n * Why a tree and not a pretty-printed `<pre>`: the whole reason to open a JSON\n * file in a viewer rather than an editor is to find something in it. A tree\n * collapses the parts you are not reading, and `@elabs-ai/components-ui`'s\n * `Tree` already ships the keyboard model, roving tabindex and virtualization,\n * so this adapter contributes the MAPPING and nothing else.\n *\n * Invalid JSON is a terminal `parse-failed`, reported with the position the\n * engine gave us — not a silent fall-through to plain text, which would hide\n * the one fact the user needs.\n */\n\nimport { cn, Tree, type TreeNode, useLocale } from \"@elabs-ai/components-ui\";\nimport type { ResolvedFileSource } from \"@elabs-ai/components-ui\";\n\nimport { ViewerError, toViewerError } from \"../../core/errors\";\nimport type {\n AdapterDocument,\n AdapterLoadContext,\n AdapterModule,\n AdapterRendererProps,\n FileAdapter,\n} from \"../../core/types\";\nimport { jsonManifest } from \"./json-manifest\";\n\nexport interface JsonDocument extends AdapterDocument {\n kind: \"json\";\n /** The parsed value. `unknown` on purpose — it is whatever the file held. */\n value: unknown;\n /** The original source text, for the raw view and for copy. */\n text: string;\n}\n\n/** A one-line preview of a value, used as the collapsed label for a container. */\nfunction summarize(value: unknown): string {\n if (Array.isArray(value)) return `[${String(value.length)}]`;\n if (value !== null && typeof value === \"object\") {\n return `{${String(Object.keys(value).length)}}`;\n }\n if (typeof value === \"string\") return `\"${value}\"`;\n return String(value);\n}\n\n/** True for a value that has children worth expanding. */\nfunction isContainer(value: unknown): value is Record<string, unknown> | unknown[] {\n return value !== null && typeof value === \"object\";\n}\n\n/**\n * Map a parsed value onto `Tree` nodes.\n *\n * Ids are the JSON path (`$.items[2].name`), which makes them stable across\n * re-renders and directly usable as a \"reveal this node\" target later.\n */\nexport function toTreeNodes(value: unknown, path = \"$\"): TreeNode[] {\n if (!isContainer(value)) return [];\n\n const entries: [string, unknown][] = Array.isArray(value)\n ? value.map((item, index) => [String(index), item])\n : Object.entries(value);\n\n return entries.map(([key, child]) => {\n const childPath = Array.isArray(value) ? `${path}[${key}]` : `${path}.${key}`;\n const container = isContainer(child);\n return {\n id: childPath,\n label: (\n <span className=\"font-mono\">\n <span className=\"text-foreground\">{key}</span>\n <span className=\"text-muted-foreground\">: </span>\n <span className={container ? \"text-muted-foreground\" : \"text-info-text\"}>\n {summarize(child)}\n </span>\n </span>\n ),\n children: container ? toTreeNodes(child, childPath) : undefined,\n };\n });\n}\n\nclass JsonAdapter implements FileAdapter {\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<JsonDocument> {\n let text: string;\n try {\n text = await source.text(context.signal);\n } catch (error) {\n throw toViewerError(error, \"read-failed\", { fileName: source.name });\n }\n\n try {\n return { kind: \"json\", value: JSON.parse(text) as unknown, text };\n } catch (error) {\n throw new ViewerError(\n \"parse-failed\",\n error instanceof Error ? error.message : \"Invalid JSON.\",\n { fileName: source.name, cause: error },\n );\n }\n }\n}\n\nfunction JsonRenderer({ document: doc, className }: AdapterRendererProps) {\n const json = doc as JsonDocument;\n const { t } = useLocale();\n const nodes = toTreeNodes(json.value);\n\n // A scalar top level (`42`, `\"hello\"`, `null`) has no children to expand —\n // a tree of nothing would read as an empty state, which it is not.\n if (nodes.length === 0) {\n return (\n <pre className={cn(\"text-code font-mono break-words whitespace-pre-wrap\", className)}>\n {json.text}\n </pre>\n );\n }\n\n return (\n <Tree\n aria-label={t(\"viewer.json.tree\")}\n nodes={nodes}\n // The top level open, everything below collapsed: enough to see the shape\n // without paying to build a DOM for a deeply nested document.\n defaultExpandedIds={nodes.map((node) => node.id)}\n selectionMode=\"none\"\n virtualize\n className={cn(\"h-full overflow-auto\", className)}\n />\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: jsonManifest,\n create: () => new JsonAdapter(),\n Renderer: JsonRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":";;;;;;;;;;;;AAgBA,SAAS,IAAI,MAAqB,iBAAiB;AAuD3C,SACE,KADF;AAjCR,SAAS,UAAU,OAAwB;AACzC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,IAAI,OAAO,MAAM,MAAM,CAAC;AACzD,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,WAAO,IAAI,OAAO,OAAO,KAAK,KAAK,EAAE,MAAM,CAAC;AAAA,EAC9C;AACA,MAAI,OAAO,UAAU,SAAU,QAAO,IAAI,KAAK;AAC/C,SAAO,OAAO,KAAK;AACrB;AAGA,SAAS,YAAY,OAA8D;AACjF,SAAO,UAAU,QAAQ,OAAO,UAAU;AAC5C;AAQO,SAAS,YAAY,OAAgB,OAAO,KAAiB;AAClE,MAAI,CAAC,YAAY,KAAK,EAAG,QAAO,CAAC;AAEjC,QAAM,UAA+B,MAAM,QAAQ,KAAK,IACpD,MAAM,IAAI,CAAC,MAAM,UAAU,CAAC,OAAO,KAAK,GAAG,IAAI,CAAC,IAChD,OAAO,QAAQ,KAAK;AAExB,SAAO,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AACnC,UAAM,YAAY,MAAM,QAAQ,KAAK,IAAI,GAAG,IAAI,IAAI,GAAG,MAAM,GAAG,IAAI,IAAI,GAAG;AAC3E,UAAM,YAAY,YAAY,KAAK;AACnC,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OACE,qBAAC,UAAK,WAAU,aACd;AAAA,4BAAC,UAAK,WAAU,mBAAmB,eAAI;AAAA,QACvC,oBAAC,UAAK,WAAU,yBAAwB,gBAAE;AAAA,QAC1C,oBAAC,UAAK,WAAW,YAAY,0BAA0B,kBACpD,oBAAU,KAAK,GAClB;AAAA,SACF;AAAA,MAEF,UAAU,YAAY,YAAY,OAAO,SAAS,IAAI;AAAA,IACxD;AAAA,EACF,CAAC;AACH;AAEA,IAAM,cAAN,MAAyC;AAAA,EACvC,MAAM,KAAK,QAA4B,SAAoD;AACzF,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,OAAO,KAAK,QAAQ,MAAM;AAAA,IACzC,SAAS,OAAO;AACd,YAAM,cAAc,OAAO,eAAe,EAAE,UAAU,OAAO,KAAK,CAAC;AAAA,IACrE;AAEA,QAAI;AACF,aAAO,EAAE,MAAM,QAAQ,OAAO,KAAK,MAAM,IAAI,GAAc,KAAK;AAAA,IAClE,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR;AAAA,QACA,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QACzC,EAAE,UAAU,OAAO,MAAM,OAAO,MAAM;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,aAAa,EAAE,UAAU,KAAK,UAAU,GAAyB;AACxE,QAAM,OAAO;AACb,QAAM,EAAE,EAAE,IAAI,UAAU;AACxB,QAAM,QAAQ,YAAY,KAAK,KAAK;AAIpC,MAAI,MAAM,WAAW,GAAG;AACtB,WACE,oBAAC,SAAI,WAAW,GAAG,uDAAuD,SAAS,GAChF,eAAK,MACR;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAY,EAAE,kBAAkB;AAAA,MAChC;AAAA,MAGA,oBAAoB,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE;AAAA,MAC/C,eAAc;AAAA,MACd,YAAU;AAAA,MACV,WAAW,GAAG,wBAAwB,SAAS;AAAA;AAAA,EACjD;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
+ jsonManifest
4
+ } from "../../chunk-GH4UBYST.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ jsonManifest
8
+ };
9
+ //# sourceMappingURL=json-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,15 +1,22 @@
1
1
  "use client";
2
2
  "use client";
3
+ import {
4
+ blockMark,
5
+ blockMarkAttributes
6
+ } from "../../chunk-AOYEL7O3.js";
3
7
  import {
4
8
  markdownManifest
5
- } from "./chunk-H3OAON3D.js";
9
+ } from "../../chunk-YWHFMCS4.js";
6
10
  import {
7
- toMarkRanges,
8
11
  useScrollActiveHighlightIntoView
9
- } from "./chunk-VO2273Z2.js";
12
+ } from "../../chunk-IB4N72FA.js";
13
+ import {
14
+ toMarkRanges
15
+ } from "../../chunk-HOQZ7OPH.js";
10
16
  import {
11
17
  toViewerError
12
- } from "./chunk-AORNMH77.js";
18
+ } from "../../chunk-JHFC2KBI.js";
19
+ import "../../chunk-CIT2HHRI.js";
13
20
 
14
21
  // src/adapters/markdown/markdown-adapter.tsx
15
22
  import {
@@ -21,40 +28,11 @@ import {
21
28
  ProseListItem,
22
29
  ProseText,
23
30
  StatePanel,
24
- cn as cn2,
31
+ cn,
25
32
  useLocale,
26
33
  useStreamdownTranslations
27
34
  } from "@elabs-ai/components-ui";
28
35
  import { createContext, use, useMemo, useRef } from "react";
29
-
30
- // src/adapters/markdown/markdown-marks.ts
31
- import { cn } from "@elabs-ai/components-ui";
32
- var UNMARKED = { marked: false, active: false };
33
- function blockMark(marks, node) {
34
- const start = node?.position?.start?.offset;
35
- const end = node?.position?.end?.offset;
36
- if (start === void 0 || end === void 0 || end <= start) return UNMARKED;
37
- let marked = false;
38
- let active = false;
39
- marks.ranges.forEach(([from, to], index) => {
40
- if (from >= end || to <= start) return;
41
- marked = true;
42
- if (index === marks.activeIndex) active = true;
43
- });
44
- return marked ? { marked, active } : UNMARKED;
45
- }
46
- var MARKED_CLASS = "bg-highlight/40 border-s-2 border-highlight rounded-e-sm ps-2 -ms-2";
47
- var ACTIVE_CLASS = "bg-highlight-active/40 border-s-4 border-highlight-active rounded-e-sm ps-2 -ms-2";
48
- function blockMarkAttributes(mark, className) {
49
- if (!mark.marked) return className === void 0 ? {} : { className };
50
- return {
51
- "data-slot": "highlight-block",
52
- ...mark.active ? { "data-active": "", "aria-current": "true" } : {},
53
- className: cn(mark.active ? ACTIVE_CLASS : MARKED_CLASS, className)
54
- };
55
- }
56
-
57
- // src/adapters/markdown/markdown-adapter.tsx
58
36
  import { jsx, jsxs } from "react/jsx-runtime";
59
37
  var MARKDOWN_CHARACTER_LIMIT = 1e6;
60
38
  var streamdown;
@@ -182,7 +160,7 @@ function MarkdownRenderer({
182
160
  return (
183
161
  // No `overflow-auto` here: `FileViewerContent` is the scroll boundary, and
184
162
  // nesting a second one clips the last block above the outer pane's padding.
185
- /* @__PURE__ */ jsxs("div", { ref: container, className: cn2("flex flex-col gap-2", className), children: [
163
+ /* @__PURE__ */ jsxs("div", { ref: container, className: cn("flex flex-col gap-2", className), children: [
186
164
  markdown.totalCharacters !== void 0 && // Not an error — the file is fine, we are showing part of it.
187
165
  /* @__PURE__ */ jsx("p", { role: "status", className: "text-meta text-muted-foreground", children: t("viewer.text.truncated", {
188
166
  shown: formatNumber(markdown.text.length),
@@ -211,4 +189,4 @@ export {
211
189
  MARKDOWN_CHARACTER_LIMIT,
212
190
  markdown_adapter_default as default
213
191
  };
214
- //# sourceMappingURL=markdown-adapter-YC6WTBS4.js.map
192
+ //# sourceMappingURL=markdown-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/markdown/markdown-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Markdown adapter — a `.md` file read as a DOCUMENT, not as source.\n *\n * Renders through `streamdown`, the same markdown engine\n * `@elabs-ai/components-ai`'s `MarkdownView` and\n * `@elabs-ai/components-editor`'s preview use, mapped onto the same\n * `Prose*` primitives from `@elabs-ai/components-ui`. That is the\n * point: a README must not look like three different documents depending on\n * which pane it opened in. The element map below is deliberately a near-copy of\n * `MarkdownView`'s — the packages are siblings and may not import each other,\n * and the shared half that could move down (the `Prose*` set, the Streamdown\n * locale bridge) already has.\n *\n * What this does NOT do, on purpose:\n *\n * - **No plugins.** `@streamdown/code`, `/math`, `/cjk` and `/mermaid` are four\n * more packages a consumer would have to install to open one file. Fenced code\n * is rendered as an unhighlighted block by the element map below (Streamdown\n * emits a bare `<code>` without the code plugin, so the `<pre>` is ours); a\n * source file opened directly still gets Shiki from the `code` adapter, and a\n * diagram fence reads as its own text rather than as a picture.\n * - **No streaming.** A file arrives settled or not at all, so `mode=\"static\"`\n * and `parseIncompleteMarkdown={false}` — the incomplete-token repair that\n * makes Streamdown good at chat is only overhead for a file on disk.\n */\n\nimport {\n ProseBlockquote,\n ProseHeading,\n ProseInlineCode,\n ProseLink,\n ProseList,\n ProseListItem,\n ProseText,\n StatePanel,\n cn,\n useLocale,\n useStreamdownTranslations,\n} from \"@elabs-ai/components-ui\";\nimport type { ProseHeadingLevel, ResolvedFileSource } from \"@elabs-ai/components-ui\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { createContext, use, useMemo, useRef } from \"react\";\nimport type * as StreamdownExports from \"streamdown\";\n\nimport { toViewerError } from \"../../core/errors\";\nimport { toMarkRanges, type MarkRanges } 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 { blockMark, blockMarkAttributes, type PositionedNode } from \"./markdown-marks\";\nimport { markdownManifest } from \"./markdown-manifest\";\n\n/**\n * Characters kept before truncation. Markdown is parsed into an element tree,\n * which costs more than a `<pre>` — this sits between the code and plain-text\n * limits for that reason.\n */\nexport const MARKDOWN_CHARACTER_LIMIT = 1_000_000;\n\nexport interface MarkdownDocument extends AdapterDocument {\n kind: \"markdown\";\n text: string;\n /** Total characters in the file, when more than what is shown. */\n totalCharacters?: number;\n}\n\n// Type-only, so it erases: the runtime edge is the dynamic import below.\ntype StreamdownModule = typeof StreamdownExports;\ntype StreamdownComponents = NonNullable<\n ComponentProps<StreamdownModule[\"Streamdown\"]>[\"components\"]\n>;\n\n/**\n * The engine, resolved once per page.\n *\n * Loaded in `load()` rather than imported at the top of this module for the\n * reason every other adapter does it: `streamdown` is an OPTIONAL peer, and a\n * static edge would make this module unresolvable — not merely heavier — for a\n * consumer who never installs it. The renderer reads the same cached module,\n * which is guaranteed to be populated because a document only exists once\n * `load()` has resolved.\n */\nlet streamdown: StreamdownModule | undefined;\n\nasync function loadStreamdown(): Promise<StreamdownModule> {\n // Dynamic: the ONLY edge to the optional peer (heavy-deps:check).\n streamdown ??= await import(\"streamdown\");\n return streamdown;\n}\n\nclass MarkdownAdapter implements FileAdapter {\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<MarkdownDocument> {\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 // Before returning: a document this adapter's Renderer cannot draw is a\n // failed load, not a blank pane. A missing peer surfaces from here as\n // `parser-missing` (see `parserMissingError`).\n await loadStreamdown();\n\n const truncated = raw.length > MARKDOWN_CHARACTER_LIMIT;\n return {\n kind: \"markdown\",\n text: truncated ? raw.slice(0, MARKDOWN_CHARACTER_LIMIT) : raw,\n totalCharacters: truncated ? raw.length : undefined,\n };\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Renderer */\n/* -------------------------------------------------------------------------- */\n\n/** Never past `h6`, whatever the offset — an `h7` is not an element. */\nconst clampHeadingLevel = (level: number): ProseHeadingLevel =>\n Math.min(6, Math.max(1, level)) as ProseHeadingLevel;\n\n/* -------------------------------------------------------------------------- */\n/* Highlight plates */\n/* -------------------------------------------------------------------------- */\n\nconst EMPTY_MARKS: MarkRanges = { ranges: [], activeIndex: -1 };\n\n/**\n * The marks, read by the block components.\n *\n * A context rather than a closure over `buildProseComponents`, so the element\n * map stays memoized on the heading offset alone: rebuilding it per keystroke\n * of a find-as-you-type would hand Streamdown a new `components` object every\n * time, which it treats as a reason to re-render every block in the file.\n */\nconst MarkContext = createContext<MarkRanges>(EMPTY_MARKS);\n\n/** Set once a block has plated, so a nested one does not plate on top of it. */\nconst PlatedContext = createContext(false);\n\n/**\n * The plate for one block, and a wrapper that stops its children plating again.\n *\n * A loose list item renders as `li > p`, and both nodes' source spans contain\n * the same mark — without the suppression the reader sees two stacked fills for\n * one citation.\n */\nfunction usePlate(node: PositionedNode | undefined, className?: string) {\n const marks = use(MarkContext);\n const plated = use(PlatedContext);\n const mark = plated ? { marked: false, active: false } : blockMark(marks, node);\n return {\n props: blockMarkAttributes(mark, className),\n wrap: (children: ReactNode) =>\n mark.marked ? <PlatedContext value={true}>{children}</PlatedContext> : children,\n };\n}\n\n/*\n * The plating blocks are named components rather than inline arrows in the map\n * below: they call a hook, and a lowercase `p:` key is not a component name as\n * far as the rules-of-hooks lint can tell.\n */\n\nconst MarkdownParagraph: NonNullable<StreamdownComponents[\"p\"]> = ({\n node,\n className,\n children,\n ...props\n}) => {\n const plate = usePlate(node, className);\n return (\n <ProseText {...plate.props} {...props}>\n {plate.wrap(children)}\n </ProseText>\n );\n};\n\nconst MarkdownListItem: NonNullable<StreamdownComponents[\"li\"]> = ({\n node,\n className,\n children,\n ...props\n}) => {\n const plate = usePlate(node, className);\n return (\n <ProseListItem {...plate.props} {...props}>\n {plate.wrap(children)}\n </ProseListItem>\n );\n};\n\nconst MarkdownCode: NonNullable<StreamdownComponents[\"code\"]> = ({\n node,\n className,\n children,\n ...props\n}) => {\n const fence = /\\blanguage-/.test(className ?? \"\");\n // The plate goes on the `<pre>` — the whole fence is what a citation points\n // at. Its own `bg-surface-muted` wins over the plate's fill (see\n // `blockMarkAttributes`), so the code keeps its ground and the rail is what\n // says it is cited.\n const plate = usePlate(\n fence ? node : undefined,\n \"bg-surface-muted text-code overflow-x-auto rounded-md p-3 font-mono whitespace-pre\",\n );\n // A fence needs its own `<pre>`. With no `@streamdown/code` plugin installed\n // Streamdown emits a BARE `<code data-block>` — no block wrapper — which the\n // surrounding prose's `whitespace-normal` then collapses into one run-on\n // line. The fence is unhighlighted here by design (see the module docblock);\n // it still has to read as a block of code.\n return fence ? (\n <pre {...plate.props}>\n <code className={className} {...props}>\n {plate.wrap(children)}\n </code>\n </pre>\n ) : (\n <ProseInlineCode className={className} {...props}>\n {children}\n </ProseInlineCode>\n );\n};\n\n/** Everything that does not depend on the heading offset. */\nconst SHARED_COMPONENTS: StreamdownComponents = {\n p: MarkdownParagraph,\n a: ({ node: _node, ...props }) => <ProseLink {...props} />,\n // `ref` is stripped: ProseList's intersection ref type (ul & ol) is narrower\n // than the per-element ref react-markdown passes.\n ul: ({ node: _node, ref: _ref, ...props }) => <ProseList {...props} />,\n ol: ({ node: _node, ref: _ref, ...props }) => <ProseList ordered {...props} />,\n li: MarkdownListItem,\n blockquote: ({ node: _node, ...props }) => <ProseBlockquote {...props} />,\n code: MarkdownCode,\n};\n\n/**\n * Map the markdown element tree onto the Prose primitives.\n *\n * Built per `baseHeadingLevel` (memoized by the renderer, not rebuilt each\n * render): the map is otherwise pure and Streamdown puts it into a context, so\n * a fresh object per render would re-render every block.\n *\n * The heading offset is the reason this takes an argument at all. A viewed file\n * carries its own heading tree, correct only relative to the page hosting it —\n * a README's `#` inside an app that already has an `<h1>` would otherwise put\n * two `h1`s in a screen reader's flat heading list. Same seam, same arithmetic\n * as `@elabs-ai/components-ai`'s `MarkdownView`.\n */\nfunction buildProseComponents(baseHeadingLevel: ProseHeadingLevel): StreamdownComponents {\n const heading =\n (markdownLevel: number): StreamdownComponents[\"h1\"] =>\n ({ node, className, children, ...props }) => {\n const plate = usePlate(node, className);\n return (\n <ProseHeading\n level={clampHeadingLevel(markdownLevel + baseHeadingLevel - 1)}\n {...plate.props}\n {...props}\n >\n {plate.wrap(children)}\n </ProseHeading>\n );\n };\n return {\n h1: heading(1),\n h2: heading(2),\n h3: heading(3),\n h4: heading(4),\n h5: heading(5),\n h6: heading(6),\n ...SHARED_COMPONENTS,\n };\n}\n\nfunction MarkdownRenderer({\n document: doc,\n className,\n baseHeadingLevel = 2,\n highlights,\n activeHighlightId,\n}: AdapterRendererProps) {\n const markdown = doc as MarkdownDocument;\n const { t, formatNumber } = useLocale();\n const translations = useStreamdownTranslations();\n const components = useMemo(() => buildProseComponents(baseHeadingLevel), [baseHeadingLevel]);\n const container = useRef<HTMLDivElement>(null);\n const marks = useMemo(\n () => toMarkRanges(highlights, markdown.text.length),\n [highlights, markdown.text],\n );\n\n useScrollActiveHighlightIntoView(container, activeHighlightId);\n\n if (markdown.text.trim().length === 0) {\n return <StatePanel kind=\"empty\" title={t(\"viewer.file.empty\")} className={className} />;\n }\n\n const Streamdown = streamdown?.Streamdown;\n if (!Streamdown) return null;\n\n return (\n // No `overflow-auto` here: `FileViewerContent` is the scroll boundary, and\n // nesting a second one clips the last block above the outer pane's padding.\n <div ref={container} className={cn(\"flex flex-col gap-2\", className)}>\n {markdown.totalCharacters !== undefined && (\n // Not an error — the file is fine, we are showing part of it.\n <p role=\"status\" className=\"text-meta text-muted-foreground\">\n {t(\"viewer.text.truncated\", {\n shown: formatNumber(markdown.text.length),\n total: formatNumber(markdown.totalCharacters),\n })}\n </p>\n )}\n {/* `max-w-prose` because this is genuine long-form reading, not a label:\n a README run edge-to-edge across a wide pane loses the line. The pane's\n own padding is the page margin — the article adds none. */}\n <article className=\"mx-auto max-w-prose space-y-3\">\n {/* `mode=\"static\"` is what makes the plates addressable: it hands the\n whole file to ONE parse, so every node's `position.start.offset` is\n an offset into `document.text`. Splitting into blocks (streaming\n mode) would restart them per block. */}\n <MarkContext value={marks}>\n <Streamdown\n mode=\"static\"\n parseIncompleteMarkdown={false}\n components={components}\n translations={translations}\n >\n {markdown.text}\n </Streamdown>\n </MarkContext>\n </article>\n </div>\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: markdownManifest,\n create: () => new MarkdownAdapter(),\n Renderer: MarkdownRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ markdownManifest
4
+ } from "../../chunk-YWHFMCS4.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ markdownManifest
8
+ };
9
+ //# sourceMappingURL=markdown-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import {
3
+ blockMark,
4
+ blockMarkAttributes
5
+ } from "../../chunk-AOYEL7O3.js";
6
+ export {
7
+ blockMark,
8
+ blockMarkAttributes
9
+ };
10
+ //# sourceMappingURL=markdown-marks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -2,10 +2,11 @@
2
2
  "use client";
3
3
  import {
4
4
  mediaManifest
5
- } from "./chunk-HMG2ERXH.js";
5
+ } from "../../chunk-YA72QE57.js";
6
6
  import {
7
7
  toViewerError
8
- } from "./chunk-AORNMH77.js";
8
+ } from "../../chunk-JHFC2KBI.js";
9
+ import "../../chunk-CIT2HHRI.js";
9
10
 
10
11
  // src/adapters/media/media-adapter.tsx
11
12
  import { cn, StatePanel, useLocale } from "@elabs-ai/components-ui";
@@ -75,4 +76,4 @@ var media_adapter_default = adapterModule;
75
76
  export {
76
77
  media_adapter_default as default
77
78
  };
78
- //# sourceMappingURL=media-adapter-MCTB4GBH.js.map
79
+ //# sourceMappingURL=media-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/media/media-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Video / audio adapter — native elements, deliberately.\n *\n * `@elabs-ai/components-ai` ships a designed `AudioPlayer` built on\n * `media-chrome`, and this adapter does NOT reach for it: `ai` is a Layer-2\n * sibling, so importing it would be a sideways edge the dependency gate rejects\n * (and would pull a chat package into a file viewer). Native `<video controls>`\n * / `<audio controls>` are the honest answer here — they bring the platform's\n * own accessible transport, keyboard handling, picture-in-picture, captions\n * menu and OS media keys, none of which a custom skin gets for free.\n *\n * The plan's \"extract `AudioPlayer` down to `ui`\" would let both sides share one\n * skinned player. That is a real refactor of an existing component with its own\n * tests and stories, so it is tracked separately rather than smuggled in here.\n */\n\nimport { cn, StatePanel, useLocale, type ResolvedFileSource } from \"@elabs-ai/components-ui\";\nimport { useEffect, useState } from \"react\";\n\nimport { toViewerError } from \"../../core/errors\";\nimport type {\n AdapterDocument,\n AdapterLoadContext,\n AdapterModule,\n AdapterRendererProps,\n FileAdapter,\n} from \"../../core/types\";\nimport { mediaManifest } from \"./media-manifest\";\n\nexport interface MediaDocument extends AdapterDocument {\n kind: \"media\";\n /** A URL the element can play — the source's own URL, or a minted object URL. */\n url: string;\n /** Which element to render. `resolveFileKind` already decided this. */\n media: \"video\" | \"audio\";\n}\n\nclass MediaAdapter implements FileAdapter {\n #source?: ResolvedFileSource;\n\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<MediaDocument> {\n this.#source = source;\n try {\n // Deliberately `url()`, never `bytes()`: an object URL lets the browser\n // stream and seek. Buffering a 2 GB video into memory to hand it to a\n // `<video>` element would be the wrong shape at every size.\n const url = await source.url(context.signal);\n return { kind: \"media\", url, media: source.category === \"audio\" ? \"audio\" : \"video\" };\n } catch (error) {\n throw toViewerError(error, \"read-failed\", { fileName: source.name });\n }\n }\n\n dispose(): void {\n this.#source?.revoke();\n this.#source = undefined;\n }\n}\n\nfunction MediaRenderer({ document: doc, source, className }: AdapterRendererProps) {\n const media = doc as MediaDocument;\n const { t } = useLocale();\n const [failed, setFailed] = useState(false);\n\n useEffect(() => setFailed(false), [media.url]);\n\n if (failed) {\n // Terminal: the browser has no decoder for this codec. Retrying cannot help,\n // so this states the fact rather than offering a button that does nothing.\n // The panel carries `role=\"alert\"` itself, and sits centred like every other\n // viewer state — a message pinned to the top-left of an empty pane reads as\n // a broken render.\n return (\n <div className={cn(\"flex min-h-full flex-col justify-center p-4\", className)}>\n <StatePanel\n kind=\"error\"\n title={t(\"viewer.media.unsupportedTitle\")}\n description={t(\"viewer.media.unsupported\", { name: source.name })}\n />\n </div>\n );\n }\n\n const label = t(\"viewer.media.label\", { name: source.name });\n\n if (media.media === \"audio\") {\n return (\n <div className={cn(\"flex min-h-full items-center justify-center\", className)}>\n <audio\n src={media.url}\n controls\n aria-label={label}\n onError={() => setFailed(true)}\n className=\"w-full max-w-lg\"\n />\n </div>\n );\n }\n\n return (\n <div className={cn(\"flex min-h-full items-center justify-center\", className)}>\n <video\n src={media.url}\n controls\n // No autoplay: a viewer opens files the reader chose to look at, not to\n // listen to. Sound starting on its own is the reason browsers block it.\n aria-label={label}\n onError={() => setFailed(true)}\n className=\"max-h-full max-w-full\"\n />\n </div>\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: mediaManifest,\n create: () => new MediaAdapter(),\n Renderer: MediaRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":";;;;;;;;;;;AAkBA,SAAS,IAAI,YAAY,iBAA0C;AACnE,SAAS,WAAW,gBAAgB;AAyD5B;AArCR,IAAM,eAAN,MAA0C;AAAA,EACxC;AAAA,EAEA,MAAM,KAAK,QAA4B,SAAqD;AAC1F,SAAK,UAAU;AACf,QAAI;AAIF,YAAM,MAAM,MAAM,OAAO,IAAI,QAAQ,MAAM;AAC3C,aAAO,EAAE,MAAM,SAAS,KAAK,OAAO,OAAO,aAAa,UAAU,UAAU,QAAQ;AAAA,IACtF,SAAS,OAAO;AACd,YAAM,cAAc,OAAO,eAAe,EAAE,UAAU,OAAO,KAAK,CAAC;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,SAAS,OAAO;AACrB,SAAK,UAAU;AAAA,EACjB;AACF;AAEA,SAAS,cAAc,EAAE,UAAU,KAAK,QAAQ,UAAU,GAAyB;AACjF,QAAM,QAAQ;AACd,QAAM,EAAE,EAAE,IAAI,UAAU;AACxB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAE1C,YAAU,MAAM,UAAU,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC;AAE7C,MAAI,QAAQ;AAMV,WACE,oBAAC,SAAI,WAAW,GAAG,+CAA+C,SAAS,GACzE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,OAAO,EAAE,+BAA+B;AAAA,QACxC,aAAa,EAAE,4BAA4B,EAAE,MAAM,OAAO,KAAK,CAAC;AAAA;AAAA,IAClE,GACF;AAAA,EAEJ;AAEA,QAAM,QAAQ,EAAE,sBAAsB,EAAE,MAAM,OAAO,KAAK,CAAC;AAE3D,MAAI,MAAM,UAAU,SAAS;AAC3B,WACE,oBAAC,SAAI,WAAW,GAAG,+CAA+C,SAAS,GACzE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,MAAM;AAAA,QACX,UAAQ;AAAA,QACR,cAAY;AAAA,QACZ,SAAS,MAAM,UAAU,IAAI;AAAA,QAC7B,WAAU;AAAA;AAAA,IACZ,GACF;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAW,GAAG,+CAA+C,SAAS,GACzE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK,MAAM;AAAA,MACX,UAAQ;AAAA,MAGR,cAAY;AAAA,MACZ,SAAS,MAAM,UAAU,IAAI;AAAA,MAC7B,WAAU;AAAA;AAAA,EACZ,GACF;AAEJ;AAEA,IAAM,gBAA+B;AAAA,EACnC,UAAU;AAAA,EACV,QAAQ,MAAM,IAAI,aAAa;AAAA,EAC/B,UAAU;AACZ;AAEA,IAAO,wBAAQ;","names":[]}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ mediaManifest
4
+ } from "../../chunk-YA72QE57.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ mediaManifest
8
+ };
9
+ //# sourceMappingURL=media-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,98 +1,48 @@
1
1
  "use client";
2
2
  "use client";
3
3
  import {
4
- usePageControl,
5
- usePagedScroll,
4
+ usePageControl
5
+ } from "../../chunk-MJUH32ZK.js";
6
+ import {
7
+ usePagedScroll
8
+ } from "../../chunk-IQ6Z4X3K.js";
9
+ import {
6
10
  useViewportSize
7
- } from "./chunk-4OFQYALG.js";
11
+ } from "../../chunk-3HKQFFZW.js";
12
+ import "../../chunk-7PGGKQVY.js";
13
+ import {
14
+ PDF_PAGE_SEPARATOR,
15
+ pageOfHighlight,
16
+ pageTextChunk,
17
+ rangeBoxes,
18
+ rectBoxes
19
+ } from "../../chunk-G27UJZWH.js";
20
+ import {
21
+ DEFAULT_ZOOM
22
+ } from "../../chunk-SASY77ZL.js";
23
+ import {
24
+ openPdfDocument
25
+ } from "../../chunk-SBG7WPGO.js";
8
26
  import {
9
- DEFAULT_ZOOM,
10
- openPdfDocument,
11
27
  pdfManifest
12
- } from "./chunk-SLXRUYT3.js";
28
+ } from "../../chunk-M77ICVWP.js";
13
29
  import {
14
- createTextIndexBuilder,
15
- spanAt
16
- } from "./chunk-UL43NGUG.js";
30
+ createTextIndexBuilder
31
+ } from "../../chunk-5YE2MUS2.js";
17
32
  import {
18
- localizeRanges,
19
- toMarkRanges,
20
33
  useScrollActiveHighlightIntoView
21
- } from "./chunk-VO2273Z2.js";
34
+ } from "../../chunk-IB4N72FA.js";
35
+ import {
36
+ toMarkRanges
37
+ } from "../../chunk-HOQZ7OPH.js";
22
38
  import {
23
39
  toViewerError
24
- } from "./chunk-AORNMH77.js";
40
+ } from "../../chunk-JHFC2KBI.js";
41
+ import "../../chunk-CIT2HHRI.js";
25
42
 
26
43
  // src/adapters/pdf/pdf-adapter.tsx
27
44
  import { cn, StatePanel, useLocale } from "@elabs-ai/components-ui";
28
45
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
29
-
30
- // src/adapters/pdf/pdf-text.ts
31
- var PDF_ITEM_SEPARATOR = " ";
32
- var PDF_PAGE_SEPARATOR = "\n\n";
33
- function pageTextChunk(items) {
34
- const spans = [];
35
- const parts = [];
36
- let cursor = 0;
37
- items.forEach((item, index) => {
38
- if (index > 0) cursor += PDF_ITEM_SEPARATOR.length;
39
- parts.push(item.str);
40
- spans.push({ start: cursor, end: cursor + item.str.length });
41
- cursor += item.str.length;
42
- });
43
- return { text: parts.join(PDF_ITEM_SEPARATOR), spans };
44
- }
45
- var FALLBACK_ADVANCE = 0.5;
46
- function rangeBoxes(spans, chunk, pageStart, marks) {
47
- if (marks.ranges.length === 0) return [];
48
- const boxes = [];
49
- for (const span of spans) {
50
- const item = chunk.spans[span.item];
51
- if (!item || item.end === item.start) continue;
52
- const local = localizeRanges(marks, pageStart + item.start, pageStart + item.end);
53
- if (local.ranges.length === 0) continue;
54
- const length = item.end - item.start;
55
- const advance = span.width > 0 ? span.width / length : span.fontSize * FALLBACK_ADVANCE;
56
- local.ranges.forEach(([from, to], index) => {
57
- boxes.push({
58
- left: span.left + advance * from,
59
- top: span.top,
60
- width: advance * (to - from),
61
- height: span.fontSize,
62
- active: index === local.activeIndex
63
- });
64
- });
65
- }
66
- return boxes;
67
- }
68
- function rectBoxes(highlights, size) {
69
- const boxes = [];
70
- for (const highlight of highlights) {
71
- for (const rect of highlight.rects ?? []) {
72
- boxes.push({
73
- left: clampFraction(rect.x) * size.width,
74
- top: clampFraction(rect.y) * size.height,
75
- width: clampFraction(rect.width) * size.width,
76
- height: clampFraction(rect.height) * size.height,
77
- active: highlight.active
78
- });
79
- }
80
- }
81
- return boxes;
82
- }
83
- function clampFraction(value) {
84
- if (!Number.isFinite(value)) return 0;
85
- return Math.max(0, Math.min(1, value));
86
- }
87
- function pageOfHighlight(highlight, index) {
88
- if (!highlight || highlight.status !== "resolved") return void 0;
89
- if (highlight.page !== void 0) return highlight.page;
90
- if (!highlight.range || !index) return void 0;
91
- const span = spanAt(index, highlight.range[0]);
92
- return typeof span?.ref === "number" ? span.ref : void 0;
93
- }
94
-
95
- // src/adapters/pdf/pdf-adapter.tsx
96
46
  import { jsx, jsxs } from "react/jsx-runtime";
97
47
  var FIT_GUTTER = 16;
98
48
  var MIN_SCALE = 0.1;
@@ -421,4 +371,4 @@ export {
421
371
  pdf_adapter_default as default,
422
372
  toTextSpans
423
373
  };
424
- //# sourceMappingURL=pdf-adapter-5PMKEXUD.js.map
374
+ //# sourceMappingURL=pdf-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/pdf/pdf-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * PDF adapter — the format nothing in this repo could open before.\n *\n * ## Why this one renders a canvas, and why that is not a rule break\n *\n * \"Adapters emit data, never HTML\" is about CHROME: an adapter may not smuggle\n * colours, fonts or borders past the token layer. A PDF page's pixels ARE the\n * document — a PDF is a description of marks on a page, and reproducing it is\n * the whole job. So the page is rasterized to a `<canvas>` in the file's own\n * colours, while everything AROUND it (the pager, the zoom control, the page\n * frame, the loading and error states) is brand-ui components on tokens.\n *\n * ## The text layer\n *\n * A canvas has no text, so a canvas-only PDF viewer is unusable: nothing to\n * select, copy, search or read aloud. pdf.js exposes the text with per-item\n * transforms, so we position transparent spans over the page. That is the same\n * approach pdf.js's own viewer takes, and it is what makes the page selectable\n * and reachable by a screen reader.\n *\n * ## Highlights are boxes, not marks\n *\n * Every other text adapter paints a `<mark>` around the cited characters. There\n * is no text to wrap here — the words are pixels — so a citation is a rectangle\n * over the raster, positioned from the page's own geometry (`pdf-text.ts`). The\n * same layer draws a `rect` address, which is why this is the one adapter that\n * can honour geometry a text pipeline never produced.\n *\n * ## The chrome is not here\n *\n * The pager and the zoom control used to live in this file, over `useState` no\n * one outside the canvas could reach. They are now shell parts over provider\n * state (ADR 0026): this renderer draws the page it is TOLD to, at the scale it\n * is told to, and reports back what a fit mode resolved to. It keeps its own\n * page only when mounted outside a provider.\n *\n * ## Pages scroll; they are not flipped\n *\n * The document is one continuous column of pages, virtualized over the shell's\n * viewport (`usePagedScroll`). A pager that replaced the canvas made a PDF the\n * only thing in the app you could not simply scroll, and it broke the two\n * gestures readers actually use — skimming, and dragging the scrollbar to\n * \"about two thirds in\". The page number is now a consequence of where the\n * reader is, and typing one is a scroll.\n */\n\nimport { cn, StatePanel, useLocale, type ResolvedFileSource } from \"@elabs-ai/components-ui\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { toViewerError } from \"../../core/errors\";\nimport type { ResolvedHighlight } from \"../../core/highlight\";\nimport { toMarkRanges, type MarkRanges } from \"../../core/highlight-marks\";\nimport { createTextIndexBuilder, 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 PageSize,\n} from \"../../core/types\";\nimport { DEFAULT_ZOOM } from \"../../core/zoom\";\nimport {\n openPdfDocument,\n type PdfDocument,\n type PdfPage,\n type PdfSession,\n type PdfTextItem,\n} from \"./pdf-engine\";\nimport { pdfManifest } from \"./pdf-manifest\";\nimport {\n PDF_PAGE_SEPARATOR,\n pageOfHighlight,\n pageTextChunk,\n rangeBoxes,\n rectBoxes,\n type PdfHighlightBox,\n type PdfTextSpan,\n} from \"./pdf-text\";\n\n/**\n * Breathing room kept around a fitted page, in CSS pixels.\n *\n * Without it a fit-to-width page is exactly as wide as the viewport, and the\n * page frame's own 1px border tips it over into a horizontal scrollbar — which\n * narrows the viewport, which re-fits smaller, which removes the scrollbar.\n */\nconst FIT_GUTTER = 16;\n\n/** Sanity bounds on a fitted scale, so a degenerate measurement cannot blank the page. */\nconst MIN_SCALE = 0.1;\nconst MAX_SCALE = 10;\n\n/**\n * Pages whose text is extracted for the plain-text projection.\n *\n * Extraction costs one worker round-trip per page, so doing it for a 900-page\n * document at load time would stall the first paint for something most readers\n * never use. The pages a reader actually looks at get their text layer rendered\n * on demand regardless — this cap only bounds the eager `document.text`.\n */\nexport const PDF_TEXT_PAGE_LIMIT = 50;\n\nexport interface PdfViewerDocument extends AdapterDocument {\n kind: \"pdf\";\n /** The live pdf.js handle. Owned by the adapter — the renderer only reads it. */\n handle: PdfDocument;\n pageCount: number;\n /** Page number per stretch of the projection, so a citation can turn the page. */\n textIndex?: TextIndex<number>;\n}\n\n/** Vertical space between two pages in the scrolling column, in CSS pixels. */\nconst PAGE_GAP = 16;\n\n/** The page frame's own 1px border, top and bottom — part of the reserved height. */\nconst PAGE_BORDER = 2;\n\n/**\n * Height assumed for a page whose size was never measured, in CSS pixels.\n *\n * Only reached by a document with no extractable page at all; every real one\n * contributes at least page 1 to `pageSizes`. US Letter at 96dpi.\n */\nconst FALLBACK_PAGE_HEIGHT = 1056;\n\nclass PdfAdapter implements FileAdapter {\n #session?: PdfSession;\n\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<PdfViewerDocument> {\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 try {\n // pdf.js takes ownership of the buffer it is handed (it transfers it to\n // the worker), so the view is built here rather than reusing the source's\n // memoized copy in place.\n const session = await openPdfDocument(new Uint8Array(buffer), context.signal);\n this.#session = session;\n const handle = session.document;\n const { textIndex, pageSizes } = await extractText(handle, context.signal);\n return {\n kind: \"pdf\",\n handle,\n pageCount: handle.numPages,\n pageSizes,\n text: textIndex?.text,\n textIndex,\n // So a passage the shell cannot find in a 900-page report reads as \"past\n // the pages we extracted\" rather than \"not in this document\".\n textTruncated: handle.numPages > PDF_TEXT_PAGE_LIMIT || undefined,\n };\n } catch (error) {\n // A password-protected or corrupt file lands here; the engine failing to\n // resolve is caught upstream and becomes `parser-missing`.\n throw toViewerError(error, \"parse-failed\", { fileName: source.name });\n }\n }\n\n dispose(): void {\n // Tears down the worker and its transferred buffers. Skipping this leaks a\n // worker per document opened, which a file browser hits within minutes.\n // The teardown lives on the SESSION, not on the document — see `PdfSession`.\n void this.#session?.destroy();\n this.#session = undefined;\n }\n}\n\n/**\n * Best-effort plain text, plus the page each stretch of it came from — and each\n * page's size, which the same loop already has in hand.\n *\n * Never throws: a document whose text will not extract still renders — the\n * reader loses search and citations, not the file. Whatever was extracted before\n * the failure is kept, because half a projection still answers half the queries.\n *\n * The index is built with the SAME join rule the renderer re-applies per page\n * (`pageTextChunk`), so an offset in the projection and a box on the page can\n * never disagree about which item they mean.\n *\n * The sizes are collected here rather than in their own pass because this loop\n * has already paid for `getPage` — a second pass over a 900-page document would\n * be 900 worker round-trips for numbers we are holding.\n */\nasync function extractText(\n handle: PdfDocument,\n signal?: AbortSignal,\n): Promise<{ textIndex?: TextIndex<number>; pageSizes?: PageSize[] }> {\n const pages = Math.min(handle.numPages, PDF_TEXT_PAGE_LIMIT);\n const builder = createTextIndexBuilder<number>({ separator: PDF_PAGE_SEPARATOR });\n const pageSizes: PageSize[] = [];\n try {\n for (let pageNumber = 1; pageNumber <= pages; pageNumber += 1) {\n if (signal?.aborted) break;\n const page = await handle.getPage(pageNumber);\n const { width, height } = page.getViewport({ scale: 1 });\n pageSizes.push({ width, height });\n const content = await page.getTextContent();\n builder.push(pageTextChunk(content.items).text, pageNumber);\n }\n } catch {\n // Fall through: return what we have.\n }\n const index = builder.build();\n return {\n textIndex: index.text.length > 0 ? index : undefined,\n pageSizes: pageSizes.length > 0 ? pageSizes : undefined,\n };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Renderer */\n/* -------------------------------------------------------------------------- */\n\nfunction PdfRenderer({\n document: doc,\n source,\n className,\n highlights,\n activeHighlightId,\n pageNumber: pageNumberProp,\n onPageChange,\n zoom = DEFAULT_ZOOM,\n onZoomResolved,\n}: AdapterRendererProps) {\n const pdf = doc as PdfViewerDocument;\n\n const [pageNumber, goToPage] = usePageControl(pageNumberProp, onPageChange, pdf.pageCount);\n\n const listRef = useRef<HTMLDivElement>(null);\n const viewport = useViewportSize(listRef);\n\n /**\n * A page's size at scale 1.\n *\n * Falls back to the first page for anything past what the adapter measured\n * (`AdapterDocument.pageSizes` may be shorter than the page count). Uniform\n * page size is overwhelmingly the common case, and a wrong guess costs a\n * corrected scrollbar, not a wrong render.\n */\n const naturalAt = useCallback(\n (index: number): PageSize | undefined => pdf.pageSizes?.[index] ?? pdf.pageSizes?.[0],\n [pdf.pageSizes],\n );\n\n // A fit mode is a REQUEST the renderer resolves — it is the only party that\n // knows how wide its viewport is (`AdapterRendererProps.zoom`). Fitted to the\n // page the reader is ON, so a landscape page in a portrait document does not\n // re-fit the whole column.\n const natural = naturalAt(pageNumber - 1);\n const scale = useMemo(() => {\n if (typeof zoom === \"number\") return zoom;\n // Until the page and the pane have both been measured, 100% is a better\n // first frame than a guess that jumps.\n if (!natural || !viewport) return DEFAULT_ZOOM;\n const byWidth = (viewport.width - FIT_GUTTER) / natural.width;\n const fitted =\n zoom === \"fit-width\"\n ? byWidth\n : Math.min(byWidth, (viewport.height - FIT_GUTTER) / natural.height);\n return Math.min(MAX_SCALE, Math.max(MIN_SCALE, fitted));\n }, [zoom, natural, viewport]);\n\n // Report what the fit became, so the chrome can show a percentage and the\n // reader's next \"zoom in\" steps from what is on screen.\n useEffect(() => {\n onZoomResolved?.(scale);\n }, [scale, onZoomResolved]);\n\n const estimateSize = useCallback(\n (index: number) =>\n Math.round((naturalAt(index)?.height ?? FALLBACK_PAGE_HEIGHT) * scale) +\n PAGE_BORDER +\n PAGE_GAP,\n [naturalAt, scale],\n );\n\n const virtualizer = usePagedScroll({\n count: pdf.pageCount,\n listRef,\n pageNumber,\n goToPage,\n estimateSize,\n sizeKey: scale,\n });\n\n // LOCATE happened in the shell; the per-page views below do MAP and PAINT.\n // Computed once here because it is a function of the whole projection, not of\n // any one page.\n const marks = useMemo(() => toMarkRanges(highlights, pdf.text?.length ?? 0), [highlights, pdf]);\n\n // Scrolling to the cited page is the first half of \"take me there\"; the mark's\n // own `scrollIntoView`, inside the page view, is the second. Keyed on the page\n // NUMBER, so a reader who scrolls away while the same citation stays active is\n // not dragged back.\n const activePage = pageOfHighlight(\n highlights?.find((highlight) => highlight.id === activeHighlightId),\n pdf.textIndex,\n );\n useEffect(() => {\n if (activePage === undefined || activePage < 1 || activePage > pdf.pageCount) return;\n goToPage(activePage);\n }, [activePage, pdf.pageCount, goToPage]);\n\n return (\n // No viewport of its own: `FileViewerContent` is the one scroll boundary\n // (`viewer-components.md`), and this column is a child of it. The height is\n // the whole document's, so the scrollbar is honest from the first frame\n // rather than growing as pages arrive.\n <div\n ref={listRef}\n data-slot=\"pdf-pages\"\n className={cn(\"relative w-full\", className)}\n style={{ height: virtualizer.getTotalSize() }}\n >\n {virtualizer.getVirtualItems().map((item) => (\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: PAGE_GAP,\n transform: `translateY(${item.start - virtualizer.options.scrollMargin}px)`,\n }}\n >\n <PdfPageView\n handle={pdf.handle}\n pageNumber={item.index + 1}\n natural={naturalAt(item.index)}\n scale={scale}\n alt={source.alt}\n highlights={highlights}\n activeHighlightId={activeHighlightId}\n marks={marks}\n pageStart={pdf.textIndex?.spans.find((span) => span.ref === item.index + 1)?.start}\n />\n </div>\n ))}\n </div>\n );\n}\n\ninterface PdfPageViewProps {\n handle: PdfDocument;\n /** 1-based, as everything on the wire is. */\n pageNumber: number;\n /** This page at scale 1, when the adapter measured it. Reserves the box. */\n natural?: PageSize;\n scale: number;\n alt?: string;\n highlights?: readonly ResolvedHighlight[];\n activeHighlightId?: string | null;\n marks: MarkRanges;\n /** Where this page's text begins in the projection, if it was extracted. */\n pageStart?: number;\n}\n\n/**\n * One page: the raster, the transparent text over it, and any citation boxes.\n *\n * A component per page rather than one effect over the visible range, so that\n * mounting and unmounting IS the lifecycle — a page scrolled out of the window\n * cancels its own render task and releases its own pdf.js page, with no\n * bookkeeping to get wrong.\n */\nfunction PdfPageView({\n handle,\n pageNumber,\n natural,\n scale,\n alt,\n highlights,\n activeHighlightId,\n marks,\n pageStart,\n}: PdfPageViewProps) {\n const { t, formatNumber } = useLocale();\n\n const [size, setSize] = useState<{ width: number; height: number } | undefined>(\n natural && { width: natural.width * scale, height: natural.height * scale },\n );\n const [spans, setSpans] = useState<PdfTextSpan[]>([]);\n const [items, setItems] = useState<PdfTextItem[]>([]);\n const [failed, setFailed] = useState<string>();\n\n const pageRef = useRef<HTMLDivElement>(null);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n\n useEffect(() => {\n let cancelled = false;\n let task: ReturnType<PdfPage[\"render\"]> | undefined;\n let page: PdfPage | undefined;\n\n void (async () => {\n try {\n page = await handle.getPage(pageNumber);\n if (cancelled) return;\n\n // Rasterize at the device pixel ratio, then present at CSS size — a 1:1\n // canvas is visibly soft on every retina display.\n const ratio = typeof window === \"undefined\" ? 1 : (window.devicePixelRatio ?? 1);\n const viewport = page.getViewport({ scale: scale * ratio });\n const cssViewport = page.getViewport({ scale });\n const canvas = canvasRef.current;\n const context = canvas?.getContext(\"2d\");\n if (!canvas || !context) return;\n\n canvas.width = Math.floor(viewport.width);\n canvas.height = Math.floor(viewport.height);\n setSize({ width: cssViewport.width, height: cssViewport.height });\n\n task = page.render({ canvasContext: context, viewport });\n await task.promise;\n if (cancelled) return;\n\n const content = await page.getTextContent();\n if (cancelled) return;\n setItems(content.items);\n setSpans(toTextSpans(content.items, cssViewport.height, scale));\n setFailed(undefined);\n } catch (error) {\n // A cancelled render is the normal outcome of scrolling quickly; only a\n // settled failure is news (loading-states.md).\n if (cancelled) return;\n const message = error instanceof Error ? error.message : String(error);\n if (/cancel/i.test(message)) return;\n setFailed(message);\n }\n })();\n\n return () => {\n cancelled = true;\n task?.cancel();\n page?.cleanup();\n };\n }, [handle, pageNumber, scale]);\n\n // MAP + PAINT. Turning the shell's offsets into rectangles needs this page's\n // own items, which the effect above already fetched for the text layer.\n const boxes = useMemo<PdfHighlightBox[]>(() => {\n if (!size) return [];\n // A `rect` address is already geometry — it only has to be on this page.\n // `page` defaults to 1 so a single-page citation needs no page number.\n const geometry = (highlights ?? []).filter(\n (highlight) =>\n highlight.status === \"resolved\" &&\n highlight.rects !== undefined &&\n (highlight.page ?? 1) === pageNumber,\n );\n return [\n ...(pageStart === undefined ? [] : rangeBoxes(spans, pageTextChunk(items), pageStart, marks)),\n ...rectBoxes(geometry, size),\n ];\n }, [size, highlights, pageNumber, pageStart, spans, items, marks]);\n\n // The boxes arrive a tick after the page does (the text content is fetched\n // asynchronously), so the scroll waits for them rather than for the id.\n useScrollActiveHighlightIntoView(pageRef, activeHighlightId, boxes);\n\n if (failed) {\n return (\n <div\n className=\"mx-auto flex w-fit items-center justify-center\"\n style={size ? { width: size.width, height: size.height } : undefined}\n >\n <StatePanel\n kind=\"error\"\n title={t(\"viewer.error.parseFailed\")}\n description={t(\"viewer.pdf.pageFailed\", {\n page: formatNumber(pageNumber),\n })}\n />\n </div>\n );\n }\n\n return (\n <div\n ref={pageRef}\n data-slot=\"pdf-page\"\n data-page={pageNumber}\n className=\"border-border relative mx-auto w-fit border shadow-sm\"\n style={size ? { width: size.width, height: size.height } : undefined}\n >\n <canvas\n ref={canvasRef}\n // The page's own description, so a screen reader gets what the document\n // is rather than \"canvas\". The text layer below carries the words\n // themselves. Every page names its own number, which is what makes a\n // continuous column navigable by heading-less landmark browsing.\n role=\"img\"\n aria-label={alt ?? t(\"viewer.pdf.page\", { page: formatNumber(pageNumber) })}\n className=\"block\"\n style={size ? { width: size.width, height: size.height } : undefined}\n />\n {/* Transparent, selectable text over the raster. `select-text` and the\n transforms come from pdf.js's own item geometry. */}\n <div aria-hidden={spans.length === 0} className=\"absolute inset-0 select-text\">\n {spans.map((span, index) => (\n <span\n key={index}\n className=\"absolute origin-top-left whitespace-pre text-transparent\"\n style={{\n left: span.left,\n top: span.top,\n fontSize: span.fontSize,\n lineHeight: 1,\n }}\n >\n {span.text}\n </span>\n ))}\n </div>\n {/* Decorative: the words themselves are in the text layer above, and the\n shell's status line is what names the citation. A plate here would\n otherwise be read out as an unlabelled region.\n\n Translucent rather than a solid plate, because the \"ink\" it sits on is\n the raster below it — an opaque mark would delete the very sentence it\n is pointing at. The current box is not distinguished by colour alone\n (WCAG 1.4.1): it is also drawn twice as thick. */}\n <div aria-hidden=\"true\" className=\"pointer-events-none absolute inset-0\">\n {boxes.map((box, index) => (\n <div\n key={index}\n data-slot=\"highlight-rect\"\n // Presence form, matching every other painter's `data-active`.\n data-active={box.active ? \"\" : undefined}\n className={cn(\n \"absolute rounded-xs\",\n box.active\n ? \"bg-highlight-active/30 border-highlight-active border-2\"\n : \"bg-highlight/35 border-highlight border\",\n )}\n style={{\n left: box.left,\n top: box.top,\n width: box.width,\n height: box.height,\n }}\n />\n ))}\n </div>\n </div>\n );\n}\n\n/**\n * pdf.js text geometry → CSS boxes.\n *\n * Item transforms are `[a, b, c, d, e, f]` in PDF user space, whose origin is\n * the BOTTOM-left of the page; CSS measures from the top. `d` carries the glyph\n * height, which is the font size once scaled.\n *\n * Whitespace-only items are dropped — they would be invisible clutter in the\n * text layer — so each span carries the index of the item it came from. That is\n * what lets a highlight box find its geometry after the filtering, without\n * either side counting positions.\n */\nexport function toTextSpans(\n items: { str: string; transform: number[]; width?: number }[],\n pageHeight: number,\n scale: number,\n): PdfTextSpan[] {\n const spans: PdfTextSpan[] = [];\n items.forEach((item, index) => {\n if (!item.str.trim()) return;\n const [, , , d = 0, e = 0, f = 0] = item.transform;\n const fontSize = Math.abs(d) * scale;\n spans.push({\n text: item.str,\n left: e * scale,\n top: pageHeight - f * scale - fontSize,\n width: (item.width ?? 0) * scale,\n fontSize,\n item: index,\n });\n });\n return spans;\n}\n\nconst adapterModule: AdapterModule = {\n manifest: pdfManifest,\n create: () => new PdfAdapter(),\n Renderer: PdfRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import {
3
+ configurePdfEngine,
4
+ getPdfEngineConfig,
5
+ loadPdfEngine,
6
+ openPdfDocument
7
+ } from "../../chunk-SBG7WPGO.js";
8
+ export {
9
+ configurePdfEngine,
10
+ getPdfEngineConfig,
11
+ loadPdfEngine,
12
+ openPdfDocument
13
+ };
14
+ //# sourceMappingURL=pdf-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ pdfManifest
4
+ } from "../../chunk-M77ICVWP.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ pdfManifest
8
+ };
9
+ //# sourceMappingURL=pdf-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import {
3
+ PDF_ITEM_SEPARATOR,
4
+ PDF_PAGE_SEPARATOR,
5
+ pageOfHighlight,
6
+ pageTextChunk,
7
+ rangeBoxes,
8
+ rectBoxes
9
+ } from "../../chunk-G27UJZWH.js";
10
+ import "../../chunk-5YE2MUS2.js";
11
+ import "../../chunk-HOQZ7OPH.js";
12
+ export {
13
+ PDF_ITEM_SEPARATOR,
14
+ PDF_PAGE_SEPARATOR,
15
+ pageOfHighlight,
16
+ pageTextChunk,
17
+ rangeBoxes,
18
+ rectBoxes
19
+ };
20
+ //# sourceMappingURL=pdf-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}