@elabs-ai/components-viewer 4.2.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,78 +1,29 @@
1
1
  "use client";
2
2
  "use client";
3
3
  import {
4
- codeManifest,
4
+ codeManifest
5
+ } from "../../chunk-CMYBLW7D.js";
6
+ import {
5
7
  languageFor
6
- } from "./chunk-5OMONA2G.js";
8
+ } from "../../chunk-6FVJ4D7W.js";
9
+ import {
10
+ codeViewerTheme
11
+ } from "../../chunk-BDUFH66C.js";
7
12
  import {
8
- localizeRanges,
9
- toMarkRanges,
10
13
  useScrollActiveHighlightIntoView
11
- } from "./chunk-VO2273Z2.js";
14
+ } from "../../chunk-IB4N72FA.js";
15
+ import {
16
+ localizeRanges,
17
+ toMarkRanges
18
+ } from "../../chunk-HOQZ7OPH.js";
12
19
  import {
13
20
  toViewerError
14
- } from "./chunk-AORNMH77.js";
21
+ } from "../../chunk-JHFC2KBI.js";
22
+ import "../../chunk-CIT2HHRI.js";
15
23
 
16
24
  // src/adapters/code/code-adapter.tsx
17
25
  import { MatchHighlight, cn, StatePanel, useLocale } from "@elabs-ai/components-ui";
18
26
  import { Fragment, useMemo, useRef } from "react";
19
-
20
- // src/adapters/code/code-theme.ts
21
- var SCOPE_COLORS = [
22
- {
23
- scopes: ["comment", "punctuation.definition.comment"],
24
- token: "--code-comment",
25
- italic: true
26
- },
27
- { scopes: ["string", "string.quoted", "punctuation.definition.string"], token: "--code-string" },
28
- {
29
- scopes: ["constant", "constant.language", "constant.character", "support.constant"],
30
- token: "--code-constant"
31
- },
32
- { scopes: ["constant.numeric", "keyword.other.unit"], token: "--code-number" },
33
- {
34
- scopes: ["keyword", "keyword.control", "keyword.operator", "storage", "storage.type"],
35
- token: "--code-keyword"
36
- },
37
- {
38
- scopes: ["entity.name.function", "support.function", "meta.function-call"],
39
- token: "--code-function"
40
- },
41
- {
42
- scopes: ["entity.name.type", "entity.name.class", "support.type", "support.class"],
43
- token: "--code-type"
44
- },
45
- { scopes: ["entity.name.tag", "punctuation.definition.tag"], token: "--code-tag" },
46
- { scopes: ["variable", "support.variable", "meta.object-literal.key"], token: "--code-property" },
47
- // Same colour as a property, but the one other scope that leans. Its own rule,
48
- // for the reason in the docblock above.
49
- { scopes: ["entity.other.attribute-name"], token: "--code-property", italic: true }
50
- ];
51
- var codeViewerTheme = {
52
- name: "brand-ui-viewer",
53
- // Shiki uses `type` only to pick its own light/dark defaults, which this theme
54
- // overrides wholesale. It is `css` — neither, resolved at paint time.
55
- type: "dark",
56
- colors: {
57
- // The renderer owns the surface; the theme must not paint over it.
58
- "editor.background": "transparent",
59
- "editor.foreground": "var(--code-foreground)"
60
- },
61
- fg: "var(--code-foreground)",
62
- bg: "transparent",
63
- settings: [
64
- { settings: { foreground: "var(--code-foreground)" } },
65
- ...SCOPE_COLORS.map(({ scopes, token, italic }) => ({
66
- scope: scopes,
67
- settings: {
68
- foreground: `var(${token})`,
69
- ...italic ? { fontStyle: "italic" } : void 0
70
- }
71
- }))
72
- ]
73
- };
74
-
75
- // src/adapters/code/code-adapter.tsx
76
27
  import { jsx, jsxs } from "react/jsx-runtime";
77
28
  var CODE_CHARACTER_LIMIT = 4e5;
78
29
  var hasFontFlag = (fontStyle, flag) => ((fontStyle ?? 0) & flag) === flag;
@@ -223,4 +174,4 @@ export {
223
174
  CODE_CHARACTER_LIMIT,
224
175
  code_adapter_default as default
225
176
  };
226
- //# sourceMappingURL=code-adapter-ADZ4UOGN.js.map
177
+ //# sourceMappingURL=code-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/code/code-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Code adapter — source files, highlighted with Shiki and coloured by tokens.\n *\n * Highlighting happens at LOAD, not at render: `load()` returns lines of plain\n * `{ text, color }` tokens, so the renderer draws data like every other adapter\n * and Shiki never reaches the render path. The colours are `var(--code-*)`\n * references (see `code-theme.ts`), which is why a theme switch recolours the\n * document without re-tokenizing it.\n *\n * The plain-text adapter is still the backstop. This one claims extensions it\n * has a grammar for; anything else — a log, a `.env`, no extension at all —\n * falls through to text, and so does every file when Shiki is not installed.\n */\n\nimport { MatchHighlight, cn, StatePanel, useLocale } from \"@elabs-ai/components-ui\";\nimport type { ResolvedFileSource } from \"@elabs-ai/components-ui\";\nimport { Fragment, useMemo, useRef } from \"react\";\nimport type { BundledLanguage, ThemedToken } from \"shiki\";\n\nimport { toViewerError } from \"../../core/errors\";\nimport { localizeRanges, 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 { languageFor } from \"./code-language\";\nimport { codeManifest } from \"./code-manifest\";\nimport { codeViewerTheme } from \"./code-theme\";\n\n/**\n * Characters kept before truncation. Well below the plain-text limit because\n * this text is also TOKENIZED — a grammar pass over multiple megabytes blocks\n * the main thread, and no one reads a 400k-character file in a preview pane.\n */\nexport const CODE_CHARACTER_LIMIT = 400_000;\n\n/** One highlighted run. `color` is always a `var(--code-*)` reference. */\nexport interface CodeToken {\n text: string;\n color?: string;\n italic?: boolean;\n bold?: boolean;\n underline?: boolean;\n}\n\nexport interface CodeDocument extends AdapterDocument {\n kind: \"code\";\n /** Shiki language id, or `undefined` when the file rendered unhighlighted. */\n language?: string;\n /** One entry per line; a blank line is an empty array. */\n lines: CodeToken[][];\n text: string;\n /** Total characters in the file, when more than what is shown. */\n totalCharacters?: number;\n}\n\n// Shiki encodes font style as bitflags: 1 = italic, 2 = bold, 4 = underline.\nconst hasFontFlag = (fontStyle: number | undefined, flag: number) =>\n ((fontStyle ?? 0) & flag) === flag;\n\n/**\n * Highlighters, cached per language for the lifetime of the page.\n *\n * Not per-document state, so it deliberately outlives the adapter instance:\n * building one loads a grammar and the WASM engine, and paging through twenty\n * TypeScript files in a file tree should pay for that once.\n */\nconst highlighters = new Map<string, Promise<{ tokenize(code: string): ThemedToken[][] }>>();\n\nfunction getHighlighter(language: BundledLanguage) {\n let pending = highlighters.get(language);\n if (!pending) {\n pending = (async () => {\n // Dynamic: the ONLY edge to the optional peer (heavy-deps:check).\n const { createHighlighter } = await import(\"shiki\");\n const highlighter = await createHighlighter({\n themes: [codeViewerTheme],\n langs: [language],\n });\n return {\n tokenize: (code: string) =>\n highlighter.codeToTokens(code, {\n lang: language,\n theme: codeViewerTheme.name as string,\n }).tokens,\n };\n })().catch((error: unknown) => {\n // Not cached: a peer installed later, or a transient chunk-load failure,\n // must be retryable without a page reload.\n highlighters.delete(language);\n throw error;\n });\n highlighters.set(language, pending);\n }\n return pending;\n}\n\n/** Split unhighlighted text into the same line/token shape. */\nfunction plainLines(text: string): CodeToken[][] {\n return text.split(\"\\n\").map((line) => (line.length > 0 ? [{ text: line }] : []));\n}\n\nclass CodeAdapter implements FileAdapter {\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<CodeDocument> {\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 const truncated = raw.length > CODE_CHARACTER_LIMIT;\n const text = truncated ? raw.slice(0, CODE_CHARACTER_LIMIT) : raw;\n const totalCharacters = truncated ? raw.length : undefined;\n // So a passage the shell cannot find reads as \"past the part we previewed\"\n // rather than \"not in this document\".\n const textTruncated = truncated || undefined;\n const language = languageFor(source.name);\n\n // No grammar for this name — still a perfectly readable file.\n if (!language) {\n return { kind: \"code\", lines: plainLines(text), text, totalCharacters, textTruncated };\n }\n\n const highlighter = await getHighlighter(language);\n if (context.signal?.aborted) {\n return {\n kind: \"code\",\n language,\n lines: plainLines(text),\n text,\n totalCharacters,\n textTruncated,\n };\n }\n\n const lines = highlighter.tokenize(text).map((line) =>\n line.map((token) => ({\n text: token.content,\n color: token.color,\n italic: hasFontFlag(token.fontStyle, 1) || undefined,\n bold: hasFontFlag(token.fontStyle, 2) || undefined,\n underline: hasFontFlag(token.fontStyle, 4) || undefined,\n })),\n );\n\n return { kind: \"code\", language, lines, text, totalCharacters, textTruncated };\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Renderer */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Where each rendered line begins in `document.text`.\n *\n * Derived from the TEXT, not from the token lines: the text is the address space\n * every highlight is expressed in, so counting its newlines is the only mapping\n * that cannot drift from what a caller asked for. The two agree by construction\n * — the tokenizer splits on the same newlines — and `code-adapter.test.tsx`\n * locks that.\n */\nfunction lineStartsIn(text: string): number[] {\n const starts = [0];\n for (let i = 0; i < text.length; i++) {\n if (text[i] === \"\\n\") starts.push(i + 1);\n }\n return starts;\n}\n\nfunction CodeRenderer({\n document: doc,\n className,\n highlights,\n activeHighlightId,\n}: AdapterRendererProps) {\n const code = doc as CodeDocument;\n const { t, formatNumber } = useLocale();\n const container = useRef<HTMLDivElement>(null);\n const lineStarts = useMemo(() => lineStartsIn(code.text), [code.text]);\n const marks = useMemo(\n () => toMarkRanges(highlights, code.text.length),\n [highlights, code.text.length],\n );\n useScrollActiveHighlightIntoView(container, activeHighlightId);\n\n if (code.text.length === 0) {\n return <StatePanel kind=\"empty\" title={t(\"viewer.file.empty\")} className={className} />;\n }\n\n return (\n // No `overflow-auto` here: `FileViewerContent` is the scroll boundary, and\n // nesting a second one clips the last line above the outer pane's padding.\n <div ref={container} className={cn(\"flex flex-col gap-2\", className)}>\n {code.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(code.text.length),\n total: formatNumber(code.totalCharacters),\n })}\n </p>\n )}\n <pre className=\"text-code text-code-foreground font-mono\">\n <code className=\"grid grid-cols-[auto_1fr] gap-x-4\">\n {code.lines.map((tokens, lineIndex) => {\n let offset = lineStarts[lineIndex] ?? code.text.length;\n return (\n <Fragment key={lineIndex}>\n {/* Decorative: the numbers are a reading aid, and keeping them out\n of the accessibility tree also keeps them out of a copy. Not\n `formatNumber` — a line gutter is an ordinal, so a thousands\n separator at line 1,000 would be wrong in every locale. */}\n <span\n aria-hidden=\"true\"\n className=\"text-muted-foreground text-right tabular-nums select-none\"\n >\n {lineIndex + 1}\n </span>\n <span className=\"break-words whitespace-pre-wrap\">\n {tokens.map((token, tokenIndex) => {\n const start = offset;\n offset += token.text.length;\n // Syntax colour is inline `var(--code-*)` (see the module\n // header), and a mark's plate would fight it — so the mark\n // layer only wraps the tokens it actually touches, and every\n // other token keeps rendering exactly as before.\n const local = localizeRanges(marks, start, offset);\n const style = {\n color: token.color,\n fontStyle: token.italic ? \"italic\" : undefined,\n fontWeight: token.bold ? \"bold\" : undefined,\n textDecoration: token.underline ? \"underline\" : undefined,\n };\n return local.ranges.length === 0 ? (\n <span key={tokenIndex} style={style}>\n {token.text}\n </span>\n ) : (\n <MatchHighlight\n key={tokenIndex}\n style={style}\n text={token.text}\n ranges={local.ranges}\n activeIndex={local.activeIndex}\n />\n );\n })}\n </span>\n </Fragment>\n );\n })}\n </code>\n </pre>\n </div>\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: codeManifest,\n create: () => new CodeAdapter(),\n Renderer: CodeRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import {
3
+ CODE_EXTENSIONS,
4
+ languageFor
5
+ } from "../../chunk-6FVJ4D7W.js";
6
+ export {
7
+ CODE_EXTENSIONS,
8
+ languageFor
9
+ };
10
+ //# sourceMappingURL=code-language.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import {
3
+ codeManifest
4
+ } from "../../chunk-CMYBLW7D.js";
5
+ import "../../chunk-6FVJ4D7W.js";
6
+ import "../../chunk-CIT2HHRI.js";
7
+ export {
8
+ codeManifest
9
+ };
10
+ //# sourceMappingURL=code-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import {
3
+ codeViewerTheme
4
+ } from "../../chunk-BDUFH66C.js";
5
+ export {
6
+ codeViewerTheme
7
+ };
8
+ //# sourceMappingURL=code-theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,21 +1,25 @@
1
1
  "use client";
2
2
  "use client";
3
3
  import {
4
- csvManifest
5
- } from "./chunk-3U3MESBU.js";
4
+ SheetTable
5
+ } from "../../chunk-AK7F3IZE.js";
6
6
  import {
7
- SheetTable,
8
7
  gridToText
9
- } from "./chunk-XBOR2YXS.js";
10
- import "./chunk-2NQ4RSJ3.js";
11
- import "./chunk-UL43NGUG.js";
8
+ } from "../../chunk-TLCNGQKL.js";
9
+ import {
10
+ csvManifest
11
+ } from "../../chunk-EA72HA4I.js";
12
+ import "../../chunk-GNBD53AT.js";
13
+ import "../../chunk-5YE2MUS2.js";
14
+ import "../../chunk-IB4N72FA.js";
12
15
  import {
13
16
  toMarkRanges
14
- } from "./chunk-VO2273Z2.js";
17
+ } from "../../chunk-HOQZ7OPH.js";
15
18
  import {
16
19
  ViewerError,
17
20
  toViewerError
18
- } from "./chunk-AORNMH77.js";
21
+ } from "../../chunk-JHFC2KBI.js";
22
+ import "../../chunk-CIT2HHRI.js";
19
23
 
20
24
  // src/adapters/csv/csv-adapter.tsx
21
25
  import { useMemo } from "react";
@@ -97,4 +101,4 @@ export {
97
101
  CSV_ROW_LIMIT,
98
102
  csv_adapter_default as default
99
103
  };
100
- //# sourceMappingURL=csv-adapter-7HOFZ5Z6.js.map
104
+ //# sourceMappingURL=csv-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/csv/csv-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * CSV / TSV adapter — a real parser and a real table.\n *\n * Two things this fixes at once:\n *\n * - **Correctness.** The repo's previous CSV \"parser\" was `line.split(\",\")`\n * (`packages/ai/src/asset-preview.tsx:69`), which mangles every quoted comma —\n * i.e. every address, every price list, every free-text column. Papa Parse\n * handles quoting, escapes, embedded newlines and delimiter detection.\n * - **Theming.** anyview's CSV adapter emits an HTML string with `#ddd` and\n * `#f5f5f5` baked in (`CsvAdapter.ts:184`). This one emits ROWS and hands them\n * to `@elabs-ai/components-ui`'s `Table`, so the grid is tokened and\n * re-themes with everything else.\n *\n * `papaparse` is an OPTIONAL peer, reached only through the dynamic import\n * below. A consumer who never opens a spreadsheet never installs it, and one who\n * forgot gets a \"install papaparse\" message rather than a resolution stack trace\n * (`isModuleNotFound` in `core/errors.ts`).\n */\n\nimport type { ResolvedFileSource } from \"@elabs-ai/components-ui\";\nimport { useMemo } from \"react\";\n\nimport { gridToText, type GridRef } from \"../../components/grid-text\";\nimport { SheetTable } from \"../../components/sheet-table\";\n\nimport { ViewerError, toViewerError } from \"../../core/errors\";\nimport { toMarkRanges } from \"../../core/highlight-marks\";\nimport type { TextIndex } from \"../../core/text-index\";\nimport type {\n AdapterDocument,\n AdapterLoadContext,\n AdapterModule,\n AdapterRendererProps,\n FileAdapter,\n} from \"../../core/types\";\nimport { csvManifest } from \"./csv-manifest\";\n\n/**\n * Rows rendered before truncation. A preview pane is for looking, not for\n * analysis — past this, reach for `@elabs-ai/components-data`'s\n * `DataTable`, which virtualizes.\n */\nexport const CSV_ROW_LIMIT = 5_000;\n\nexport interface CsvDocument extends AdapterDocument {\n kind: \"csv\";\n /** Header cells. Empty when the file had no usable first row. */\n columns: string[];\n /** Body rows, already capped at {@link CSV_ROW_LIMIT}. */\n rows: string[][];\n /** Total body rows in the file, when more than what is shown. */\n totalRows?: number;\n /** Which row each stretch of `text` came from. */\n textIndex?: TextIndex<GridRef>;\n}\n\nclass CsvAdapter implements FileAdapter {\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<CsvDocument> {\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 // Dynamic: this is the ONLY edge to the optional peer. A static import here\n // would break every consumer that did not install it (heavy-deps:check).\n const Papa = await import(\"papaparse\");\n const parsed = Papa.parse<string[]>(text, {\n skipEmptyLines: \"greedy\",\n // Let Papa detect `,` vs `\\t` vs `;` rather than trusting the extension —\n // a .csv exported by a European locale is very often semicolon-delimited.\n delimiter: \"\",\n });\n\n // Papa reports recoverable problems as errors while still returning data;\n // only an empty result with errors is genuinely unreadable.\n if (parsed.data.length === 0 && parsed.errors.length > 0) {\n throw new ViewerError(\n \"parse-failed\",\n parsed.errors[0]?.message ?? \"Could not parse the file.\",\n {\n fileName: source.name,\n },\n );\n }\n\n const [header = [], ...body] = parsed.data;\n const rows = body.length <= CSV_ROW_LIMIT ? body : body.slice(0, CSV_ROW_LIMIT);\n // `text` is the PARSED grid, not the raw file (changed in this release).\n // A citation's offsets have to address what the reader can see: the raw\n // bytes carry quoting, escapes and a delimiter that may not be a comma, so\n // an offset into them lands nowhere in particular in the rendered table.\n const textIndex = gridToText([{ columns: header, rows }]);\n return {\n kind: \"csv\",\n columns: header,\n rows,\n ...(body.length > CSV_ROW_LIMIT ? { totalRows: body.length } : {}),\n text: textIndex.text,\n textIndex,\n };\n }\n}\n\nfunction CsvRenderer({\n document: doc,\n className,\n highlights,\n activeHighlightId,\n}: AdapterRendererProps) {\n const csv = doc as CsvDocument;\n const marks = useMemo(\n () => toMarkRanges(highlights, csv.text?.length ?? 0),\n [highlights, csv.text],\n );\n // One sheet, so a row's start is simply the span whose ref names that row.\n const rowStart = useMemo(() => {\n const starts = new Map<number, number>();\n for (const span of csv.textIndex?.spans ?? []) starts.set(span.ref.row, span.start);\n return (row: number) => starts.get(row);\n }, [csv.textIndex]);\n\n return (\n <SheetTable\n columns={csv.columns}\n rows={csv.rows}\n totalRows={csv.totalRows}\n className={className}\n marks={marks}\n rowStart={rowStart}\n activeHighlightId={activeHighlightId}\n />\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: csvManifest,\n create: () => new CsvAdapter(),\n Renderer: CsvRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAS,eAAe;AAwGpB;AAlFG,IAAM,gBAAgB;AAc7B,IAAM,aAAN,MAAwC;AAAA,EACtC,MAAM,KAAK,QAA4B,SAAmD;AACxF,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;AAIA,UAAM,OAAO,MAAM,OAAO,WAAW;AACrC,UAAM,SAAS,KAAK,MAAgB,MAAM;AAAA,MACxC,gBAAgB;AAAA;AAAA;AAAA,MAGhB,WAAW;AAAA,IACb,CAAC;AAID,QAAI,OAAO,KAAK,WAAW,KAAK,OAAO,OAAO,SAAS,GAAG;AACxD,YAAM,IAAI;AAAA,QACR;AAAA,QACA,OAAO,OAAO,CAAC,GAAG,WAAW;AAAA,QAC7B;AAAA,UACE,UAAU,OAAO;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,CAAC,SAAS,CAAC,GAAG,GAAG,IAAI,IAAI,OAAO;AACtC,UAAM,OAAO,KAAK,UAAU,gBAAgB,OAAO,KAAK,MAAM,GAAG,aAAa;AAK9E,UAAM,YAAY,WAAW,CAAC,EAAE,SAAS,QAAQ,KAAK,CAAC,CAAC;AACxD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,MACT;AAAA,MACA,GAAI,KAAK,SAAS,gBAAgB,EAAE,WAAW,KAAK,OAAO,IAAI,CAAC;AAAA,MAChE,MAAM,UAAU;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,YAAY;AAAA,EACnB,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,MAAM;AACZ,QAAM,QAAQ;AAAA,IACZ,MAAM,aAAa,YAAY,IAAI,MAAM,UAAU,CAAC;AAAA,IACpD,CAAC,YAAY,IAAI,IAAI;AAAA,EACvB;AAEA,QAAM,WAAW,QAAQ,MAAM;AAC7B,UAAM,SAAS,oBAAI,IAAoB;AACvC,eAAW,QAAQ,IAAI,WAAW,SAAS,CAAC,EAAG,QAAO,IAAI,KAAK,IAAI,KAAK,KAAK,KAAK;AAClF,WAAO,CAAC,QAAgB,OAAO,IAAI,GAAG;AAAA,EACxC,GAAG,CAAC,IAAI,SAAS,CAAC;AAElB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS,IAAI;AAAA,MACb,MAAM,IAAI;AAAA,MACV,WAAW,IAAI;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAM,gBAA+B;AAAA,EACnC,UAAU;AAAA,EACV,QAAQ,MAAM,IAAI,WAAW;AAAA,EAC7B,UAAU;AACZ;AAEA,IAAO,sBAAQ;","names":[]}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ csvManifest
4
+ } from "../../chunk-EA72HA4I.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ csvManifest
8
+ };
9
+ //# sourceMappingURL=csv-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,21 +1,29 @@
1
1
  "use client";
2
2
  "use client";
3
+ import {
4
+ DOCX_CELL_SEPARATOR,
5
+ DOCX_HEAD_ROW,
6
+ DOCX_LIST_BULLET,
7
+ blocksToTextWithMap,
8
+ htmlToBlocks
9
+ } from "../../chunk-5VJWILZ7.js";
3
10
  import {
4
11
  docxManifest
5
- } from "./chunk-FELIAGKI.js";
12
+ } from "../../chunk-I5XD2NJ6.js";
6
13
  import {
7
14
  MarkedText
8
- } from "./chunk-2NQ4RSJ3.js";
9
- import {
10
- createTextIndexBuilder
11
- } from "./chunk-UL43NGUG.js";
15
+ } from "../../chunk-GNBD53AT.js";
16
+ import "../../chunk-5YE2MUS2.js";
12
17
  import {
13
- toMarkRanges,
14
18
  useScrollActiveHighlightIntoView
15
- } from "./chunk-VO2273Z2.js";
19
+ } from "../../chunk-IB4N72FA.js";
20
+ import {
21
+ toMarkRanges
22
+ } from "../../chunk-HOQZ7OPH.js";
16
23
  import {
17
24
  toViewerError
18
- } from "./chunk-AORNMH77.js";
25
+ } from "../../chunk-JHFC2KBI.js";
26
+ import "../../chunk-CIT2HHRI.js";
19
27
 
20
28
  // src/adapters/docx/docx-adapter.tsx
21
29
  import {
@@ -35,172 +43,6 @@ import {
35
43
  useLocale
36
44
  } from "@elabs-ai/components-ui";
37
45
  import { useMemo, useRef } from "react";
38
-
39
- // src/adapters/docx/docx-model.ts
40
- var SAFE_SCHEMES = ["http:", "https:", "mailto:", "tel:"];
41
- function safeHref(value) {
42
- if (!value) return void 0;
43
- try {
44
- const url = new URL(value, "https://viewer.invalid");
45
- return SAFE_SCHEMES.includes(url.protocol) && !value.startsWith("#") ? url.href : void 0;
46
- } catch {
47
- return void 0;
48
- }
49
- }
50
- function collectRuns(node, style = {}, out = []) {
51
- for (const child of Array.from(node.childNodes)) {
52
- if (child.nodeType === 3) {
53
- const text = child.nodeValue ?? "";
54
- if (text) out.push({ text, ...style });
55
- continue;
56
- }
57
- if (child.nodeType !== 1) continue;
58
- const element = child;
59
- const tag = element.tagName.toLowerCase();
60
- if (tag === "br") {
61
- out.push({ text: "\n", ...style });
62
- continue;
63
- }
64
- const next = { ...style };
65
- if (tag === "strong" || tag === "b") next.bold = true;
66
- if (tag === "em" || tag === "i") next.italic = true;
67
- if (tag === "a") {
68
- const href = safeHref(element.getAttribute("href"));
69
- if (href) next.href = href;
70
- }
71
- collectRuns(element, next, out);
72
- }
73
- return out;
74
- }
75
- function compact(runs) {
76
- const merged = [];
77
- for (const run of runs) {
78
- const last = merged[merged.length - 1];
79
- if (last && last.bold === run.bold && last.italic === run.italic && last.href === run.href) {
80
- last.text += run.text;
81
- } else {
82
- merged.push({ ...run });
83
- }
84
- }
85
- return merged.filter((run) => run.text.trim() !== "" || run.text.includes("\n"));
86
- }
87
- function textOf(node) {
88
- return compact(collectRuns(node)).map((run) => run.text).join("").trim();
89
- }
90
- function listItems(element) {
91
- const items = [];
92
- for (const child of Array.from(element.children)) {
93
- if (child.tagName.toLowerCase() !== "li") continue;
94
- const runs = compact(collectRuns(child));
95
- if (runs.length > 0) items.push(runs);
96
- for (const nested of Array.from(child.children)) {
97
- const tag = nested.tagName.toLowerCase();
98
- if (tag === "ul" || tag === "ol") items.push(...listItems(nested));
99
- }
100
- }
101
- return items;
102
- }
103
- function tableBlock(element) {
104
- const rows = Array.from(element.querySelectorAll("tr"));
105
- if (rows.length === 0) return void 0;
106
- const cellsOf = (row) => Array.from(row.children).filter((cell) => ["td", "th"].includes(cell.tagName.toLowerCase())).map(textOf);
107
- const [firstRow, ...restRows] = rows;
108
- if (!firstRow) return void 0;
109
- const isHeader = firstRow.querySelector("th") !== null;
110
- return isHeader ? { type: "table", head: cellsOf(firstRow), rows: restRows.map(cellsOf) } : { type: "table", rows: rows.map(cellsOf) };
111
- }
112
- var HEADING_LEVELS = {
113
- h1: 1,
114
- h2: 2,
115
- h3: 3,
116
- h4: 4,
117
- h5: 5,
118
- h6: 6
119
- };
120
- function htmlToBlocks(html, parse) {
121
- const document = parse(`<body>${html}</body>`);
122
- const blocks = [];
123
- const walk = (parent) => {
124
- for (const element of Array.from(parent.children)) {
125
- const tag = element.tagName.toLowerCase();
126
- const level = HEADING_LEVELS[tag];
127
- if (level) {
128
- const runs = compact(collectRuns(element));
129
- if (runs.length > 0) blocks.push({ type: "heading", level, runs });
130
- continue;
131
- }
132
- if (tag === "p") {
133
- const image = element.querySelector("img");
134
- const runs = compact(collectRuns(element));
135
- if (image && runs.length === 0) {
136
- blocks.push(imageBlock(image));
137
- continue;
138
- }
139
- if (runs.length > 0) blocks.push({ type: "paragraph", runs });
140
- continue;
141
- }
142
- if (tag === "ul" || tag === "ol") {
143
- const items = listItems(element);
144
- if (items.length > 0) blocks.push({ type: "list", ordered: tag === "ol", items });
145
- continue;
146
- }
147
- if (tag === "table") {
148
- const table = tableBlock(element);
149
- if (table) blocks.push(table);
150
- continue;
151
- }
152
- if (tag === "img") {
153
- blocks.push(imageBlock(element));
154
- continue;
155
- }
156
- walk(element);
157
- }
158
- };
159
- walk(document.body);
160
- return blocks;
161
- }
162
- function imageBlock(element) {
163
- const alt = element.getAttribute("alt")?.trim();
164
- return {
165
- type: "image",
166
- // mammoth inlines images as `data:` URIs by default, so there is no remote
167
- // origin here — and no `src` at all is better than a URL we did not vet.
168
- src: element.getAttribute("src") ?? "",
169
- ...alt ? { alt } : {}
170
- };
171
- }
172
- var DOCX_LIST_BULLET = "\u2022 ";
173
- var DOCX_CELL_SEPARATOR = " ";
174
- var DOCX_HEAD_ROW = -1;
175
- function blocksToTextWithMap(blocks) {
176
- const builder = createTextIndexBuilder();
177
- blocks.forEach((block, index) => {
178
- if (block.type === "heading" || block.type === "paragraph") {
179
- builder.push(block.runs.map((run) => run.text).join(""), { block: index });
180
- return;
181
- }
182
- if (block.type === "list") {
183
- block.items.forEach((item, item_) => {
184
- builder.push(`${DOCX_LIST_BULLET}${item.map((run) => run.text).join("")}`, {
185
- block: index,
186
- item: item_
187
- });
188
- });
189
- return;
190
- }
191
- if (block.type === "table") {
192
- if (block.head) {
193
- builder.push(block.head.join(DOCX_CELL_SEPARATOR), { block: index, row: DOCX_HEAD_ROW });
194
- }
195
- block.rows.forEach((row, rowIndex) => {
196
- builder.push(row.join(DOCX_CELL_SEPARATOR), { block: index, row: rowIndex });
197
- });
198
- }
199
- });
200
- return builder.build();
201
- }
202
-
203
- // src/adapters/docx/docx-adapter.tsx
204
46
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
205
47
  function parseMarkup(markup) {
206
48
  return new DOMParser().parseFromString(markup, "text/html");
@@ -380,4 +222,4 @@ var docx_adapter_default = adapterModule;
380
222
  export {
381
223
  docx_adapter_default as default
382
224
  };
383
- //# sourceMappingURL=docx-adapter-5CQDHWTD.js.map
225
+ //# sourceMappingURL=docx-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/docx/docx-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Word adapter — a `.docx` becomes blocks, and blocks become brand-ui prose.\n *\n * mammoth does the hard part (unzipping OOXML, resolving styles, numbering,\n * images); `docx-model.ts` then parses its HTML into a model and discards the\n * markup, so nothing here writes `innerHTML`. That single decision is what makes\n * a Word document themeable, Trusted-Types-safe and free of a sanitizer\n * dependency — the reasoning lives in `docx-model.ts`.\n *\n * What a reader gets is the document's STRUCTURE in this system's typography:\n * real headings, real lists, a real `Table`, images with their own alt text. It\n * is not a pixel reproduction of Word's page layout — no page breaks, no columns,\n * no margins — and it does not pretend to be. For a byte-faithful rendering the\n * honest answer is to download the file, which the toolbar already offers.\n */\n\nimport type { ProseHeadingLevel, ResolvedFileSource } from \"@elabs-ai/components-ui\";\nimport {\n cn,\n ProseHeading,\n ProseLink,\n ProseList,\n ProseListItem,\n ProseText,\n StatePanel,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n useLocale,\n} from \"@elabs-ai/components-ui\";\n\nimport { useMemo, useRef } from \"react\";\n\nimport { MarkedText } from \"../../components/marked-text\";\nimport { toViewerError } from \"../../core/errors\";\nimport { toMarkRanges, type MarkRanges } from \"../../core/highlight-marks\";\nimport type { TextIndex, TextSpan } from \"../../core/text-index\";\nimport { useScrollActiveHighlightIntoView } from \"../../core/use-highlight-scroll\";\nimport type {\n AdapterDocument,\n AdapterLoadContext,\n AdapterModule,\n AdapterRendererProps,\n FileAdapter,\n} from \"../../core/types\";\nimport {\n blocksToTextWithMap,\n DOCX_CELL_SEPARATOR,\n DOCX_HEAD_ROW,\n DOCX_LIST_BULLET,\n htmlToBlocks,\n type DocxBlock,\n type DocxRef,\n type DocxRun,\n} from \"./docx-model\";\nimport { docxManifest } from \"./docx-manifest\";\n\nexport interface DocxDocument extends AdapterDocument {\n kind: \"docx\";\n blocks: DocxBlock[];\n /** Non-fatal conversion notes mammoth reported (an unsupported style, a dropped field). */\n warnings: string[];\n /** Which block, item or row each stretch of `text` came from. */\n textIndex?: TextIndex<DocxRef>;\n}\n\n/**\n * Parse markup with the DOM the runtime already has.\n *\n * `DOMParser` is the browser's own parser and jsdom's in tests — it does NOT\n * execute anything it parses, which is why building the model from it is safe\n * even though the input is third-party markup.\n */\nfunction parseMarkup(markup: string): Document {\n return new DOMParser().parseFromString(markup, \"text/html\");\n}\n\nclass DocxAdapter implements FileAdapter {\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<DocxDocument> {\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 mammoth = await import(\"mammoth\");\n\n try {\n const result = await mammoth.convertToHtml({ arrayBuffer: buffer });\n const blocks = htmlToBlocks(result.value, parseMarkup);\n const textIndex = blocksToTextWithMap(blocks);\n return {\n kind: \"docx\",\n blocks,\n // mammoth's messages are about the CONVERSION, not about the file being\n // broken — a document that lost one custom style still reads fine, so\n // they are carried as notes rather than raised as a failure.\n warnings: result.messages.map((message) => message.message),\n text: textIndex.text,\n textIndex,\n };\n } catch (error) {\n throw toViewerError(error, \"parse-failed\", { fileName: source.name });\n }\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Renderer */\n/* -------------------------------------------------------------------------- */\n\nfunction Runs({ runs, marks, start }: { runs: DocxRun[]; marks: MarkRanges; start?: number }) {\n let offset = start;\n return (\n <>\n {runs.map((run, index) => {\n const from = offset;\n if (offset !== undefined) offset += run.text.length;\n // Runs are joined with nothing in the projection, so a run's offset is\n // simply the sum of the ones before it — the same accumulation the code\n // adapter does over syntax tokens.\n const content = <MarkedText text={run.text} marks={marks} start={from} />;\n const bolded = run.bold ? <strong>{content}</strong> : content;\n const styled = run.italic ? <em>{bolded}</em> : bolded;\n if (run.href) {\n return (\n <ProseLink key={index} href={run.href}>\n {styled}\n </ProseLink>\n );\n }\n return <span key={index}>{styled}</span>;\n })}\n </>\n );\n}\n\n/** Shared empty list, so a block with no spans does not remount on every render. */\nconst EMPTY_SPANS: readonly TextSpan<DocxRef>[] = [];\n\n/** The projection offset of one row's `index`-th cell, given the row's own start. */\nfunction cellStart(row: readonly string[], index: number, rowStart?: number): number | undefined {\n if (rowStart === undefined) return undefined;\n let offset = rowStart;\n for (let i = 0; i < index; i += 1) {\n offset += (row[i]?.length ?? 0) + DOCX_CELL_SEPARATOR.length;\n }\n return offset;\n}\n\nfunction Block({\n block,\n baseHeadingLevel,\n marks,\n spans,\n}: {\n block: DocxBlock;\n baseHeadingLevel: number;\n marks: MarkRanges;\n /** The projection spans belonging to THIS block, in document order. */\n spans: readonly TextSpan<DocxRef>[];\n}) {\n const startOf = (match: (ref: DocxRef) => boolean) =>\n spans.find((span) => match(span.ref))?.start;\n\n if (block.type === \"heading\") {\n return (\n // Offset, not absolute: Word's \"Heading 1\" is the top of THAT document,\n // not of the page showing it. Never past h6 — an h7 is not an element.\n <ProseHeading\n level={Math.min(6, Math.max(1, block.level + baseHeadingLevel - 1)) as ProseHeadingLevel}\n >\n <Runs runs={block.runs} marks={marks} start={startOf(() => true)} />\n </ProseHeading>\n );\n }\n if (block.type === \"paragraph\") {\n return (\n <ProseText className=\"whitespace-pre-wrap\">\n <Runs runs={block.runs} marks={marks} start={startOf(() => true)} />\n </ProseText>\n );\n }\n if (block.type === \"list\") {\n return (\n <ProseList ordered={block.ordered}>\n {block.items.map((item, index) => {\n // The bullet is in the projection but not in the DOM — the list\n // element draws it — so an item's own text starts after it.\n const start = startOf((ref) => ref.item === index);\n return (\n <ProseListItem key={index}>\n <Runs\n runs={item}\n marks={marks}\n start={start === undefined ? undefined : start + DOCX_LIST_BULLET.length}\n />\n </ProseListItem>\n );\n })}\n </ProseList>\n );\n }\n if (block.type === \"image\") {\n return (\n <img\n src={block.src}\n // The document's own alt text when the author wrote one. An image with\n // none is decoration as far as the reader can tell, and a filename would\n // be noise, not a description.\n alt={block.alt ?? \"\"}\n {...(block.alt ? {} : { \"aria-hidden\": true })}\n className=\"my-2 block h-auto max-w-full rounded-md\"\n />\n );\n }\n const headStart = startOf((ref) => ref.row === DOCX_HEAD_ROW);\n return (\n <Table className=\"my-2\">\n {block.head && (\n <TableHeader>\n <TableRow>\n {block.head.map((cell, index) => (\n <TableHead key={index} scope=\"col\">\n <MarkedText\n text={cell}\n marks={marks}\n start={cellStart(block.head ?? [], index, headStart)}\n />\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n )}\n <TableBody>\n {block.rows.map((row, rowIndex) => {\n const rowStart = startOf((ref) => ref.row === rowIndex);\n return (\n <TableRow key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <TableCell key={cellIndex} className=\"whitespace-pre-wrap align-top\">\n <MarkedText\n text={cell}\n marks={marks}\n start={cellStart(row, cellIndex, rowStart)}\n />\n </TableCell>\n ))}\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n );\n}\n\nfunction DocxRenderer({\n document: doc,\n className,\n baseHeadingLevel = 2,\n highlights,\n activeHighlightId,\n}: AdapterRendererProps) {\n const docx = doc as DocxDocument;\n const { t } = useLocale();\n const container = useRef<HTMLElement>(null);\n\n const marks = useMemo(\n () => toMarkRanges(highlights, docx.text?.length ?? 0),\n [highlights, docx.text],\n );\n // Grouped once per document rather than searched per block: a long report is\n // thousands of blocks, and a linear scan inside the render loop would make it\n // quadratic on every keystroke of a find-as-you-type.\n const spansByBlock = useMemo(() => {\n const map = new Map<number, TextSpan<DocxRef>[]>();\n for (const span of docx.textIndex?.spans ?? []) {\n const list = map.get(span.ref.block);\n if (list) list.push(span);\n else map.set(span.ref.block, [span]);\n }\n return map;\n }, [docx.textIndex]);\n\n useScrollActiveHighlightIntoView(container, activeHighlightId);\n\n if (docx.blocks.length === 0) {\n return (\n <div className={cn(\"flex min-h-full flex-col justify-center p-4\", className)}>\n <StatePanel kind=\"empty\" title={t(\"viewer.docx.empty\")} />\n </div>\n );\n }\n\n return (\n // `max-w-prose` because this is genuine multi-sentence prose in a pane that\n // can be very wide — the one case styling-and-tokens.md says to cap the\n // measure. Centred so the column does not hug one edge. No `overflow-auto`:\n // `FileViewerContent` is the scroll boundary, and a second one clips the\n // last paragraph above the outer pane's padding.\n <article ref={container} className={cn(\"mx-auto max-w-prose space-y-2\", className)}>\n {docx.blocks.map((block, index) => (\n <Block\n key={index}\n block={block}\n baseHeadingLevel={baseHeadingLevel}\n marks={marks}\n spans={spansByBlock.get(index) ?? EMPTY_SPANS}\n />\n ))}\n </article>\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: docxManifest,\n create: () => new DocxAdapter(),\n Renderer: DocxRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ docxManifest
4
+ } from "../../chunk-I5XD2NJ6.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ docxManifest
8
+ };
9
+ //# sourceMappingURL=docx-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import {
3
+ DOCX_CELL_SEPARATOR,
4
+ DOCX_HEAD_ROW,
5
+ DOCX_LIST_BULLET,
6
+ blocksToText,
7
+ blocksToTextWithMap,
8
+ htmlToBlocks,
9
+ safeHref
10
+ } from "../../chunk-5VJWILZ7.js";
11
+ import "../../chunk-5YE2MUS2.js";
12
+ export {
13
+ DOCX_CELL_SEPARATOR,
14
+ DOCX_HEAD_ROW,
15
+ DOCX_LIST_BULLET,
16
+ blocksToText,
17
+ blocksToTextWithMap,
18
+ htmlToBlocks,
19
+ safeHref
20
+ };
21
+ //# sourceMappingURL=docx-model.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
  imageManifest
5
- } from "./chunk-GGR7BNW4.js";
5
+ } from "../../chunk-HUUJIFFT.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/image/image-adapter.tsx
11
12
  import { cn, StatePanel, useLocale } from "@elabs-ai/components-ui";
@@ -129,4 +130,4 @@ var image_adapter_default = adapterModule;
129
130
  export {
130
131
  image_adapter_default as default
131
132
  };
132
- //# sourceMappingURL=image-adapter-WOHZR24J.js.map
133
+ //# sourceMappingURL=image-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/image/image-adapter.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Image adapter — the reference implementation of \"adapters emit data\".\n *\n * It renders an `<img>`, never a `<canvas>`. anyview draws images to a canvas\n * (`ImageAdapter.ts:118`, `PageRenderer.tsx:128`), which throws away the alt\n * text, the browser's own decoding and zoom, and the ability to select or save\n * the image — with no route back, because its API has no alt-text path at all.\n * Here the description travels on the `FileSource` itself, so a screen reader\n * user gets the same information a sighted user does.\n */\n\nimport { cn, StatePanel, useLocale } from \"@elabs-ai/components-ui\";\nimport { useEffect, useState } from \"react\";\n\nimport type {\n AdapterDocument,\n AdapterLoadContext,\n AdapterModule,\n AdapterRendererProps,\n FileAdapter,\n} from \"../../core/types\";\nimport { imageManifest } from \"./image-manifest\";\nimport { toViewerError } from \"../../core/errors\";\nimport type { ResolvedFileSource } from \"@elabs-ai/components-ui\";\n\nexport interface ImageDocument extends AdapterDocument {\n kind: \"image\";\n /** A URL an `<img>` can load — the source's own URL, or a minted object URL. */\n url: string;\n /** Intrinsic size, once decoded. Used to reserve the box and to label the file. */\n width?: number;\n height?: number;\n}\n\n/** Decode just enough to learn the intrinsic size. Never rejects the load. */\nfunction measure(\n url: string,\n signal?: AbortSignal,\n): Promise<{ width: number; height: number } | undefined> {\n if (typeof Image !== \"function\") return Promise.resolve(undefined);\n return new Promise((resolve) => {\n const img = new Image();\n const done = (value?: { width: number; height: number }) => {\n img.onload = null;\n img.onerror = null;\n resolve(value);\n };\n img.onload = () => done({ width: img.naturalWidth, height: img.naturalHeight });\n // A measurement failure is not a load failure — the <img> will surface it.\n img.onerror = () => done(undefined);\n signal?.addEventListener(\"abort\", () => done(undefined), { once: true });\n img.src = url;\n });\n}\n\nclass ImageAdapter implements FileAdapter {\n #source?: ResolvedFileSource;\n\n async load(source: ResolvedFileSource, context: AdapterLoadContext): Promise<ImageDocument> {\n this.#source = source;\n try {\n const url = await source.url(context.signal);\n const size = await measure(url, context.signal);\n return { kind: \"image\", url, ...size };\n } catch (error) {\n throw toViewerError(error, \"read-failed\", { fileName: source.name });\n }\n }\n\n dispose(): void {\n // Releases the object URL this load minted, if any. A remote public image\n // never minted one, and `revoke()` is a no-op there.\n this.#source?.revoke();\n this.#source = undefined;\n }\n}\n\nfunction ImageRenderer({\n document: doc,\n source,\n className,\n zoom = \"fit-page\",\n rotation = 0,\n}: AdapterRendererProps) {\n const image = doc as ImageDocument;\n const { t } = useLocale();\n const [failed, setFailed] = useState(false);\n\n useEffect(() => setFailed(false), [image.url]);\n\n if (failed) {\n // A terminal, settled failure (loading-states.md): the browser tried and\n // gave up, so this is not a transient not-ready state.\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.error.imageFailedTitle\")}\n description={t(\"viewer.error.imageFailed\", { name: source.name })}\n />\n </div>\n );\n }\n\n const fitting = typeof zoom !== \"number\";\n // A quarter turn swaps the axes: what was the image's height is now the width\n // the reader sees. Everything below that treats 90/270 differently is that one\n // fact — 180 leaves the bounds alone and needs none of it.\n const quarter = rotation === 90 || rotation === 270;\n const scaled =\n fitting || image.width === undefined || image.height === undefined\n ? undefined\n : { width: image.width * zoom, height: image.height * zoom };\n // A `transform` does not change layout, so a turned image at a fixed scale\n // needs a box with the ROTATED bounds. Without one it overflows the pane on\n // every side, and the half above the top edge is unreachable — scrolling only\n // ever reaches transform overflow past the END edges.\n const boxed = quarter && scaled !== undefined;\n\n const img = (\n <img\n src={image.url}\n // An image with no author description is decorative to AT — an empty alt\n // is correct and deliberate, not a missing label.\n alt={source.alt ?? \"\"}\n width={image.width}\n height={image.height}\n onError={() => setFailed(true)}\n className={cn(\n \"block object-contain\",\n !quarter && zoom === \"fit-page\" && \"max-h-full max-w-full\",\n !quarter && zoom === \"fit-width\" && \"h-auto max-w-full\",\n // Turned on its side, the pane's HEIGHT caps the image's width and its\n // width caps the height. Container units read the pane directly, so the\n // fit needs no measurement. Both fit modes converge here deliberately:\n // an image whose rotated width filled the pane would overflow the top\n // edge as well, which is the unreachable half described above.\n fitting && quarter && \"max-h-[100cqw] max-w-[100cqh]\",\n // At a fixed scale the intrinsic cap has to come off, or \"200%\" would\n // silently stop at the pane's width.\n !fitting && \"max-w-none\",\n boxed && \"absolute top-1/2 left-1/2\",\n )}\n style={{\n ...scaled,\n ...(rotation === 0\n ? undefined\n : {\n transform: boxed\n ? `translate(-50%, -50%) rotate(${rotation}deg)`\n : `rotate(${rotation}deg)`,\n }),\n }}\n />\n );\n\n return (\n // Centred on both axes: a small image pinned to the top-left of a tall pane\n // reads as a layout accident. While fitting, the box takes the pane's height\n // so `max-h-full` has something definite to resolve against; at a fixed\n // scale it grows instead, and `FileViewerContent` scrolls it.\n <div\n className={cn(\n \"flex items-center justify-center\",\n fitting ? \"h-full\" : \"min-h-full\",\n // Only a size container can answer `cqh`, and only a definite height\n // makes one — which is exactly the fitting case.\n fitting && quarter && \"[container-type:size]\",\n className,\n )}\n >\n {quarter && scaled ? (\n <div className=\"relative shrink-0\" style={{ width: scaled.height, height: scaled.width }}>\n {img}\n </div>\n ) : (\n img\n )}\n </div>\n );\n}\n\nconst adapterModule: AdapterModule = {\n manifest: imageManifest,\n create: () => new ImageAdapter(),\n Renderer: ImageRenderer,\n};\n\nexport default adapterModule;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ imageManifest
4
+ } from "../../chunk-HUUJIFFT.js";
5
+ import "../../chunk-CIT2HHRI.js";
6
+ export {
7
+ imageManifest
8
+ };
9
+ //# sourceMappingURL=image-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}