@pierre/diffs 1.1.0-beta.1 → 1.1.0-beta.11

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 (313) hide show
  1. package/README.md +7 -18
  2. package/dist/components/AdvancedVirtualizedFileDiff.d.ts +40 -0
  3. package/dist/components/AdvancedVirtualizedFileDiff.d.ts.map +1 -0
  4. package/dist/components/AdvancedVirtualizedFileDiff.js +145 -0
  5. package/dist/components/AdvancedVirtualizedFileDiff.js.map +1 -0
  6. package/dist/components/AdvancedVirtualizer.d.ts +38 -0
  7. package/dist/components/AdvancedVirtualizer.d.ts.map +1 -0
  8. package/dist/components/AdvancedVirtualizer.js +201 -0
  9. package/dist/components/AdvancedVirtualizer.js.map +1 -0
  10. package/dist/components/File.d.ts +60 -29
  11. package/dist/components/File.d.ts.map +1 -1
  12. package/dist/components/File.js +226 -26
  13. package/dist/components/File.js.map +1 -1
  14. package/dist/components/FileDiff.d.ts +44 -12
  15. package/dist/components/FileDiff.d.ts.map +1 -1
  16. package/dist/components/FileDiff.js +510 -71
  17. package/dist/components/FileDiff.js.map +1 -1
  18. package/dist/components/FileStream.d.ts +5 -0
  19. package/dist/components/FileStream.d.ts.map +1 -1
  20. package/dist/components/FileStream.js +66 -8
  21. package/dist/components/FileStream.js.map +1 -1
  22. package/dist/components/VirtualizedFile.d.ts +33 -0
  23. package/dist/components/VirtualizedFile.d.ts.map +1 -0
  24. package/dist/components/VirtualizedFile.js +227 -0
  25. package/dist/components/VirtualizedFile.js.map +1 -0
  26. package/dist/components/VirtualizedFileDiff.d.ts +39 -0
  27. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -0
  28. package/dist/components/VirtualizedFileDiff.js +316 -0
  29. package/dist/components/VirtualizedFileDiff.js.map +1 -0
  30. package/dist/components/Virtualizer.d.ts +63 -0
  31. package/dist/components/Virtualizer.d.ts.map +1 -0
  32. package/dist/components/Virtualizer.js +369 -0
  33. package/dist/components/Virtualizer.js.map +1 -0
  34. package/dist/components/VirtulizerDevelopment.d.ts +14 -0
  35. package/dist/components/VirtulizerDevelopment.d.ts.map +1 -0
  36. package/dist/components/web-components.d.ts +1 -1
  37. package/dist/components/web-components.d.ts.map +1 -1
  38. package/dist/constants.d.ts +6 -8
  39. package/dist/constants.d.ts.map +1 -1
  40. package/dist/constants.js +16 -7
  41. package/dist/constants.js.map +1 -1
  42. package/dist/highlighter/languages/areLanguagesAttached.d.ts.map +1 -1
  43. package/dist/highlighter/languages/attachResolvedLanguages.d.ts.map +1 -1
  44. package/dist/highlighter/languages/cleanUpResolvedLanguages.d.ts.map +1 -1
  45. package/dist/highlighter/languages/constants.d.ts +3 -1
  46. package/dist/highlighter/languages/constants.d.ts.map +1 -1
  47. package/dist/highlighter/languages/constants.js +2 -1
  48. package/dist/highlighter/languages/constants.js.map +1 -1
  49. package/dist/highlighter/languages/getResolvedLanguages.d.ts.map +1 -1
  50. package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts +1 -1
  51. package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts.map +1 -1
  52. package/dist/highlighter/languages/hasResolvedLanguages.d.ts.map +1 -1
  53. package/dist/highlighter/languages/registerCustomLanguage.d.ts +19 -0
  54. package/dist/highlighter/languages/registerCustomLanguage.d.ts.map +1 -0
  55. package/dist/highlighter/languages/registerCustomLanguage.js +21 -0
  56. package/dist/highlighter/languages/registerCustomLanguage.js.map +1 -0
  57. package/dist/highlighter/languages/resolveLanguage.d.ts +1 -1
  58. package/dist/highlighter/languages/resolveLanguage.d.ts.map +1 -1
  59. package/dist/highlighter/languages/resolveLanguage.js +4 -3
  60. package/dist/highlighter/languages/resolveLanguage.js.map +1 -1
  61. package/dist/highlighter/languages/resolveLanguages.d.ts.map +1 -1
  62. package/dist/highlighter/shared_highlighter.d.ts +4 -2
  63. package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
  64. package/dist/highlighter/shared_highlighter.js +3 -3
  65. package/dist/highlighter/shared_highlighter.js.map +1 -1
  66. package/dist/highlighter/themes/areThemesAttached.d.ts.map +1 -1
  67. package/dist/highlighter/themes/attachResolvedThemes.d.ts.map +1 -1
  68. package/dist/highlighter/themes/cleanUpResolvedThemes.d.ts.map +1 -1
  69. package/dist/highlighter/themes/constants.d.ts.map +1 -1
  70. package/dist/highlighter/themes/getResolvedOrResolveTheme.d.ts.map +1 -1
  71. package/dist/highlighter/themes/getResolvedThemes.d.ts.map +1 -1
  72. package/dist/highlighter/themes/hasResolvedThemes.d.ts.map +1 -1
  73. package/dist/highlighter/themes/registerCustomCSSVariableTheme.d.ts.map +1 -1
  74. package/dist/highlighter/themes/registerCustomTheme.d.ts.map +1 -1
  75. package/dist/highlighter/themes/resolveTheme.d.ts.map +1 -1
  76. package/dist/highlighter/themes/resolveThemes.d.ts.map +1 -1
  77. package/dist/index.d.ts +17 -12
  78. package/dist/index.js +14 -9
  79. package/dist/managers/LineSelectionManager.d.ts +14 -15
  80. package/dist/managers/LineSelectionManager.d.ts.map +1 -1
  81. package/dist/managers/LineSelectionManager.js +60 -71
  82. package/dist/managers/LineSelectionManager.js.map +1 -1
  83. package/dist/managers/MouseEventManager.d.ts +13 -6
  84. package/dist/managers/MouseEventManager.d.ts.map +1 -1
  85. package/dist/managers/MouseEventManager.js +161 -47
  86. package/dist/managers/MouseEventManager.js.map +1 -1
  87. package/dist/managers/ResizeManager.d.ts +6 -1
  88. package/dist/managers/ResizeManager.d.ts.map +1 -1
  89. package/dist/managers/ResizeManager.js +114 -64
  90. package/dist/managers/ResizeManager.js.map +1 -1
  91. package/dist/managers/ScrollSyncManager.d.ts.map +1 -1
  92. package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
  93. package/dist/react/File.d.ts +1 -0
  94. package/dist/react/File.d.ts.map +1 -1
  95. package/dist/react/File.js +2 -1
  96. package/dist/react/File.js.map +1 -1
  97. package/dist/react/FileDiff.d.ts +1 -0
  98. package/dist/react/FileDiff.d.ts.map +1 -1
  99. package/dist/react/FileDiff.js +2 -1
  100. package/dist/react/FileDiff.js.map +1 -1
  101. package/dist/react/MultiFileDiff.d.ts +1 -0
  102. package/dist/react/MultiFileDiff.d.ts.map +1 -1
  103. package/dist/react/MultiFileDiff.js +2 -1
  104. package/dist/react/MultiFileDiff.js.map +1 -1
  105. package/dist/react/PatchDiff.d.ts +1 -0
  106. package/dist/react/PatchDiff.d.ts.map +1 -1
  107. package/dist/react/PatchDiff.js +3 -2
  108. package/dist/react/PatchDiff.js.map +1 -1
  109. package/dist/react/Virtualizer.d.ts +25 -0
  110. package/dist/react/Virtualizer.d.ts.map +1 -0
  111. package/dist/react/Virtualizer.js +38 -0
  112. package/dist/react/Virtualizer.js.map +1 -0
  113. package/dist/react/WorkerPoolContext.d.ts.map +1 -1
  114. package/dist/react/WorkerPoolContext.js +1 -1
  115. package/dist/react/WorkerPoolContext.js.map +1 -1
  116. package/dist/react/constants.d.ts.map +1 -1
  117. package/dist/react/index.d.ts +3 -2
  118. package/dist/react/index.js +2 -1
  119. package/dist/react/jsx.d.ts.map +1 -1
  120. package/dist/react/types.d.ts +5 -3
  121. package/dist/react/types.d.ts.map +1 -1
  122. package/dist/react/utils/renderDiffChildren.d.ts +5 -5
  123. package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
  124. package/dist/react/utils/renderFileChildren.d.ts +5 -5
  125. package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
  126. package/dist/react/utils/templateRender.d.ts.map +1 -1
  127. package/dist/react/utils/useFileDiffInstance.d.ts +5 -3
  128. package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
  129. package/dist/react/utils/useFileDiffInstance.js +6 -2
  130. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  131. package/dist/react/utils/useFileInstance.d.ts +5 -3
  132. package/dist/react/utils/useFileInstance.d.ts.map +1 -1
  133. package/dist/react/utils/useFileInstance.js +6 -2
  134. package/dist/react/utils/useFileInstance.js.map +1 -1
  135. package/dist/react/utils/useStableCallback.d.ts.map +1 -1
  136. package/dist/react/utils/useStableCallback.js.map +1 -1
  137. package/dist/renderers/DiffHunksRenderer.d.ts +15 -10
  138. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  139. package/dist/renderers/DiffHunksRenderer.js +249 -140
  140. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  141. package/dist/renderers/FileRenderer.d.ts +12 -5
  142. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  143. package/dist/renderers/FileRenderer.js +90 -31
  144. package/dist/renderers/FileRenderer.js.map +1 -1
  145. package/dist/shiki-stream/stream.d.ts +3 -3
  146. package/dist/shiki-stream/stream.d.ts.map +1 -1
  147. package/dist/shiki-stream/stream.js.map +1 -1
  148. package/dist/shiki-stream/tokenizer.d.ts +3 -3
  149. package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
  150. package/dist/shiki-stream/tokenizer.js.map +1 -1
  151. package/dist/shiki-stream/types.d.ts +19 -19
  152. package/dist/shiki-stream/types.d.ts.map +1 -1
  153. package/dist/sprite.d.ts +1 -1
  154. package/dist/sprite.d.ts.map +1 -1
  155. package/dist/ssr/FileDiffReact.d.ts.map +1 -1
  156. package/dist/ssr/FileDiffReact.js +1 -1
  157. package/dist/ssr/index.d.ts +2 -2
  158. package/dist/ssr/preloadDiffs.d.ts.map +1 -1
  159. package/dist/ssr/preloadFile.d.ts.map +1 -1
  160. package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
  161. package/dist/ssr/preloadPatchFile.js.map +1 -1
  162. package/dist/ssr/renderHTML.d.ts.map +1 -1
  163. package/dist/style.js +1 -1
  164. package/dist/style.js.map +1 -1
  165. package/dist/types.d.ts +200 -165
  166. package/dist/types.d.ts.map +1 -1
  167. package/dist/utils/areDiffLineAnnotationsEqual.d.ts.map +1 -1
  168. package/dist/utils/areDiffLineAnnotationsEqual.js.map +1 -1
  169. package/dist/utils/areFilesEqual.d.ts.map +1 -1
  170. package/dist/utils/areHunkDataEqual.d.ts.map +1 -1
  171. package/dist/utils/areLineAnnotationsEqual.d.ts.map +1 -1
  172. package/dist/utils/areObjectsEqual.d.ts.map +1 -1
  173. package/dist/utils/areOptionsEqual.d.ts +1 -1
  174. package/dist/utils/areOptionsEqual.d.ts.map +1 -1
  175. package/dist/utils/arePrePropertiesEqual.d.ts.map +1 -1
  176. package/dist/utils/arePrePropertiesEqual.js +1 -1
  177. package/dist/utils/arePrePropertiesEqual.js.map +1 -1
  178. package/dist/utils/areRenderRangesEqual.d.ts.map +1 -1
  179. package/dist/utils/areSelectionsEqual.d.ts.map +1 -1
  180. package/dist/utils/areThemesEqual.d.ts.map +1 -1
  181. package/dist/utils/areVirtualWindowSpecsEqual.d.ts.map +1 -1
  182. package/dist/utils/areWorkerStatsEqual.d.ts.map +1 -1
  183. package/dist/utils/cleanLastNewline.d.ts.map +1 -1
  184. package/dist/utils/createAnnotationElement.d.ts.map +1 -1
  185. package/dist/utils/createAnnotationWrapperNode.d.ts.map +1 -1
  186. package/dist/utils/createContentColumn.d.ts +7 -0
  187. package/dist/utils/createContentColumn.d.ts.map +1 -0
  188. package/dist/utils/createContentColumn.js +17 -0
  189. package/dist/utils/createContentColumn.js.map +1 -0
  190. package/dist/utils/createEmptyRowBuffer.d.ts.map +1 -1
  191. package/dist/utils/createEmptyRowBuffer.js +2 -1
  192. package/dist/utils/createEmptyRowBuffer.js.map +1 -1
  193. package/dist/utils/createFileHeaderElement.d.ts.map +1 -1
  194. package/dist/utils/createHoverContentNode.d.ts.map +1 -1
  195. package/dist/utils/createNoNewlineElement.d.ts +2 -1
  196. package/dist/utils/createNoNewlineElement.d.ts.map +1 -1
  197. package/dist/utils/createNoNewlineElement.js +3 -6
  198. package/dist/utils/createNoNewlineElement.js.map +1 -1
  199. package/dist/utils/createPreElement.d.ts +2 -1
  200. package/dist/utils/createPreElement.d.ts.map +1 -1
  201. package/dist/utils/createPreElement.js +4 -3
  202. package/dist/utils/createPreElement.js.map +1 -1
  203. package/dist/utils/createRowNodes.d.ts.map +1 -1
  204. package/dist/utils/createSeparator.d.ts.map +1 -1
  205. package/dist/utils/createSeparator.js +2 -2
  206. package/dist/utils/createSeparator.js.map +1 -1
  207. package/dist/utils/createSpanNodeFromToken.d.ts.map +1 -1
  208. package/dist/utils/createSpanNodeFromToken.js.map +1 -1
  209. package/dist/utils/createStyleElement.d.ts.map +1 -1
  210. package/dist/utils/createTransformerWithState.d.ts.map +1 -1
  211. package/dist/utils/createUnsafeCSSStyleNode.d.ts.map +1 -1
  212. package/dist/utils/createWindowFromScrollPosition.d.ts.map +1 -1
  213. package/dist/utils/cssWrappers.d.ts.map +1 -1
  214. package/dist/utils/diffAcceptRejectHunk.d.ts +1 -1
  215. package/dist/utils/diffAcceptRejectHunk.d.ts.map +1 -1
  216. package/dist/utils/formatCSSVariablePrefix.d.ts +1 -1
  217. package/dist/utils/formatCSSVariablePrefix.d.ts.map +1 -1
  218. package/dist/utils/getFiletypeFromFileName.d.ts +2 -1
  219. package/dist/utils/getFiletypeFromFileName.d.ts.map +1 -1
  220. package/dist/utils/getFiletypeFromFileName.js +14 -4
  221. package/dist/utils/getFiletypeFromFileName.js.map +1 -1
  222. package/dist/utils/getHighlighterOptions.d.ts +7 -2
  223. package/dist/utils/getHighlighterOptions.d.ts.map +1 -1
  224. package/dist/utils/getHighlighterOptions.js +3 -2
  225. package/dist/utils/getHighlighterOptions.js.map +1 -1
  226. package/dist/utils/getHighlighterThemeStyles.d.ts.map +1 -1
  227. package/dist/utils/getHunkSeparatorSlotName.d.ts +3 -1
  228. package/dist/utils/getHunkSeparatorSlotName.d.ts.map +1 -1
  229. package/dist/utils/getHunkSeparatorSlotName.js.map +1 -1
  230. package/dist/utils/getIconForType.d.ts +1 -1
  231. package/dist/utils/getIconForType.d.ts.map +1 -1
  232. package/dist/utils/getLineAnnotationName.d.ts.map +1 -1
  233. package/dist/utils/getLineEndingType.d.ts +1 -1
  234. package/dist/utils/getLineEndingType.d.ts.map +1 -1
  235. package/dist/utils/getLineNodes.d.ts.map +1 -1
  236. package/dist/utils/getOrCreateCodeNode.d.ts +4 -2
  237. package/dist/utils/getOrCreateCodeNode.d.ts.map +1 -1
  238. package/dist/utils/getOrCreateCodeNode.js +9 -6
  239. package/dist/utils/getOrCreateCodeNode.js.map +1 -1
  240. package/dist/utils/getSingularPatch.d.ts.map +1 -1
  241. package/dist/utils/getThemes.d.ts.map +1 -1
  242. package/dist/utils/getTotalLineCountFromHunks.d.ts.map +1 -1
  243. package/dist/utils/hast_utils.d.ts +6 -3
  244. package/dist/utils/hast_utils.d.ts.map +1 -1
  245. package/dist/utils/hast_utils.js +28 -4
  246. package/dist/utils/hast_utils.js.map +1 -1
  247. package/dist/utils/isDefaultRenderRange.d.ts.map +1 -1
  248. package/dist/utils/isWorkerContext.d.ts.map +1 -1
  249. package/dist/utils/iterateOverDiff.d.ts +28 -13
  250. package/dist/utils/iterateOverDiff.d.ts.map +1 -1
  251. package/dist/utils/iterateOverDiff.js +101 -60
  252. package/dist/utils/iterateOverDiff.js.map +1 -1
  253. package/dist/utils/iterateOverFile.d.ts +50 -0
  254. package/dist/utils/iterateOverFile.d.ts.map +1 -0
  255. package/dist/utils/iterateOverFile.js +49 -0
  256. package/dist/utils/iterateOverFile.js.map +1 -0
  257. package/dist/utils/parseDiffDecorations.d.ts.map +1 -1
  258. package/dist/utils/parseDiffFromFile.d.ts +6 -6
  259. package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
  260. package/dist/utils/parseDiffFromFile.js +3 -2
  261. package/dist/utils/parseDiffFromFile.js.map +1 -1
  262. package/dist/utils/parseLineType.d.ts +1 -1
  263. package/dist/utils/parseLineType.d.ts.map +1 -1
  264. package/dist/utils/parsePatchFiles.d.ts +12 -10
  265. package/dist/utils/parsePatchFiles.d.ts.map +1 -1
  266. package/dist/utils/parsePatchFiles.js +20 -11
  267. package/dist/utils/parsePatchFiles.js.map +1 -1
  268. package/dist/utils/prerenderHTMLIfNecessary.d.ts.map +1 -1
  269. package/dist/utils/processLine.d.ts.map +1 -1
  270. package/dist/utils/processLine.js +7 -24
  271. package/dist/utils/processLine.js.map +1 -1
  272. package/dist/utils/renderDiffWithHighlighter.d.ts +4 -3
  273. package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
  274. package/dist/utils/renderDiffWithHighlighter.js +18 -16
  275. package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
  276. package/dist/utils/renderFileWithHighlighter.d.ts +7 -2
  277. package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
  278. package/dist/utils/renderFileWithHighlighter.js +30 -4
  279. package/dist/utils/renderFileWithHighlighter.js.map +1 -1
  280. package/dist/utils/resolveVirtualFileMetrics.d.ts +7 -0
  281. package/dist/utils/resolveVirtualFileMetrics.d.ts.map +1 -0
  282. package/dist/utils/resolveVirtualFileMetrics.js +25 -0
  283. package/dist/utils/resolveVirtualFileMetrics.js.map +1 -0
  284. package/dist/utils/setLanguageOverride.d.ts +2 -1
  285. package/dist/utils/setLanguageOverride.d.ts.map +1 -1
  286. package/dist/utils/setLanguageOverride.js.map +1 -1
  287. package/dist/utils/setWrapperNodeProps.d.ts +1 -0
  288. package/dist/utils/setWrapperNodeProps.d.ts.map +1 -1
  289. package/dist/utils/setWrapperNodeProps.js +19 -12
  290. package/dist/utils/setWrapperNodeProps.js.map +1 -1
  291. package/dist/utils/splitFileContents.d.ts +12 -0
  292. package/dist/utils/splitFileContents.d.ts.map +1 -0
  293. package/dist/utils/splitFileContents.js +17 -0
  294. package/dist/utils/splitFileContents.js.map +1 -0
  295. package/dist/utils/trimPatchContext.d.ts +11 -0
  296. package/dist/utils/trimPatchContext.d.ts.map +1 -0
  297. package/dist/utils/trimPatchContext.js +99 -0
  298. package/dist/utils/trimPatchContext.js.map +1 -0
  299. package/dist/worker/WorkerPoolManager.d.ts +6 -4
  300. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  301. package/dist/worker/WorkerPoolManager.js +47 -29
  302. package/dist/worker/WorkerPoolManager.js.map +1 -1
  303. package/dist/worker/getOrCreateWorkerPoolSingleton.d.ts.map +1 -1
  304. package/dist/worker/getOrCreateWorkerPoolSingleton.js.map +1 -1
  305. package/dist/worker/types.d.ts +29 -27
  306. package/dist/worker/types.d.ts.map +1 -1
  307. package/dist/worker/wasm-BlUZCxHM.js +10 -0
  308. package/dist/worker/wasm-BlUZCxHM.js.map +1 -0
  309. package/dist/worker/worker-portable.js +10887 -10257
  310. package/dist/worker/worker-portable.js.map +1 -1
  311. package/dist/worker/worker.js +249 -132
  312. package/dist/worker/worker.js.map +1 -1
  313. package/package.json +50 -53
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VirtualizedFileDiff.js","names":["hunkOffsets: number[]","firstVisibleHunk: number | undefined","centerHunk: number | undefined","overflowCounter: number | undefined","lineHeight"],"sources":["../../src/components/VirtualizedFileDiff.ts"],"sourcesContent":["import { DEFAULT_COLLAPSED_CONTEXT_THRESHOLD } from '../constants';\nimport type {\n ExpansionDirections,\n FileDiffMetadata,\n RenderRange,\n RenderWindow,\n VirtualFileMetrics,\n} from '../types';\nimport { iterateOverDiff } from '../utils/iterateOverDiff';\nimport { parseDiffFromFile } from '../utils/parseDiffFromFile';\nimport { resolveVirtualFileMetrics } from '../utils/resolveVirtualFileMetrics';\nimport type { WorkerPoolManager } from '../worker';\nimport {\n FileDiff,\n type FileDiffOptions,\n type FileDiffRenderProps,\n} from './FileDiff';\nimport type { Virtualizer } from './Virtualizer';\n\ninterface ExpandedRegionSpecs {\n fromStart: number;\n fromEnd: number;\n collapsedLines: number;\n renderAll: boolean;\n}\n\nlet instanceId = -1;\n\nexport class VirtualizedFileDiff<\n LAnnotation = undefined,\n> extends FileDiff<LAnnotation> {\n override readonly __id: string = `little-virtualized-file-diff:${++instanceId}`;\n\n public top: number | undefined;\n public height: number = 0;\n private metrics: VirtualFileMetrics;\n // Sparse map: view-specific line index -> measured height\n // Only stores lines that differ what is returned from `getLineHeight`\n private heightCache: Map<number, number> = new Map();\n private isVisible: boolean = false;\n private virtualizer: Virtualizer;\n\n constructor(\n options: FileDiffOptions<LAnnotation> | undefined,\n virtualizer: Virtualizer,\n metrics?: Partial<VirtualFileMetrics>,\n workerManager?: WorkerPoolManager,\n isContainerManaged = false\n ) {\n super(options, workerManager, isContainerManaged);\n const { hunkSeparators = 'line-info' } = this.options;\n this.virtualizer = virtualizer;\n this.metrics = resolveVirtualFileMetrics(\n typeof hunkSeparators === 'function' ? 'custom' : hunkSeparators,\n metrics\n );\n }\n\n // Get the height for a line, using cached value if available.\n // If not cached and hasMetadataLine is true, adds lineHeight for the metadata.\n private getLineHeight(lineIndex: number, hasMetadataLine = false): number {\n const cached = this.heightCache.get(lineIndex);\n if (cached != null) {\n return cached;\n }\n const multiplier = hasMetadataLine ? 2 : 1;\n return this.metrics.lineHeight * multiplier;\n }\n\n // Override setOptions to clear height cache when diffStyle changes\n override setOptions(options: FileDiffOptions<LAnnotation> | undefined): void {\n if (options == null) return;\n const previousDiffStyle = this.options.diffStyle;\n const previousOverflow = this.options.overflow;\n\n super.setOptions(options);\n\n if (\n previousDiffStyle !== this.options.diffStyle ||\n previousOverflow !== this.options.overflow\n ) {\n this.heightCache.clear();\n this.computeApproximateSize();\n this.renderRange = undefined;\n }\n this.virtualizer.instanceChanged(this);\n }\n\n // Measure rendered lines and update height cache.\n // Called after render to reconcile estimated vs actual heights.\n // Definitely need to optimize this in cases where there aren't any custom\n // line heights or in cases of extremely large files...\n public reconcileHeights(): void {\n const { overflow = 'scroll' } = this.options;\n if (this.fileContainer != null) {\n this.top = this.virtualizer.getOffsetInScrollContainer(\n this.fileContainer\n );\n }\n if (this.fileContainer == null || this.fileDiff == null) {\n this.height = 0;\n return;\n }\n // NOTE(amadeus): We can probably be a lot smarter about this, and we\n // should be thinking about ways to improve this\n // If the file has no annotations and we are using the scroll variant, then\n // we can probably skip everything\n if (\n overflow === 'scroll' &&\n this.lineAnnotations.length === 0 &&\n !this.virtualizer.config.resizeDebugging\n ) {\n return;\n }\n const diffStyle = this.getDiffStyle();\n let hasLineHeightChange = false;\n const codeGroups =\n diffStyle === 'split'\n ? [this.codeDeletions, this.codeAdditions]\n : [this.codeUnified];\n\n for (const codeGroup of codeGroups) {\n if (codeGroup == null) continue;\n const content = codeGroup.children[1];\n if (!(content instanceof HTMLElement)) continue;\n for (const line of content.children) {\n if (!(line instanceof HTMLElement)) continue;\n\n const lineIndexAttr = line.dataset.lineIndex;\n if (lineIndexAttr == null) continue;\n\n const lineIndex = parseLineIndex(lineIndexAttr, diffStyle);\n let measuredHeight = line.getBoundingClientRect().height;\n let hasMetadata = false;\n // Annotations or noNewline metadata increase the size of the their\n // attached line\n if (\n line.nextElementSibling instanceof HTMLElement &&\n ('lineAnnotation' in line.nextElementSibling.dataset ||\n 'noNewline' in line.nextElementSibling.dataset)\n ) {\n if ('noNewline' in line.nextElementSibling.dataset) {\n hasMetadata = true;\n }\n measuredHeight +=\n line.nextElementSibling.getBoundingClientRect().height;\n }\n const expectedHeight = this.getLineHeight(lineIndex, hasMetadata);\n\n if (measuredHeight === expectedHeight) {\n continue;\n }\n\n hasLineHeightChange = true;\n // Line is back to standard height (e.g., after window resize)\n // Remove from cache\n if (\n measuredHeight ===\n this.metrics.lineHeight * (hasMetadata ? 2 : 1)\n ) {\n this.heightCache.delete(lineIndex);\n }\n // Non-standard height, cache it\n else {\n this.heightCache.set(lineIndex, measuredHeight);\n }\n }\n }\n\n if (hasLineHeightChange || this.virtualizer.config.resizeDebugging) {\n this.computeApproximateSize();\n }\n }\n\n public onRender = (dirty: boolean): boolean => {\n if (this.fileContainer == null) {\n return false;\n }\n if (dirty) {\n this.top = this.virtualizer.getOffsetInScrollContainer(\n this.fileContainer\n );\n }\n return this.render();\n };\n\n override cleanUp(): void {\n if (this.fileContainer != null) {\n this.virtualizer.disconnect(this.fileContainer);\n }\n super.cleanUp();\n }\n\n override expandHunk(hunkIndex: number, direction: ExpansionDirections): void {\n this.hunksRenderer.expandHunk(hunkIndex, direction);\n this.computeApproximateSize();\n this.renderRange = undefined;\n this.virtualizer.instanceChanged(this);\n // NOTE(amadeus): We should probably defer to the virtualizer to re-render\n // this.rerender();\n }\n\n public setVisibility(visible: boolean): void {\n if (this.fileContainer == null) {\n return;\n }\n if (visible && !this.isVisible) {\n this.top = this.virtualizer.getOffsetInScrollContainer(\n this.fileContainer\n );\n this.isVisible = true;\n } else if (!visible && this.isVisible) {\n this.isVisible = false;\n this.rerender();\n }\n }\n\n // Compute the approximate size of the file using cached line heights.\n // Uses lineHeight for lines without cached measurements.\n // We should probably optimize this if there are no custom line heights...\n // The reason we refer to this as `approximate size` is because heights my\n // dynamically change for a number of reasons so we can never be fully sure\n // if the height is 100% accurate\n private computeApproximateSize(): void {\n this.height = 0;\n if (this.fileDiff == null) {\n return;\n }\n\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n hunkSeparators = 'line-info',\n } = this.options;\n const { diffHeaderHeight, fileGap, hunkSeparatorHeight } = this.metrics;\n const diffStyle = this.getDiffStyle();\n const separatorGap =\n hunkSeparators !== 'simple' &&\n hunkSeparators !== 'metadata' &&\n hunkSeparators !== 'line-info-basic'\n ? fileGap\n : 0;\n\n // Header or initial padding\n if (!disableFileHeader) {\n this.height += diffHeaderHeight;\n } else if (hunkSeparators !== 'simple' && hunkSeparators !== 'metadata') {\n this.height += fileGap;\n }\n\n iterateOverDiff({\n diff: this.fileDiff,\n diffStyle,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const splitLineIndex =\n additionLine != null\n ? additionLine.splitLineIndex\n : deletionLine.splitLineIndex;\n const unifiedLineIndex =\n additionLine != null\n ? additionLine.unifiedLineIndex\n : deletionLine.unifiedLineIndex;\n const hasMetadata =\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);\n if (collapsedBefore > 0) {\n if (hunkIndex > 0) {\n this.height += separatorGap;\n }\n this.height += hunkSeparatorHeight + separatorGap;\n }\n\n this.height += this.getLineHeight(\n diffStyle === 'split' ? splitLineIndex : unifiedLineIndex,\n hasMetadata\n );\n\n if (collapsedAfter > 0 && hunkSeparators !== 'simple') {\n this.height += separatorGap + hunkSeparatorHeight;\n }\n },\n });\n\n // Bottom padding\n if (this.fileDiff.hunks.length > 0) {\n this.height += fileGap;\n }\n\n if (this.fileContainer != null && this.virtualizer.config.resizeDebugging) {\n const rect = this.fileContainer.getBoundingClientRect();\n if (rect.height !== this.height) {\n console.log(\n 'VirtualizedFileDiff.computeApproximateSize: computed height doesnt match',\n {\n name: this.fileDiff.name,\n elementHeight: rect.height,\n computedHeight: this.height,\n }\n );\n } else {\n console.log(\n 'VirtualizedFileDiff.computeApproximateSize: computed height IS CORRECT'\n );\n }\n }\n }\n\n override render({\n fileContainer,\n oldFile,\n newFile,\n fileDiff,\n ...props\n }: FileDiffRenderProps<LAnnotation> = {}): boolean {\n // NOTE(amadeus): Probably not the safest way to determine first render...\n // but for now...\n const isFirstRender = this.fileContainer == null;\n\n this.fileDiff ??=\n fileDiff ??\n (oldFile != null && newFile != null\n ? // NOTE(amadeus): We might be forcing ourselves to double up the\n // computation of fileDiff (in the super.render() call), so we might want\n // to figure out a way to avoid that. That also could be just as simple as\n // passing through fileDiff though... so maybe we good?\n parseDiffFromFile(oldFile, newFile)\n : undefined);\n\n fileContainer = this.getOrCreateFileContainer(fileContainer);\n\n if (this.fileDiff == null) {\n console.error(\n 'VirtualizedFileDiff.render: attempting to virtually render when we dont have the correct data'\n );\n return false;\n }\n\n this.top ??= this.virtualizer.getOffsetInScrollContainer(fileContainer);\n if (isFirstRender) {\n this.computeApproximateSize();\n // Figure out how to properly manage this...\n this.virtualizer.connect(fileContainer, this);\n this.isVisible = this.virtualizer.isInstanceVisible(\n this.top,\n this.height\n );\n }\n\n if (!this.isVisible) {\n return this.renderPlaceholder(this.height);\n }\n\n const windowSpecs = this.virtualizer.getWindowSpecs();\n const renderRange = this.computeRenderRangeFromWindow(\n this.fileDiff,\n this.top,\n windowSpecs\n );\n return super.render({\n fileDiff: this.fileDiff,\n fileContainer,\n renderRange,\n oldFile,\n newFile,\n ...props,\n });\n }\n\n private getDiffStyle(): 'split' | 'unified' {\n return this.options.diffStyle ?? 'split';\n }\n\n private getExpandedRegion(\n isPartial: boolean,\n hunkIndex: number,\n rangeSize: number\n ): ExpandedRegionSpecs {\n if (rangeSize <= 0 || isPartial) {\n return {\n fromStart: 0,\n fromEnd: 0,\n collapsedLines: Math.max(rangeSize, 0),\n renderAll: false,\n };\n }\n const {\n expandUnchanged = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n } = this.options;\n if (expandUnchanged || rangeSize <= collapsedContextThreshold) {\n return {\n fromStart: rangeSize,\n fromEnd: 0,\n collapsedLines: 0,\n renderAll: true,\n };\n }\n const region = this.hunksRenderer.getExpandedHunk(hunkIndex);\n const fromStart = Math.min(Math.max(region.fromStart, 0), rangeSize);\n const fromEnd = Math.min(Math.max(region.fromEnd, 0), rangeSize);\n const expandedCount = fromStart + fromEnd;\n const renderAll = expandedCount >= rangeSize;\n return {\n fromStart,\n fromEnd,\n collapsedLines: Math.max(rangeSize - expandedCount, 0),\n renderAll,\n };\n }\n\n private getExpandedLineCount(\n fileDiff: FileDiffMetadata,\n diffStyle: 'split' | 'unified'\n ): number {\n let count = 0;\n if (fileDiff.isPartial) {\n for (const hunk of fileDiff.hunks) {\n count +=\n diffStyle === 'split' ? hunk.splitLineCount : hunk.unifiedLineCount;\n }\n return count;\n }\n\n for (const [hunkIndex, hunk] of fileDiff.hunks.entries()) {\n const hunkCount =\n diffStyle === 'split' ? hunk.splitLineCount : hunk.unifiedLineCount;\n count += hunkCount;\n const collapsedBefore = Math.max(hunk.collapsedBefore, 0);\n const { fromStart, fromEnd, renderAll } = this.getExpandedRegion(\n fileDiff.isPartial,\n hunkIndex,\n collapsedBefore\n );\n if (collapsedBefore > 0) {\n count += renderAll ? collapsedBefore : fromStart + fromEnd;\n }\n }\n\n const lastHunk = fileDiff.hunks.at(-1);\n if (lastHunk != null && hasFinalHunk(fileDiff)) {\n const additionRemaining =\n fileDiff.additionLines.length -\n (lastHunk.additionLineIndex + lastHunk.additionCount);\n const deletionRemaining =\n fileDiff.deletionLines.length -\n (lastHunk.deletionLineIndex + lastHunk.deletionCount);\n if (lastHunk != null && additionRemaining !== deletionRemaining) {\n throw new Error(\n `VirtualizedFileDiff: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${fileDiff.name}`\n );\n }\n const trailingRangeSize = Math.min(additionRemaining, deletionRemaining);\n if (lastHunk != null && trailingRangeSize > 0) {\n const { fromStart, renderAll } = this.getExpandedRegion(\n fileDiff.isPartial,\n fileDiff.hunks.length,\n trailingRangeSize\n );\n count += renderAll ? trailingRangeSize : fromStart;\n }\n }\n\n return count;\n }\n\n private computeRenderRangeFromWindow(\n fileDiff: FileDiffMetadata,\n fileTop: number,\n { top, bottom }: RenderWindow\n ): RenderRange {\n const {\n disableFileHeader = false,\n expandUnchanged = false,\n collapsedContextThreshold = DEFAULT_COLLAPSED_CONTEXT_THRESHOLD,\n hunkSeparators = 'line-info',\n } = this.options;\n const {\n diffHeaderHeight,\n fileGap,\n hunkLineCount,\n hunkSeparatorHeight,\n lineHeight,\n } = this.metrics;\n const diffStyle = this.getDiffStyle();\n const fileHeight = this.height;\n const lineCount = this.getExpandedLineCount(fileDiff, diffStyle);\n\n // Calculate headerRegion before early returns\n const headerRegion = disableFileHeader ? fileGap : diffHeaderHeight;\n\n // File is outside render window\n if (fileTop < top - fileHeight || fileTop > bottom) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter:\n fileHeight -\n headerRegion -\n // This last file gap represents the bottom padding that buffers\n // should not account for\n fileGap,\n };\n }\n\n // Whole file is under hunkLineCount, just render it all\n if (lineCount <= hunkLineCount || fileDiff.hunks.length === 0) {\n return {\n startingLine: 0,\n totalLines: hunkLineCount,\n bufferBefore: 0,\n bufferAfter: 0,\n };\n }\n const estimatedTargetLines = Math.ceil(\n Math.max(bottom - top, 0) / lineHeight\n );\n const totalLines =\n Math.ceil(estimatedTargetLines / hunkLineCount) * hunkLineCount +\n hunkLineCount;\n const totalHunks = totalLines / hunkLineCount;\n const overflowHunks = totalHunks;\n const hunkOffsets: number[] = [];\n // Halfway between top & bottom, represented as an absolute position\n const viewportCenter = (top + bottom) / 2;\n const separatorGap =\n hunkSeparators === 'simple' ||\n hunkSeparators === 'metadata' ||\n hunkSeparators === 'line-info-basic'\n ? 0\n : fileGap;\n\n let absoluteLineTop = fileTop + headerRegion;\n let currentLine = 0;\n let firstVisibleHunk: number | undefined;\n let centerHunk: number | undefined;\n let overflowCounter: number | undefined;\n\n iterateOverDiff({\n diff: fileDiff,\n diffStyle,\n expandedHunks: expandUnchanged\n ? true\n : this.hunksRenderer.getExpandedHunksMap(),\n collapsedContextThreshold,\n callback: ({\n hunkIndex,\n collapsedBefore,\n collapsedAfter,\n deletionLine,\n additionLine,\n }) => {\n const splitLineIndex =\n additionLine != null\n ? additionLine.splitLineIndex\n : deletionLine.splitLineIndex;\n const unifiedLineIndex =\n additionLine != null\n ? additionLine.unifiedLineIndex\n : deletionLine.unifiedLineIndex;\n const hasMetadata =\n (additionLine?.noEOFCR ?? false) || (deletionLine?.noEOFCR ?? false);\n let gapAdjustment =\n collapsedBefore > 0\n ? hunkSeparatorHeight +\n separatorGap +\n (hunkIndex > 0 ? separatorGap : 0)\n : 0;\n if (hunkIndex === 0 && hunkSeparators === 'simple') {\n gapAdjustment = 0;\n }\n\n absoluteLineTop += gapAdjustment;\n\n const isAtHunkBoundary = currentLine % hunkLineCount === 0;\n\n // Track the boundary positional offset at a hunk\n if (isAtHunkBoundary) {\n hunkOffsets.push(\n absoluteLineTop - (fileTop + headerRegion + gapAdjustment)\n );\n\n // Check if we should bail (overflow complete)\n if (overflowCounter != null) {\n if (overflowCounter <= 0) {\n return true;\n }\n overflowCounter--;\n }\n }\n\n const lineHeight = this.getLineHeight(\n diffStyle === 'split' ? splitLineIndex : unifiedLineIndex,\n hasMetadata\n );\n\n const currentHunk = Math.floor(currentLine / hunkLineCount);\n\n // Track visible region\n if (absoluteLineTop > top - lineHeight && absoluteLineTop < bottom) {\n firstVisibleHunk ??= currentHunk;\n }\n\n // Track which hunk contains the viewport center\n // If viewport center is above this line and we haven't set centerHunk yet,\n // this is the first line at or past the center\n if (\n centerHunk == null &&\n absoluteLineTop + lineHeight > viewportCenter\n ) {\n centerHunk = currentHunk;\n }\n\n // Start overflow when we are out of the viewport at a hunk boundary\n if (\n overflowCounter == null &&\n absoluteLineTop >= bottom &&\n isAtHunkBoundary\n ) {\n overflowCounter = overflowHunks;\n }\n\n currentLine++;\n absoluteLineTop += lineHeight;\n\n if (collapsedAfter > 0 && hunkSeparators !== 'simple') {\n absoluteLineTop += hunkSeparatorHeight + separatorGap;\n }\n\n return false;\n },\n });\n\n // No visible lines found\n if (firstVisibleHunk == null) {\n return {\n startingLine: 0,\n totalLines: 0,\n bufferBefore: 0,\n bufferAfter:\n fileHeight -\n headerRegion -\n // We gotta subtract the bottom padding off of the buffer\n fileGap,\n };\n }\n\n // Calculate balanced startingLine centered around the viewport center\n // Fall back to firstVisibleHunk if center wasn't found (e.g., center in a gap)\n const collectedHunks = hunkOffsets.length;\n centerHunk ??= firstVisibleHunk;\n const idealStartHunk = Math.round(centerHunk - totalHunks / 2);\n\n // Clamp startHunk: at the beginning, reduce totalLines; at the end, shift startHunk back\n const maxStartHunk = Math.max(0, collectedHunks - totalHunks);\n const startHunk = Math.max(0, Math.min(idealStartHunk, maxStartHunk));\n const startingLine = startHunk * hunkLineCount;\n\n // If we wanted to start before 0, reduce totalLines by the clamped amount\n const clampedTotalLines =\n idealStartHunk < 0\n ? totalLines + idealStartHunk * hunkLineCount\n : totalLines;\n\n // Use hunkOffsets array for efficient buffer calculations\n const bufferBefore = hunkOffsets[startHunk] ?? 0;\n\n // Calculate bufferAfter using hunkOffset if available, otherwise use cumulative height\n const finalHunkIndex = startHunk + clampedTotalLines / hunkLineCount;\n const bufferAfter =\n finalHunkIndex < hunkOffsets.length\n ? fileHeight -\n headerRegion -\n hunkOffsets[finalHunkIndex] -\n // We gotta subtract the bottom padding off of the buffer\n fileGap\n : // We stopped early, calculate from current position\n fileHeight -\n (absoluteLineTop - fileTop) -\n // We gotta subtract the bottom padding off of the buffer\n fileGap;\n\n return {\n startingLine,\n totalLines: clampedTotalLines,\n bufferBefore,\n bufferAfter,\n };\n }\n}\n\nfunction hasFinalHunk(fileDiff: FileDiffMetadata): boolean {\n const lastHunk = fileDiff.hunks.at(-1);\n if (\n lastHunk == null ||\n fileDiff.isPartial ||\n fileDiff.additionLines.length === 0 ||\n fileDiff.deletionLines.length === 0\n ) {\n return false;\n }\n\n return (\n lastHunk.additionLineIndex + lastHunk.additionCount <\n fileDiff.additionLines.length ||\n lastHunk.deletionLineIndex + lastHunk.deletionCount <\n fileDiff.deletionLines.length\n );\n}\n\n// Extracts the view-specific line index from the data-line-index attribute.\n// Format is \"unifiedIndex,splitIndex\"\nfunction parseLineIndex(\n lineIndexAttr: string,\n diffStyle: 'split' | 'unified'\n): number {\n const [unifiedIndex, splitIndex] = lineIndexAttr.split(',').map(Number);\n return diffStyle === 'split' ? splitIndex : unifiedIndex;\n}\n"],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { VirtualWindowSpecs } from "../types.js";
2
+
3
+ //#region src/components/Virtualizer.d.ts
4
+ interface SubscribedInstance {
5
+ onRender(dirty: boolean): boolean;
6
+ reconcileHeights(): void;
7
+ setVisibility(visible: boolean): void;
8
+ }
9
+ interface VirtualizerConfig {
10
+ overscrollSize: number;
11
+ intersectionObserverMargin: number;
12
+ resizeDebugging: boolean;
13
+ }
14
+ declare class Virtualizer {
15
+ static __STOP: boolean;
16
+ static __lastScrollPosition: number;
17
+ type: string;
18
+ readonly config: VirtualizerConfig;
19
+ private intersectionObserver;
20
+ private scrollTop;
21
+ private height;
22
+ private scrollHeight;
23
+ private windowSpecs;
24
+ private root;
25
+ private resizeObserver;
26
+ private observers;
27
+ private visibleInstances;
28
+ private visibleInstancesDirty;
29
+ private instancesChanged;
30
+ private scrollDirty;
31
+ private heightDirty;
32
+ private scrollHeightDirty;
33
+ private renderedObservers;
34
+ private connectQueue;
35
+ constructor(config?: Partial<VirtualizerConfig>);
36
+ setup(root: HTMLElement | Document, contentContainer?: Element): void;
37
+ instanceChanged(instance: SubscribedInstance): void;
38
+ getWindowSpecs(): VirtualWindowSpecs;
39
+ isInstanceVisible(elementTop: number, elementHeight: number): boolean;
40
+ private handleContainerResize;
41
+ private setupWindow;
42
+ private setupElement;
43
+ cleanUp(): void;
44
+ getOffsetInScrollContainer(element: HTMLElement): number;
45
+ connect(container: HTMLElement, instance: SubscribedInstance): () => void;
46
+ disconnect(container: HTMLElement): void;
47
+ private handleWindowResize;
48
+ private handleWindowScroll;
49
+ private handleElementScroll;
50
+ private computeRenderRangeAndEmit;
51
+ private scrollFix;
52
+ private applyScrollFix;
53
+ private getScrollAnchor;
54
+ private handleIntersectionChange;
55
+ private getScrollTop;
56
+ private getScrollHeight;
57
+ private getHeight;
58
+ private markDOMDirty;
59
+ private getScrollContainerElement;
60
+ }
61
+ //#endregion
62
+ export { Virtualizer, VirtualizerConfig };
63
+ //# sourceMappingURL=Virtualizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Virtualizer.d.ts","names":["VirtualWindowSpecs","SubscribedInstance","VirtualizerConfig","Virtualizer","Partial","HTMLElement","Document","Element"],"sources":["../../src/components/Virtualizer.d.ts"],"sourcesContent":["import type { VirtualWindowSpecs } from '../types';\ninterface SubscribedInstance {\n onRender(dirty: boolean): boolean;\n reconcileHeights(): void;\n setVisibility(visible: boolean): void;\n}\nexport interface VirtualizerConfig {\n overscrollSize: number;\n intersectionObserverMargin: number;\n resizeDebugging: boolean;\n}\nexport declare class Virtualizer {\n static __STOP: boolean;\n static __lastScrollPosition: number;\n type: string;\n readonly config: VirtualizerConfig;\n private intersectionObserver;\n private scrollTop;\n private height;\n private scrollHeight;\n private windowSpecs;\n private root;\n private resizeObserver;\n private observers;\n private visibleInstances;\n private visibleInstancesDirty;\n private instancesChanged;\n private scrollDirty;\n private heightDirty;\n private scrollHeightDirty;\n private renderedObservers;\n private connectQueue;\n constructor(config?: Partial<VirtualizerConfig>);\n setup(root: HTMLElement | Document, contentContainer?: Element): void;\n instanceChanged(instance: SubscribedInstance): void;\n getWindowSpecs(): VirtualWindowSpecs;\n isInstanceVisible(elementTop: number, elementHeight: number): boolean;\n private handleContainerResize;\n private setupWindow;\n private setupElement;\n cleanUp(): void;\n getOffsetInScrollContainer(element: HTMLElement): number;\n connect(container: HTMLElement, instance: SubscribedInstance): () => void;\n disconnect(container: HTMLElement): void;\n private handleWindowResize;\n private handleWindowScroll;\n private handleElementScroll;\n private computeRenderRangeAndEmit;\n private scrollFix;\n private applyScrollFix;\n private getScrollAnchor;\n private handleIntersectionChange;\n private getScrollTop;\n private getScrollHeight;\n private getHeight;\n private markDOMDirty;\n private getScrollContainerElement;\n}\nexport {};\n//# sourceMappingURL=Virtualizer.d.ts.map"],"mappings":";;;UACUC,kBAAAA;;EAAAA,gBAAAA,EAAAA,EAAAA,IAAkB;EAKXC,aAAAA,CAAAA,OAAiB,EAAA,OAAA,CAAA,EAAA,IAAA;AAKlC;AAIqBA,UATJA,iBAAAA,CASIA;EAiBYA,cAAAA,EAAAA,MAAAA;EAARE,0BAAAA,EAAAA,MAAAA;EACTC,eAAAA,EAAAA,OAAAA;;AAA2CE,cAtBtCJ,WAAAA,CAsBsCI;EAC7BN,OAAAA,MAAAA,EAAAA,OAAAA;EACRD,OAAAA,oBAAAA,EAAAA,MAAAA;EAMkBK,IAAAA,EAAAA,MAAAA;EACjBA,SAAAA,MAAAA,EA3BFH,iBA2BEG;EAAuBJ,QAAAA,oBAAAA;EACpBI,QAAAA,SAAAA;EAAW,QAAA,MAAA;;;;;;;;;;;;;;uBAXZD,QAAQF;cACjBG,cAAcC,6BAA6BC;4BAC7BN;oBACRD;;;;;;sCAMkBK;qBACjBA,uBAAuBJ;wBACpBI"}
@@ -0,0 +1,369 @@
1
+ import { queueRender } from "../managers/UniversalRenderingManager.js";
2
+ import { areVirtualWindowSpecsEqual } from "../utils/areVirtualWindowSpecsEqual.js";
3
+ import { createWindowFromScrollPosition } from "../utils/createWindowFromScrollPosition.js";
4
+
5
+ //#region src/components/Virtualizer.ts
6
+ const DEFAULT_OVERSCROLL_SIZE = 1e3;
7
+ const INTERSECTION_OBSERVER_MARGIN = DEFAULT_OVERSCROLL_SIZE * 4;
8
+ const INTERSECTION_OBSERVER_THRESHOLD = [
9
+ 0,
10
+ 1e-6,
11
+ .99999,
12
+ 1
13
+ ];
14
+ const DEFAULT_VIRTUALIZER_CONFIG = {
15
+ overscrollSize: DEFAULT_OVERSCROLL_SIZE,
16
+ intersectionObserverMargin: INTERSECTION_OBSERVER_MARGIN,
17
+ resizeDebugging: false
18
+ };
19
+ let lastSize = 0;
20
+ var Virtualizer = class Virtualizer {
21
+ static __STOP = false;
22
+ static __lastScrollPosition = 0;
23
+ type = "basic";
24
+ config;
25
+ intersectionObserver;
26
+ scrollTop = 0;
27
+ height = 0;
28
+ scrollHeight = 0;
29
+ windowSpecs = {
30
+ top: 0,
31
+ bottom: 0
32
+ };
33
+ root;
34
+ resizeObserver;
35
+ observers = /* @__PURE__ */ new Map();
36
+ visibleInstances = /* @__PURE__ */ new Map();
37
+ visibleInstancesDirty = false;
38
+ instancesChanged = /* @__PURE__ */ new Set();
39
+ scrollDirty = true;
40
+ heightDirty = true;
41
+ scrollHeightDirty = true;
42
+ renderedObservers = 0;
43
+ connectQueue = /* @__PURE__ */ new Map();
44
+ constructor(config) {
45
+ this.config = {
46
+ ...DEFAULT_VIRTUALIZER_CONFIG,
47
+ ...config
48
+ };
49
+ }
50
+ setup(root, contentContainer) {
51
+ if (this.root != null) return;
52
+ this.root = root;
53
+ this.resizeObserver = new ResizeObserver(this.handleContainerResize);
54
+ this.intersectionObserver = new IntersectionObserver(this.handleIntersectionChange, {
55
+ root: this.root,
56
+ threshold: INTERSECTION_OBSERVER_THRESHOLD,
57
+ rootMargin: `${this.config.intersectionObserverMargin}px 0px ${this.config.intersectionObserverMargin}px 0px`
58
+ });
59
+ if (root instanceof Document) this.setupWindow();
60
+ else this.setupElement(contentContainer);
61
+ window.__INSTANCE = this;
62
+ window.__TOGGLE = () => {
63
+ if (Virtualizer.__STOP) {
64
+ Virtualizer.__STOP = false;
65
+ (this.getScrollContainerElement() ?? window).scrollTo({ top: Virtualizer.__lastScrollPosition });
66
+ queueRender(this.computeRenderRangeAndEmit);
67
+ } else {
68
+ Virtualizer.__lastScrollPosition = this.getScrollTop();
69
+ Virtualizer.__STOP = true;
70
+ }
71
+ };
72
+ for (const [container, instance] of this.connectQueue.entries()) this.connect(container, instance);
73
+ this.connectQueue.clear();
74
+ this.markDOMDirty();
75
+ queueRender(this.computeRenderRangeAndEmit);
76
+ }
77
+ instanceChanged(instance) {
78
+ this.instancesChanged.add(instance);
79
+ queueRender(this.computeRenderRangeAndEmit);
80
+ }
81
+ getWindowSpecs() {
82
+ if (this.windowSpecs.top === 0 && this.windowSpecs.bottom === 0) this.windowSpecs = createWindowFromScrollPosition({
83
+ scrollTop: this.getScrollTop(),
84
+ height: this.getHeight(),
85
+ scrollHeight: this.getScrollHeight(),
86
+ fitPerfectly: false,
87
+ overscrollSize: this.config.overscrollSize
88
+ });
89
+ return this.windowSpecs;
90
+ }
91
+ isInstanceVisible(elementTop, elementHeight) {
92
+ const scrollTop = this.getScrollTop();
93
+ const height = this.getHeight();
94
+ const margin = this.config.intersectionObserverMargin;
95
+ const top = scrollTop - margin;
96
+ const bottom = scrollTop + height + margin;
97
+ return !(elementTop < top - elementHeight || elementTop > bottom);
98
+ }
99
+ handleContainerResize = (entries) => {
100
+ if (this.root == null) return;
101
+ let shouldQueueUpdate = false;
102
+ for (const entry of entries) {
103
+ const blockSize = entry.borderBoxSize[0].blockSize;
104
+ if (this.root instanceof Document) {
105
+ if (blockSize !== this.scrollHeight) {
106
+ this.scrollHeightDirty = true;
107
+ shouldQueueUpdate = true;
108
+ if (this.config.resizeDebugging) {
109
+ console.log("Virtualizer: content size change", {
110
+ sizeChange: blockSize - lastSize,
111
+ newSize: blockSize
112
+ });
113
+ lastSize = blockSize;
114
+ }
115
+ }
116
+ } else if (entry.target === this.root) {
117
+ if (blockSize !== this.height) {
118
+ this.heightDirty = true;
119
+ shouldQueueUpdate = true;
120
+ }
121
+ } else if (entry.target === this.root.firstElementChild) {
122
+ this.scrollHeightDirty = true;
123
+ shouldQueueUpdate = true;
124
+ if (this.config.resizeDebugging) {
125
+ console.log("Virtualizer: scroller size change", {
126
+ sizeChange: blockSize - lastSize,
127
+ newSize: blockSize
128
+ });
129
+ lastSize = blockSize;
130
+ }
131
+ }
132
+ }
133
+ if (shouldQueueUpdate) queueRender(this.computeRenderRangeAndEmit);
134
+ };
135
+ setupWindow() {
136
+ if (this.root == null || !(this.root instanceof Document)) throw new Error("Virtualizer.setupWindow: Invalid setup method");
137
+ window.addEventListener("scroll", this.handleWindowScroll, { passive: true });
138
+ window.addEventListener("resize", this.handleWindowResize, { passive: true });
139
+ this.resizeObserver?.observe(this.root.documentElement);
140
+ }
141
+ setupElement(contentContainer) {
142
+ if (this.root == null || this.root instanceof Document) throw new Error("Virtualizer.setupElement: Invalid setup method");
143
+ this.root.addEventListener("scroll", this.handleElementScroll, { passive: true });
144
+ this.resizeObserver?.observe(this.root);
145
+ contentContainer ??= this.root.firstElementChild ?? void 0;
146
+ if (contentContainer != null) this.resizeObserver?.observe(contentContainer);
147
+ }
148
+ cleanUp() {
149
+ this.intersectionObserver?.disconnect();
150
+ this.intersectionObserver = void 0;
151
+ this.root = void 0;
152
+ }
153
+ getOffsetInScrollContainer(element) {
154
+ return this.getScrollTop() + getRelativeBoundingTop(element, this.getScrollContainerElement());
155
+ }
156
+ connect(container, instance) {
157
+ if (this.observers.has(container)) throw new Error("Virtualizer.connect: instance is already connected...");
158
+ if (this.intersectionObserver == null) this.connectQueue.set(container, instance);
159
+ else {
160
+ this.intersectionObserver.observe(container);
161
+ this.observers.set(container, instance);
162
+ this.instancesChanged.add(instance);
163
+ this.markDOMDirty();
164
+ queueRender(this.computeRenderRangeAndEmit);
165
+ }
166
+ return () => this.disconnect(container);
167
+ }
168
+ disconnect(container) {
169
+ const instance = this.observers.get(container);
170
+ this.connectQueue.delete(container);
171
+ if (instance == null) return;
172
+ this.intersectionObserver?.unobserve(container);
173
+ this.observers.delete(container);
174
+ this.markDOMDirty();
175
+ queueRender(this.computeRenderRangeAndEmit);
176
+ }
177
+ handleWindowResize = () => {
178
+ if (Virtualizer.__STOP || window.innerHeight === this.height) return;
179
+ this.heightDirty = true;
180
+ queueRender(this.computeRenderRangeAndEmit);
181
+ };
182
+ handleWindowScroll = () => {
183
+ if (Virtualizer.__STOP || this.root == null || !(this.root instanceof Document)) return;
184
+ this.scrollDirty = true;
185
+ queueRender(this.computeRenderRangeAndEmit);
186
+ };
187
+ handleElementScroll = () => {
188
+ if (Virtualizer.__STOP || this.root == null || this.root instanceof Document) return;
189
+ this.scrollDirty = true;
190
+ queueRender(this.computeRenderRangeAndEmit);
191
+ };
192
+ computeRenderRangeAndEmit = () => {
193
+ if (Virtualizer.__STOP) return;
194
+ const wrapperDirty = this.heightDirty || this.scrollHeightDirty;
195
+ if (!this.scrollDirty && !this.scrollHeightDirty && !this.heightDirty && this.renderedObservers === this.observers.size && !this.visibleInstancesDirty && this.instancesChanged.size === 0) return;
196
+ if (this.instancesChanged.size === 0) {
197
+ const windowSpecs = createWindowFromScrollPosition({
198
+ scrollTop: this.getScrollTop(),
199
+ height: this.getHeight(),
200
+ scrollHeight: this.getScrollHeight(),
201
+ fitPerfectly: false,
202
+ overscrollSize: this.config.overscrollSize
203
+ });
204
+ if (areVirtualWindowSpecsEqual(this.windowSpecs, windowSpecs) && this.renderedObservers === this.observers.size && !this.visibleInstancesDirty && this.instancesChanged.size === 0) return;
205
+ this.windowSpecs = windowSpecs;
206
+ }
207
+ this.visibleInstancesDirty = false;
208
+ this.renderedObservers = this.observers.size;
209
+ const anchor = this.getScrollAnchor(this.height);
210
+ const updatedInstances = /* @__PURE__ */ new Set();
211
+ for (const instance of this.visibleInstances.values()) if (instance.onRender(wrapperDirty)) updatedInstances.add(instance);
212
+ for (const instance of this.instancesChanged) {
213
+ if (updatedInstances.has(instance)) continue;
214
+ if (instance.onRender(wrapperDirty)) updatedInstances.add(instance);
215
+ }
216
+ this.scrollFix(anchor);
217
+ if (this.instancesChanged.size > 0) this.markDOMDirty();
218
+ for (const instance of updatedInstances) instance.reconcileHeights();
219
+ if (this.instancesChanged.size > 0 || wrapperDirty) queueRender(this.computeRenderRangeAndEmit);
220
+ updatedInstances.clear();
221
+ this.instancesChanged.clear();
222
+ };
223
+ scrollFix(anchor) {
224
+ if (anchor == null) return;
225
+ const scrollContainer = this.getScrollContainerElement();
226
+ const { lineIndex, lineOffset, fileElement, fileOffset, fileTypeOffset } = anchor;
227
+ if (lineIndex != null && lineOffset != null) {
228
+ const element = fileElement.shadowRoot?.querySelector(`[data-line][data-line-index="${lineIndex}"]`);
229
+ if (element instanceof HTMLElement) {
230
+ const top$1 = getRelativeBoundingTop(element, scrollContainer);
231
+ if (top$1 !== lineOffset) {
232
+ const scrollOffset = top$1 - lineOffset;
233
+ this.applyScrollFix(scrollOffset);
234
+ }
235
+ return;
236
+ }
237
+ }
238
+ const top = getRelativeBoundingTop(fileElement, scrollContainer);
239
+ if (fileTypeOffset === "top") {
240
+ if (top !== fileOffset) this.applyScrollFix(top - fileOffset);
241
+ } else {
242
+ const bottom = top + fileElement.getBoundingClientRect().height;
243
+ if (bottom !== fileOffset) this.applyScrollFix(bottom - fileOffset);
244
+ }
245
+ }
246
+ applyScrollFix(scrollOffset) {
247
+ if (this.root == null || this.root instanceof Document) window.scrollTo({
248
+ top: window.scrollY + scrollOffset,
249
+ behavior: "instant"
250
+ });
251
+ else this.root.scrollTo({
252
+ top: this.root.scrollTop + scrollOffset,
253
+ behavior: "instant"
254
+ });
255
+ this.markDOMDirty();
256
+ }
257
+ getScrollAnchor(viewportHeight) {
258
+ const scrollContainer = this.getScrollContainerElement();
259
+ let bestAnchor;
260
+ for (const [fileElement] of this.visibleInstances.entries()) {
261
+ const fileTop = getRelativeBoundingTop(fileElement, scrollContainer);
262
+ const fileBottom = fileTop + fileElement.offsetHeight;
263
+ let fileOffset;
264
+ let fileTypeOffset;
265
+ if (fileBottom <= 0) {
266
+ fileOffset = fileBottom;
267
+ fileTypeOffset = "bottom";
268
+ } else {
269
+ fileOffset = fileTop;
270
+ fileTypeOffset = "top";
271
+ }
272
+ let bestLineIndex;
273
+ let bestLineOffset;
274
+ if (fileBottom > 0 && fileTop < viewportHeight) for (const line of fileElement.shadowRoot?.querySelectorAll("[data-line][data-line-index]") ?? []) {
275
+ if (!(line instanceof HTMLElement)) continue;
276
+ const lineIndex = line.dataset.lineIndex;
277
+ if (lineIndex == null) continue;
278
+ const lineOffset = getRelativeBoundingTop(line, scrollContainer);
279
+ if (lineOffset < 0) continue;
280
+ bestLineIndex = lineIndex;
281
+ bestLineOffset = lineOffset;
282
+ break;
283
+ }
284
+ if (bestAnchor?.lineOffset != null && bestLineOffset == null) continue;
285
+ let shouldReplace = false;
286
+ if (bestAnchor == null) shouldReplace = true;
287
+ else if (bestLineOffset != null && (bestAnchor.lineOffset == null || bestLineOffset < bestAnchor.lineOffset)) shouldReplace = true;
288
+ else if (bestLineOffset == null && bestAnchor.lineOffset == null) {
289
+ if (fileOffset >= 0 && (bestAnchor.fileOffset < 0 || fileOffset < bestAnchor.fileOffset)) shouldReplace = true;
290
+ else if (fileOffset < 0 && bestAnchor.fileOffset < 0 && fileOffset > bestAnchor.fileOffset) shouldReplace = true;
291
+ }
292
+ if (shouldReplace) bestAnchor = {
293
+ fileElement,
294
+ fileTypeOffset,
295
+ fileOffset,
296
+ lineIndex: bestLineIndex,
297
+ lineOffset: bestLineOffset
298
+ };
299
+ }
300
+ return bestAnchor;
301
+ }
302
+ handleIntersectionChange = (entries) => {
303
+ this.scrollDirty = true;
304
+ for (const { target, isIntersecting } of entries) {
305
+ if (!(target instanceof HTMLElement)) throw new Error("Virtualizer.handleIntersectionChange: target not an HTMLElement");
306
+ const instance = this.observers.get(target);
307
+ if (instance == null) throw new Error("Virtualizer.handleIntersectionChange: no instance for target");
308
+ if (isIntersecting && !this.visibleInstances.has(target)) {
309
+ instance.setVisibility(true);
310
+ this.visibleInstances.set(target, instance);
311
+ this.visibleInstancesDirty = true;
312
+ } else if (!isIntersecting && this.visibleInstances.has(target)) {
313
+ instance.setVisibility(false);
314
+ this.visibleInstances.delete(target);
315
+ this.visibleInstancesDirty = true;
316
+ }
317
+ }
318
+ if (this.visibleInstancesDirty) queueRender(this.computeRenderRangeAndEmit);
319
+ };
320
+ getScrollTop() {
321
+ if (!this.scrollDirty) return this.scrollTop;
322
+ this.scrollDirty = false;
323
+ let scrollTop = (() => {
324
+ if (this.root == null) return 0;
325
+ if (this.root instanceof Document) return window.scrollY;
326
+ return this.root.scrollTop;
327
+ })();
328
+ scrollTop = Math.max(0, Math.min(scrollTop, this.getScrollHeight() - this.getHeight()));
329
+ this.scrollTop = scrollTop;
330
+ return scrollTop;
331
+ }
332
+ getScrollHeight() {
333
+ if (!this.scrollHeightDirty) return this.scrollHeight;
334
+ this.scrollHeightDirty = false;
335
+ this.scrollHeight = (() => {
336
+ if (this.root == null) return 0;
337
+ if (this.root instanceof Document) return this.root.documentElement.scrollHeight;
338
+ return this.root.scrollHeight;
339
+ })();
340
+ return this.scrollHeight;
341
+ }
342
+ getHeight() {
343
+ if (!this.heightDirty) return this.height;
344
+ this.heightDirty = false;
345
+ this.height = (() => {
346
+ if (this.root == null) return 0;
347
+ if (this.root instanceof Document) return globalThis.innerHeight;
348
+ return this.root.getBoundingClientRect().height;
349
+ })();
350
+ return this.height;
351
+ }
352
+ markDOMDirty() {
353
+ this.scrollDirty = true;
354
+ this.scrollHeightDirty = true;
355
+ this.heightDirty = true;
356
+ }
357
+ getScrollContainerElement() {
358
+ return this.root == null || this.root instanceof Document ? void 0 : this.root;
359
+ }
360
+ };
361
+ function getRelativeBoundingTop(element, scrollContainer) {
362
+ const rect = element.getBoundingClientRect();
363
+ const scrollContainerTop = scrollContainer?.getBoundingClientRect().top ?? 0;
364
+ return rect.top - scrollContainerTop;
365
+ }
366
+
367
+ //#endregion
368
+ export { Virtualizer };
369
+ //# sourceMappingURL=Virtualizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Virtualizer.js","names":["DEFAULT_VIRTUALIZER_CONFIG: VirtualizerConfig","top","bestAnchor: ScrollAnchor | undefined","fileOffset: number","fileTypeOffset: 'top' | 'bottom'","bestLineIndex: string | undefined","bestLineOffset: number | undefined"],"sources":["../../src/components/Virtualizer.ts"],"sourcesContent":["import { queueRender } from '../managers/UniversalRenderingManager';\nimport type { VirtualWindowSpecs } from '../types';\nimport { areVirtualWindowSpecsEqual } from '../utils/areVirtualWindowSpecsEqual';\nimport { createWindowFromScrollPosition } from '../utils/createWindowFromScrollPosition';\n\ninterface SubscribedInstance {\n onRender(dirty: boolean): boolean;\n reconcileHeights(): void;\n setVisibility(visible: boolean): void;\n}\n\ninterface ScrollAnchor {\n fileElement: HTMLElement;\n fileTypeOffset: 'top' | 'bottom';\n fileOffset: number;\n lineIndex: string | undefined;\n lineOffset: number | undefined;\n}\n\n// 800 seems like the healthy overscan required to\n// keep safari from blanking... if we catch it tho, maybe 900\nconst DEFAULT_OVERSCROLL_SIZE = 1000;\nconst INTERSECTION_OBSERVER_MARGIN = DEFAULT_OVERSCROLL_SIZE * 4;\nconst INTERSECTION_OBSERVER_THRESHOLD = [0, 0.000001, 0.99999, 1];\n\nexport interface VirtualizerConfig {\n overscrollSize: number;\n intersectionObserverMargin: number;\n resizeDebugging: boolean;\n}\n\nconst DEFAULT_VIRTUALIZER_CONFIG: VirtualizerConfig = {\n overscrollSize: DEFAULT_OVERSCROLL_SIZE,\n intersectionObserverMargin: INTERSECTION_OBSERVER_MARGIN,\n resizeDebugging: false,\n};\n\nlet lastSize = 0;\n\nexport class Virtualizer {\n static __STOP: boolean = false;\n static __lastScrollPosition = 0;\n\n public type = 'basic';\n public readonly config: VirtualizerConfig;\n private intersectionObserver: IntersectionObserver | undefined;\n private scrollTop: number = 0;\n private height: number = 0;\n private scrollHeight: number = 0;\n private windowSpecs: VirtualWindowSpecs = { top: 0, bottom: 0 };\n private root: HTMLElement | Document | undefined;\n\n private resizeObserver: ResizeObserver | undefined;\n private observers: Map<HTMLElement, SubscribedInstance> = new Map();\n private visibleInstances: Map<HTMLElement, SubscribedInstance> = new Map();\n private visibleInstancesDirty: boolean = false;\n private instancesChanged: Set<SubscribedInstance> = new Set();\n\n private scrollDirty = true;\n private heightDirty = true;\n private scrollHeightDirty = true;\n private renderedObservers = 0;\n private connectQueue: Map<HTMLElement, SubscribedInstance> = new Map();\n\n constructor(config?: Partial<VirtualizerConfig>) {\n this.config = { ...DEFAULT_VIRTUALIZER_CONFIG, ...config };\n }\n\n setup(root: HTMLElement | Document, contentContainer?: Element): void {\n if (this.root != null) {\n return;\n }\n this.root = root;\n this.resizeObserver = new ResizeObserver(this.handleContainerResize);\n this.intersectionObserver = new IntersectionObserver(\n this.handleIntersectionChange,\n {\n root: this.root,\n threshold: INTERSECTION_OBSERVER_THRESHOLD,\n rootMargin: `${this.config.intersectionObserverMargin}px 0px ${this.config.intersectionObserverMargin}px 0px`,\n // FIXME(amadeus): Figure out the other settings we'll want in here, or\n // if we should make them configurable...\n }\n );\n if (root instanceof Document) {\n this.setupWindow();\n } else {\n this.setupElement(contentContainer);\n }\n\n // FIXME(amadeus): Remove me before release\n window.__INSTANCE = this;\n window.__TOGGLE = () => {\n if (Virtualizer.__STOP) {\n Virtualizer.__STOP = false;\n const scroller = this.getScrollContainerElement() ?? window;\n scroller.scrollTo({ top: Virtualizer.__lastScrollPosition });\n queueRender(this.computeRenderRangeAndEmit);\n } else {\n Virtualizer.__lastScrollPosition = this.getScrollTop();\n Virtualizer.__STOP = true;\n }\n };\n for (const [container, instance] of this.connectQueue.entries()) {\n this.connect(container, instance);\n }\n this.connectQueue.clear();\n this.markDOMDirty();\n queueRender(this.computeRenderRangeAndEmit);\n }\n\n instanceChanged(instance: SubscribedInstance): void {\n this.instancesChanged.add(instance);\n queueRender(this.computeRenderRangeAndEmit);\n }\n\n getWindowSpecs(): VirtualWindowSpecs {\n if (this.windowSpecs.top === 0 && this.windowSpecs.bottom === 0) {\n this.windowSpecs = createWindowFromScrollPosition({\n scrollTop: this.getScrollTop(),\n height: this.getHeight(),\n scrollHeight: this.getScrollHeight(),\n fitPerfectly: false,\n overscrollSize: this.config.overscrollSize,\n });\n }\n return this.windowSpecs;\n }\n\n isInstanceVisible(elementTop: number, elementHeight: number): boolean {\n const scrollTop = this.getScrollTop();\n const height = this.getHeight();\n const margin = this.config.intersectionObserverMargin;\n const top = scrollTop - margin;\n const bottom = scrollTop + height + margin;\n return !(elementTop < top - elementHeight || elementTop > bottom);\n }\n\n private handleContainerResize = (entries: ResizeObserverEntry[]) => {\n if (this.root == null) return;\n let shouldQueueUpdate = false;\n for (const entry of entries) {\n const blockSize = entry.borderBoxSize[0].blockSize;\n if (this.root instanceof Document) {\n if (blockSize !== this.scrollHeight) {\n this.scrollHeightDirty = true;\n shouldQueueUpdate = true;\n if (this.config.resizeDebugging) {\n console.log('Virtualizer: content size change', {\n sizeChange: blockSize - lastSize,\n newSize: blockSize,\n });\n lastSize = blockSize;\n }\n }\n } else {\n if (entry.target === this.root) {\n if (blockSize !== this.height) {\n this.heightDirty = true;\n shouldQueueUpdate = true;\n }\n } else if (entry.target === this.root.firstElementChild) {\n this.scrollHeightDirty = true;\n shouldQueueUpdate = true;\n if (this.config.resizeDebugging) {\n console.log('Virtualizer: scroller size change', {\n sizeChange: blockSize - lastSize,\n newSize: blockSize,\n });\n lastSize = blockSize;\n }\n }\n }\n }\n\n if (shouldQueueUpdate) {\n queueRender(this.computeRenderRangeAndEmit);\n }\n };\n\n private setupWindow() {\n if (this.root == null || !(this.root instanceof Document)) {\n throw new Error('Virtualizer.setupWindow: Invalid setup method');\n }\n window.addEventListener('scroll', this.handleWindowScroll, {\n passive: true,\n });\n window.addEventListener('resize', this.handleWindowResize, {\n passive: true,\n });\n this.resizeObserver?.observe(this.root.documentElement);\n }\n\n private setupElement(contentContainer: Element | undefined) {\n if (this.root == null || this.root instanceof Document) {\n throw new Error('Virtualizer.setupElement: Invalid setup method');\n }\n this.root.addEventListener('scroll', this.handleElementScroll, {\n passive: true,\n });\n this.resizeObserver?.observe(this.root);\n contentContainer ??= this.root.firstElementChild ?? undefined;\n if (contentContainer != null) {\n this.resizeObserver?.observe(contentContainer);\n }\n }\n\n cleanUp(): void {\n this.intersectionObserver?.disconnect();\n this.intersectionObserver = undefined;\n this.root = undefined;\n }\n\n getOffsetInScrollContainer(element: HTMLElement): number {\n return (\n this.getScrollTop() +\n getRelativeBoundingTop(element, this.getScrollContainerElement())\n );\n }\n\n connect(container: HTMLElement, instance: SubscribedInstance): () => void {\n if (this.observers.has(container)) {\n throw new Error('Virtualizer.connect: instance is already connected...');\n }\n // If we are racing against the intersectionObserver, then we should just\n // queue up the connection for when the observer does get set up\n if (this.intersectionObserver == null) {\n this.connectQueue.set(container, instance);\n } else {\n // FIXME(amadeus): Go through the connection phase a bit more closely...\n this.intersectionObserver.observe(container);\n this.observers.set(container, instance);\n this.instancesChanged.add(instance);\n this.markDOMDirty();\n queueRender(this.computeRenderRangeAndEmit);\n }\n return () => this.disconnect(container);\n }\n\n disconnect(container: HTMLElement): void {\n const instance = this.observers.get(container);\n this.connectQueue.delete(container);\n if (instance == null) {\n return;\n }\n this.intersectionObserver?.unobserve(container);\n this.observers.delete(container);\n this.markDOMDirty();\n queueRender(this.computeRenderRangeAndEmit);\n }\n\n private handleWindowResize = () => {\n if (Virtualizer.__STOP || window.innerHeight === this.height) {\n return;\n }\n this.heightDirty = true;\n queueRender(this.computeRenderRangeAndEmit);\n };\n\n private handleWindowScroll = () => {\n if (\n Virtualizer.__STOP ||\n this.root == null ||\n !(this.root instanceof Document)\n ) {\n return;\n }\n this.scrollDirty = true;\n queueRender(this.computeRenderRangeAndEmit);\n };\n\n private handleElementScroll = () => {\n if (\n Virtualizer.__STOP ||\n this.root == null ||\n this.root instanceof Document\n ) {\n return;\n }\n this.scrollDirty = true;\n queueRender(this.computeRenderRangeAndEmit);\n };\n\n private computeRenderRangeAndEmit = () => {\n if (Virtualizer.__STOP) {\n return;\n }\n const wrapperDirty = this.heightDirty || this.scrollHeightDirty;\n if (\n !this.scrollDirty &&\n !this.scrollHeightDirty &&\n !this.heightDirty &&\n this.renderedObservers === this.observers.size &&\n !this.visibleInstancesDirty &&\n this.instancesChanged.size === 0\n ) {\n // NOTE(amadeus): Is this a safe assumption/optimization?\n return;\n }\n\n // If we got an emitted update from a bunch of instances, we should skip\n // the window check first and attempt to render with existing logic first\n // and then queue up a corrected render after\n if (this.instancesChanged.size === 0) {\n const windowSpecs = createWindowFromScrollPosition({\n scrollTop: this.getScrollTop(),\n height: this.getHeight(),\n scrollHeight: this.getScrollHeight(),\n fitPerfectly: false,\n overscrollSize: this.config.overscrollSize,\n });\n if (\n areVirtualWindowSpecsEqual(this.windowSpecs, windowSpecs) &&\n this.renderedObservers === this.observers.size &&\n !this.visibleInstancesDirty &&\n this.instancesChanged.size === 0\n ) {\n return;\n }\n this.windowSpecs = windowSpecs;\n }\n this.visibleInstancesDirty = false;\n this.renderedObservers = this.observers.size;\n const anchor = this.getScrollAnchor(this.height);\n const updatedInstances = new Set<SubscribedInstance>();\n for (const instance of this.visibleInstances.values()) {\n if (instance.onRender(wrapperDirty)) {\n updatedInstances.add(instance);\n }\n }\n for (const instance of this.instancesChanged) {\n if (updatedInstances.has(instance)) continue;\n if (instance.onRender(wrapperDirty)) {\n updatedInstances.add(instance);\n }\n }\n\n this.scrollFix(anchor);\n // Scroll fix may have marked the dom as dirty, but if there instance\n // changes, we should definitely mark as dirty\n if (this.instancesChanged.size > 0) {\n this.markDOMDirty();\n }\n\n for (const instance of updatedInstances) {\n instance.reconcileHeights();\n }\n\n if (this.instancesChanged.size > 0 || wrapperDirty) {\n queueRender(this.computeRenderRangeAndEmit);\n }\n updatedInstances.clear();\n this.instancesChanged.clear();\n };\n\n private scrollFix(anchor: ScrollAnchor | undefined) {\n if (anchor == null) {\n return;\n }\n const scrollContainer = this.getScrollContainerElement();\n const { lineIndex, lineOffset, fileElement, fileOffset, fileTypeOffset } =\n anchor;\n if (lineIndex != null && lineOffset != null) {\n const element = fileElement.shadowRoot?.querySelector(\n `[data-line][data-line-index=\"${lineIndex}\"]`\n );\n if (element instanceof HTMLElement) {\n const top = getRelativeBoundingTop(element, scrollContainer);\n if (top !== lineOffset) {\n const scrollOffset = top - lineOffset;\n this.applyScrollFix(scrollOffset);\n }\n return;\n }\n }\n const top = getRelativeBoundingTop(fileElement, scrollContainer);\n if (fileTypeOffset === 'top') {\n if (top !== fileOffset) {\n this.applyScrollFix(top - fileOffset);\n }\n } else {\n const bottom = top + fileElement.getBoundingClientRect().height;\n if (bottom !== fileOffset) {\n this.applyScrollFix(bottom - fileOffset);\n }\n }\n }\n\n private applyScrollFix(scrollOffset: number) {\n if (this.root == null || this.root instanceof Document) {\n window.scrollTo({\n top: window.scrollY + scrollOffset,\n behavior: 'instant',\n });\n } else {\n this.root.scrollTo({\n top: this.root.scrollTop + scrollOffset,\n behavior: 'instant',\n });\n }\n // Because we fixed our scroll positions, it means something resized or\n // moved around, so we should mark everything as dirty so the\n // reconciliation call will get the latest data when figuring calling\n // .getOffsetInScrollContainer\n this.markDOMDirty();\n }\n\n // This function tries to figure out the closest file or line to the viewport\n // top that's visible to use as a relative marker for how to fix scroll\n // position after issuing dom updates\n private getScrollAnchor(viewportHeight: number): ScrollAnchor | undefined {\n const scrollContainer = this.getScrollContainerElement();\n let bestAnchor: ScrollAnchor | undefined;\n\n for (const [fileElement] of this.visibleInstances.entries()) {\n const fileTop = getRelativeBoundingTop(fileElement, scrollContainer);\n const fileBottom = fileTop + fileElement.offsetHeight;\n\n // Determine file offset and type based on position\n // Only use bottom anchor when entire file is above viewport\n let fileOffset: number;\n let fileTypeOffset: 'top' | 'bottom';\n if (fileBottom <= 0) {\n // Entire file is above viewport - use bottom as anchor\n fileOffset = fileBottom;\n fileTypeOffset = 'bottom';\n } else {\n // File is at least partially visible or below - use top\n fileOffset = fileTop;\n fileTypeOffset = 'top';\n }\n\n // Find the best line (first fully visible) within this file\n let bestLineIndex: string | undefined;\n let bestLineOffset: number | undefined;\n\n // Only search for lines if file potentially intersects viewport\n if (fileBottom > 0 && fileTop < viewportHeight) {\n for (const line of fileElement.shadowRoot?.querySelectorAll(\n '[data-line][data-line-index]'\n ) ?? []) {\n if (!(line instanceof HTMLElement)) continue;\n const lineIndex = line.dataset.lineIndex;\n if (lineIndex == null) continue;\n\n const lineOffset = getRelativeBoundingTop(line, scrollContainer);\n\n // Ignore lines with negative offsets (above viewport top)\n if (lineOffset < 0) continue;\n\n // First visible line in DOM order is the best one because\n // querySelectorAll will grab lines in order as they appear in the\n // DOM\n bestLineIndex = lineIndex;\n bestLineOffset = lineOffset;\n break;\n }\n }\n\n // If we already have an anchor with a visible line, skip files without one\n if (bestAnchor?.lineOffset != null && bestLineOffset == null) {\n continue;\n }\n\n // Decide if this file should become the new best anchor\n let shouldReplace = false;\n // If we don't already have an anchor we should set one\n if (bestAnchor == null) {\n shouldReplace = true;\n }\n // If we found a better line anchor, we should replace the old one\n else if (\n bestLineOffset != null &&\n (bestAnchor.lineOffset == null ||\n bestLineOffset < bestAnchor.lineOffset)\n ) {\n shouldReplace = true;\n }\n // Otherwise we need to compare file only anchors\n else if (bestLineOffset == null && bestAnchor.lineOffset == null) {\n // Favor files with their tops in view\n if (\n fileOffset >= 0 &&\n (bestAnchor.fileOffset < 0 || fileOffset < bestAnchor.fileOffset)\n ) {\n shouldReplace = true;\n }\n // Or the closest file\n else if (\n fileOffset < 0 &&\n bestAnchor.fileOffset < 0 &&\n fileOffset > bestAnchor.fileOffset\n ) {\n shouldReplace = true;\n }\n }\n\n if (shouldReplace) {\n bestAnchor = {\n fileElement,\n fileTypeOffset,\n fileOffset,\n lineIndex: bestLineIndex,\n lineOffset: bestLineOffset,\n };\n }\n }\n\n return bestAnchor;\n }\n\n private handleIntersectionChange = (\n entries: IntersectionObserverEntry[]\n ): void => {\n this.scrollDirty = true;\n for (const { target, isIntersecting } of entries) {\n if (!(target instanceof HTMLElement)) {\n throw new Error(\n 'Virtualizer.handleIntersectionChange: target not an HTMLElement'\n );\n }\n const instance = this.observers.get(target);\n if (instance == null) {\n throw new Error(\n 'Virtualizer.handleIntersectionChange: no instance for target'\n );\n }\n if (isIntersecting && !this.visibleInstances.has(target)) {\n instance.setVisibility(true);\n this.visibleInstances.set(target, instance);\n this.visibleInstancesDirty = true;\n } else if (!isIntersecting && this.visibleInstances.has(target)) {\n instance.setVisibility(false);\n this.visibleInstances.delete(target);\n this.visibleInstancesDirty = true;\n }\n }\n\n if (this.visibleInstancesDirty) {\n // Since this call is already debounced, should we just call\n // computeRenderRangeAndEmit directly?\n queueRender(this.computeRenderRangeAndEmit);\n }\n // Debug logging for visible instances\n // console.log(\n // 'handleIntersectionChange',\n // ...Array.from(this.visibleInstances.keys())\n // );\n };\n\n private getScrollTop() {\n if (!this.scrollDirty) {\n return this.scrollTop;\n }\n this.scrollDirty = false;\n let scrollTop = (() => {\n if (this.root == null) {\n return 0;\n }\n if (this.root instanceof Document) {\n return window.scrollY;\n }\n return this.root.scrollTop;\n })();\n\n // Lets always make sure to clamp scroll position cases of\n // over/bounce scroll\n scrollTop = Math.max(\n 0,\n Math.min(scrollTop, this.getScrollHeight() - this.getHeight())\n );\n this.scrollTop = scrollTop;\n return scrollTop;\n }\n\n private getScrollHeight() {\n if (!this.scrollHeightDirty) {\n return this.scrollHeight;\n }\n this.scrollHeightDirty = false;\n this.scrollHeight = (() => {\n if (this.root == null) {\n return 0;\n }\n if (this.root instanceof Document) {\n return this.root.documentElement.scrollHeight;\n }\n return this.root.scrollHeight;\n })();\n return this.scrollHeight;\n }\n\n private getHeight() {\n if (!this.heightDirty) {\n return this.height;\n }\n this.heightDirty = false;\n this.height = (() => {\n if (this.root == null) {\n return 0;\n }\n if (this.root instanceof Document) {\n return globalThis.innerHeight;\n }\n return this.root.getBoundingClientRect().height;\n })();\n return this.height;\n }\n\n private markDOMDirty() {\n this.scrollDirty = true;\n this.scrollHeightDirty = true;\n this.heightDirty = true;\n }\n\n private getScrollContainerElement(): HTMLElement | undefined {\n return this.root == null || this.root instanceof Document\n ? undefined\n : this.root;\n }\n}\n\n// This function is like a generalized getBoundingClientRect for it's relative\n// scroll container\nfunction getRelativeBoundingTop(\n element: HTMLElement,\n scrollContainer: HTMLElement | undefined\n) {\n const rect = element.getBoundingClientRect();\n const scrollContainerTop = scrollContainer?.getBoundingClientRect().top ?? 0;\n return rect.top - scrollContainerTop;\n}\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Virtualizer } from "./Virtualizer.js";
2
+ import { AdvancedVirtualizer } from "./AdvancedVirtualizer.js";
3
+
4
+ //#region src/components/VirtulizerDevelopment.d.ts
5
+ // FIXME(amadeus): REMOVE ME AFTER RELEASING VIRTUALIZATION
6
+ declare global {
7
+ interface Window {
8
+ // oxlint-disable-next-line typescript/no-explicit-any
9
+ __INSTANCE?: AdvancedVirtualizer<any> | Virtualizer;
10
+ __TOGGLE?: () => void;
11
+ __LOG?: boolean;
12
+ }
13
+ }
14
+ //# sourceMappingURL=VirtulizerDevelopment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VirtulizerDevelopment.d.ts","names":["AdvancedVirtualizer","Virtualizer","_0","sideEffect"],"sources":["../../src/components/VirtulizerDevelopment.d.ts"],"sourcesContent":["import type { AdvancedVirtualizer } from './AdvancedVirtualizer';\nimport type { Virtualizer } from './Virtualizer';\n\n// FIXME(amadeus): REMOVE ME AFTER RELEASING VIRTUALIZATION\ndeclare global {\n interface Window {\n // oxlint-disable-next-line typescript/no-explicit-any\n __INSTANCE?: AdvancedVirtualizer<any> | Virtualizer;\n __TOGGLE?: () => void;\n __LOG?: boolean;\n }\n}\n"],"mappings":";;;;;AACiD,QAAAE,MAAA,CAAA;EAAA,UAAA,MAAA,CAAA;;IAMMC,UAAAD,CAAA,EAAtCF,mBAAsC,CAAA,GAAA,CAAA,GAAXC,WAAW;IAAA,QAAA,CAAA,EAAA,GAAA,GAAA,IAAA"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/web-components.d.ts
2
- declare const DiffsContainerLoaded: boolean;
2
+ declare const DiffsContainerLoaded = true;
3
3
  //#endregion
4
4
  export { DiffsContainerLoaded };
5
5
  //# sourceMappingURL=web-components.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"web-components.d.ts","names":[],"sources":["../../src/components/web-components.ts"],"sourcesContent":[],"mappings":";cAmCa"}
1
+ {"version":3,"file":"web-components.d.ts","names":["DiffsContainerLoaded"],"sources":["../../src/components/web-components.d.ts"],"sourcesContent":["export declare const DiffsContainerLoaded = true;\n//# sourceMappingURL=web-components.d.ts.map"],"mappings":";cAAqBA,oBAAAA"}
@@ -1,4 +1,4 @@
1
- import { HunkExpansionRegion, ThemesType } from "./types.js";
1
+ import { HunkExpansionRegion, RenderRange, ThemesType, VirtualFileMetrics } from "./types.js";
2
2
 
3
3
  //#region src/constants.d.ts
4
4
  declare const DIFFS_TAG_NAME: "diffs-container";
@@ -11,17 +11,15 @@ declare const SPLIT_WITH_NEWLINES: RegExp;
11
11
  declare const FILENAME_HEADER_REGEX: RegExp;
12
12
  declare const FILENAME_HEADER_REGEX_GIT: RegExp;
13
13
  declare const ALTERNATE_FILE_NAMES_GIT: RegExp;
14
- declare const FILE_MODE_FROM_INDEX: RegExp;
14
+ declare const INDEX_LINE_METADATA: RegExp;
15
15
  declare const HEADER_METADATA_SLOT_ID = "header-metadata";
16
16
  declare const DEFAULT_THEMES: ThemesType;
17
17
  declare const UNSAFE_CSS_ATTRIBUTE = "data-unsafe-css";
18
18
  declare const CORE_CSS_ATTRIBUTE = "data-core-css";
19
- declare const LINE_HUNK_COUNT = 10;
20
- declare const LINE_HEIGHT = 20;
21
- declare const DIFF_HEADER_HEIGHT = 44;
22
- declare const HUNK_SEPARATOR_HEIGHT = 32;
23
- declare const FILE_GAP = 8;
19
+ declare const DEFAULT_COLLAPSED_CONTEXT_THRESHOLD = 1;
20
+ declare const DEFAULT_VIRTUAL_FILE_METRICS: VirtualFileMetrics;
24
21
  declare const DEFAULT_EXPANDED_REGION: HunkExpansionRegion;
22
+ declare const DEFAULT_RENDER_RANGE: RenderRange;
25
23
  //#endregion
26
- export { ALTERNATE_FILE_NAMES_GIT, COMMIT_METADATA_SPLIT, CORE_CSS_ATTRIBUTE, DEFAULT_EXPANDED_REGION, DEFAULT_THEMES, DIFFS_TAG_NAME, DIFF_HEADER_HEIGHT, FILENAME_HEADER_REGEX, FILENAME_HEADER_REGEX_GIT, FILE_CONTEXT_BLOB, FILE_GAP, FILE_MODE_FROM_INDEX, GIT_DIFF_FILE_BREAK_REGEX, HEADER_METADATA_SLOT_ID, HUNK_HEADER, HUNK_SEPARATOR_HEIGHT, LINE_HEIGHT, LINE_HUNK_COUNT, SPLIT_WITH_NEWLINES, UNIFIED_DIFF_FILE_BREAK_REGEX, UNSAFE_CSS_ATTRIBUTE };
24
+ export { ALTERNATE_FILE_NAMES_GIT, COMMIT_METADATA_SPLIT, CORE_CSS_ATTRIBUTE, DEFAULT_COLLAPSED_CONTEXT_THRESHOLD, DEFAULT_EXPANDED_REGION, DEFAULT_RENDER_RANGE, DEFAULT_THEMES, DEFAULT_VIRTUAL_FILE_METRICS, DIFFS_TAG_NAME, FILENAME_HEADER_REGEX, FILENAME_HEADER_REGEX_GIT, FILE_CONTEXT_BLOB, GIT_DIFF_FILE_BREAK_REGEX, HEADER_METADATA_SLOT_ID, HUNK_HEADER, INDEX_LINE_METADATA, SPLIT_WITH_NEWLINES, UNIFIED_DIFF_FILE_BREAK_REGEX, UNSAFE_CSS_ATTRIBUTE };
27
25
  //# sourceMappingURL=constants.d.ts.map