@vertesia/ui 0.80.0-dev-20251118 → 0.80.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 (311) hide show
  1. package/README.md +105 -0
  2. package/lib/esm/core/components/MenuList.js +2 -5
  3. package/lib/esm/core/components/MenuList.js.map +1 -1
  4. package/lib/esm/core/components/MessageBox.js +1 -1
  5. package/lib/esm/core/components/MessageBox.js.map +1 -1
  6. package/lib/esm/core/components/TagsInput.js +194 -0
  7. package/lib/esm/core/components/TagsInput.js.map +1 -0
  8. package/lib/esm/core/components/index.js +2 -1
  9. package/lib/esm/core/components/index.js.map +1 -1
  10. package/lib/esm/core/components/shadcn/dialog.js +16 -2
  11. package/lib/esm/core/components/shadcn/dialog.js.map +1 -1
  12. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js +6 -9
  13. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js.map +1 -1
  14. package/lib/esm/core/components/shadcn/filters/filterBar.js +1 -1
  15. package/lib/esm/core/components/shadcn/filters/filterBar.js.map +1 -1
  16. package/lib/esm/core/components/shadcn/popover.js +1 -1
  17. package/lib/esm/core/components/shadcn/popover.js.map +1 -1
  18. package/lib/esm/core/components/shadcn/selectBox.js +23 -5
  19. package/lib/esm/core/components/shadcn/selectBox.js.map +1 -1
  20. package/lib/esm/core/components/shadcn/tabs.js +3 -3
  21. package/lib/esm/core/components/shadcn/tabs.js.map +1 -1
  22. package/lib/esm/env/index.js +4 -1
  23. package/lib/esm/env/index.js.map +1 -1
  24. package/lib/esm/features/agent/chat/AgentChart.js +184 -0
  25. package/lib/esm/features/agent/chat/AgentChart.js.map +1 -0
  26. package/lib/esm/features/agent/chat/ModernAgentConversation.js +87 -10
  27. package/lib/esm/features/agent/chat/ModernAgentConversation.js.map +1 -1
  28. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +6 -2
  29. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  30. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js +4 -4
  31. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  32. package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js +4 -1
  33. package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js.map +1 -1
  34. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageInput.js +12 -4
  35. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  36. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js +60 -56
  37. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  38. package/lib/esm/features/agent/chat/index.js +1 -0
  39. package/lib/esm/features/agent/chat/index.js.map +1 -1
  40. package/lib/esm/features/agent/createChartTool.js +354 -0
  41. package/lib/esm/features/agent/createChartTool.js.map +1 -0
  42. package/lib/esm/features/agent/examples.js +295 -0
  43. package/lib/esm/features/agent/examples.js.map +1 -0
  44. package/lib/esm/features/agent/index.js +2 -0
  45. package/lib/esm/features/agent/index.js.map +1 -1
  46. package/lib/esm/features/agent/visualization.js +165 -0
  47. package/lib/esm/features/agent/visualization.js.map +1 -0
  48. package/lib/esm/features/facets/CollectionsFacetsNav.js +5 -1
  49. package/lib/esm/features/facets/CollectionsFacetsNav.js.map +1 -1
  50. package/lib/esm/features/index.js +1 -0
  51. package/lib/esm/features/index.js.map +1 -1
  52. package/lib/esm/features/layout/GenericPageNavHeader.js +14 -4
  53. package/lib/esm/features/layout/GenericPageNavHeader.js.map +1 -1
  54. package/lib/esm/features/magic-pdf/AnnotatedImageSlider.js +268 -0
  55. package/lib/esm/features/magic-pdf/AnnotatedImageSlider.js.map +1 -0
  56. package/lib/esm/features/magic-pdf/DownloadPopover.js +11 -11
  57. package/lib/esm/features/magic-pdf/DownloadPopover.js.map +1 -1
  58. package/lib/esm/features/magic-pdf/ExtractedContentView.js +77 -0
  59. package/lib/esm/features/magic-pdf/ExtractedContentView.js.map +1 -0
  60. package/lib/esm/features/magic-pdf/MagicPdfProvider.js +242 -0
  61. package/lib/esm/features/magic-pdf/MagicPdfProvider.js.map +1 -0
  62. package/lib/esm/features/magic-pdf/MagicPdfView.js +41 -47
  63. package/lib/esm/features/magic-pdf/MagicPdfView.js.map +1 -1
  64. package/lib/esm/features/pdf-viewer/PdfPageRenderer.js +261 -0
  65. package/lib/esm/features/pdf-viewer/PdfPageRenderer.js.map +1 -0
  66. package/lib/esm/features/pdf-viewer/PdfPageSlider.js +276 -0
  67. package/lib/esm/features/pdf-viewer/PdfPageSlider.js.map +1 -0
  68. package/lib/esm/features/pdf-viewer/SimplePdfViewer.js +71 -0
  69. package/lib/esm/features/pdf-viewer/SimplePdfViewer.js.map +1 -0
  70. package/lib/esm/features/pdf-viewer/index.js +4 -0
  71. package/lib/esm/features/pdf-viewer/index.js.map +1 -0
  72. package/lib/esm/features/store/collections/EditCollectionView.js +19 -10
  73. package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
  74. package/lib/esm/features/store/collections/SelectCollection.js +104 -39
  75. package/lib/esm/features/store/collections/SelectCollection.js.map +1 -1
  76. package/lib/esm/features/store/collections/SharedPropsEditor.js +39 -0
  77. package/lib/esm/features/store/collections/SharedPropsEditor.js.map +1 -0
  78. package/lib/esm/features/store/collections/SyncMemberHeadsToggle.js +35 -0
  79. package/lib/esm/features/store/collections/SyncMemberHeadsToggle.js.map +1 -0
  80. package/lib/esm/features/store/collections/index.js +2 -0
  81. package/lib/esm/features/store/collections/index.js.map +1 -1
  82. package/lib/esm/features/store/objects/DocumentSearchResults.js +0 -7
  83. package/lib/esm/features/store/objects/DocumentSearchResults.js.map +1 -1
  84. package/lib/esm/features/store/objects/components/ContentOverview.js +273 -83
  85. package/lib/esm/features/store/objects/components/ContentOverview.js.map +1 -1
  86. package/lib/esm/features/store/objects/components/useContentPanelHooks.js +153 -0
  87. package/lib/esm/features/store/objects/components/useContentPanelHooks.js.map +1 -0
  88. package/lib/esm/features/store/objects/layout/DocumentTableColumn.js +3 -3
  89. package/lib/esm/features/store/objects/layout/DocumentTableColumn.js.map +1 -1
  90. package/lib/esm/features/store/objects/layout/renderers.js +13 -0
  91. package/lib/esm/features/store/objects/layout/renderers.js.map +1 -1
  92. package/lib/esm/features/store/objects/upload/useSmartFileUploadProcessing.js +10 -9
  93. package/lib/esm/features/store/objects/upload/useSmartFileUploadProcessing.js.map +1 -1
  94. package/lib/esm/features/utils/index.js +2 -0
  95. package/lib/esm/features/utils/index.js.map +1 -1
  96. package/lib/esm/features/utils/mimeType.js +8 -0
  97. package/lib/esm/features/utils/mimeType.js.map +1 -1
  98. package/lib/esm/features/utils/print.js +181 -0
  99. package/lib/esm/features/utils/print.js.map +1 -0
  100. package/lib/esm/features/utils/workflowStatus.js +43 -0
  101. package/lib/esm/features/utils/workflowStatus.js.map +1 -0
  102. package/lib/esm/router/HistoryNavigator.js +22 -2
  103. package/lib/esm/router/HistoryNavigator.js.map +1 -1
  104. package/lib/esm/session/UserSessionProvider.js +2 -2
  105. package/lib/esm/session/UserSessionProvider.js.map +1 -1
  106. package/lib/esm/shell/apps/AppProjectSelector.js +2 -2
  107. package/lib/esm/shell/apps/AppProjectSelector.js.map +1 -1
  108. package/lib/esm/shell/login/UserInfo.js +2 -1
  109. package/lib/esm/shell/login/UserInfo.js.map +1 -1
  110. package/lib/esm/shell/login/UserSessionMenu.js +7 -1
  111. package/lib/esm/shell/login/UserSessionMenu.js.map +1 -1
  112. package/lib/esm/widgets/form/Form.js +6 -2
  113. package/lib/esm/widgets/form/Form.js.map +1 -1
  114. package/lib/esm/widgets/markdown/MarkdownRenderer.js +226 -4
  115. package/lib/esm/widgets/markdown/MarkdownRenderer.js.map +1 -1
  116. package/lib/esm/widgets/schema-editor/ManagedSchema.js +0 -3
  117. package/lib/esm/widgets/schema-editor/ManagedSchema.js.map +1 -1
  118. package/lib/esm/widgets/schema-editor/json-schema4-utils.js +1 -1
  119. package/lib/esm/widgets/schema-editor/json-schema4-utils.js.map +1 -1
  120. package/lib/esm/widgets/xml-viewer/components/XMLViewer.js +18 -9
  121. package/lib/esm/widgets/xml-viewer/components/XMLViewer.js.map +1 -1
  122. package/lib/esm/widgets/xml-viewer/constants/index.js +10 -0
  123. package/lib/esm/widgets/xml-viewer/constants/index.js.map +1 -1
  124. package/lib/tsconfig.tsbuildinfo +1 -1
  125. package/lib/types/core/components/MessageBox.d.ts.map +1 -1
  126. package/lib/types/core/components/TagsInput.d.ts +16 -0
  127. package/lib/types/core/components/TagsInput.d.ts.map +1 -0
  128. package/lib/types/core/components/index.d.ts +2 -1
  129. package/lib/types/core/components/index.d.ts.map +1 -1
  130. package/lib/types/core/components/shadcn/dialog.d.ts +2 -1
  131. package/lib/types/core/components/shadcn/dialog.d.ts.map +1 -1
  132. package/lib/types/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
  133. package/lib/types/core/components/shadcn/popover.d.ts +7 -0
  134. package/lib/types/core/components/shadcn/popover.d.ts.map +1 -1
  135. package/lib/types/core/components/shadcn/selectBox.d.ts +5 -1
  136. package/lib/types/core/components/shadcn/selectBox.d.ts.map +1 -1
  137. package/lib/types/core/components/shadcn/tabs.d.ts +3 -1
  138. package/lib/types/core/components/shadcn/tabs.d.ts.map +1 -1
  139. package/lib/types/env/index.d.ts +2 -0
  140. package/lib/types/env/index.d.ts.map +1 -1
  141. package/lib/types/features/agent/chat/AgentChart.d.ts +48 -0
  142. package/lib/types/features/agent/chat/AgentChart.d.ts.map +1 -0
  143. package/lib/types/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  144. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -2
  145. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  146. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts +2 -1
  147. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  148. package/lib/types/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.d.ts +4 -2
  149. package/lib/types/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.d.ts.map +1 -1
  150. package/lib/types/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +2 -4
  151. package/lib/types/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  152. package/lib/types/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  153. package/lib/types/features/agent/chat/index.d.ts +1 -0
  154. package/lib/types/features/agent/chat/index.d.ts.map +1 -1
  155. package/lib/types/features/agent/createChartTool.d.ts +178 -0
  156. package/lib/types/features/agent/createChartTool.d.ts.map +1 -0
  157. package/lib/types/features/agent/examples.d.ts +59 -0
  158. package/lib/types/features/agent/examples.d.ts.map +1 -0
  159. package/lib/types/features/agent/index.d.ts +2 -0
  160. package/lib/types/features/agent/index.d.ts.map +1 -1
  161. package/lib/types/features/agent/visualization.d.ts +95 -0
  162. package/lib/types/features/agent/visualization.d.ts.map +1 -0
  163. package/lib/types/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
  164. package/lib/types/features/index.d.ts +1 -0
  165. package/lib/types/features/index.d.ts.map +1 -1
  166. package/lib/types/features/layout/GenericPageNavHeader.d.ts.map +1 -1
  167. package/lib/types/features/magic-pdf/AnnotatedImageSlider.d.ts +13 -0
  168. package/lib/types/features/magic-pdf/AnnotatedImageSlider.d.ts.map +1 -0
  169. package/lib/types/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
  170. package/lib/types/features/magic-pdf/ExtractedContentView.d.ts +8 -0
  171. package/lib/types/features/magic-pdf/ExtractedContentView.d.ts.map +1 -0
  172. package/lib/types/features/magic-pdf/MagicPdfProvider.d.ts +58 -0
  173. package/lib/types/features/magic-pdf/MagicPdfProvider.d.ts.map +1 -0
  174. package/lib/types/features/magic-pdf/MagicPdfView.d.ts +1 -1
  175. package/lib/types/features/magic-pdf/MagicPdfView.d.ts.map +1 -1
  176. package/lib/types/features/pdf-viewer/PdfPageRenderer.d.ts +83 -0
  177. package/lib/types/features/pdf-viewer/PdfPageRenderer.d.ts.map +1 -0
  178. package/lib/types/features/pdf-viewer/PdfPageSlider.d.ts +29 -0
  179. package/lib/types/features/pdf-viewer/PdfPageSlider.d.ts.map +1 -0
  180. package/lib/types/features/pdf-viewer/SimplePdfViewer.d.ts +19 -0
  181. package/lib/types/features/pdf-viewer/SimplePdfViewer.d.ts.map +1 -0
  182. package/lib/types/features/pdf-viewer/index.d.ts +4 -0
  183. package/lib/types/features/pdf-viewer/index.d.ts.map +1 -0
  184. package/lib/types/features/store/collections/EditCollectionView.d.ts.map +1 -1
  185. package/lib/types/features/store/collections/SelectCollection.d.ts +2 -1
  186. package/lib/types/features/store/collections/SelectCollection.d.ts.map +1 -1
  187. package/lib/types/features/store/collections/SharedPropsEditor.d.ts +7 -0
  188. package/lib/types/features/store/collections/SharedPropsEditor.d.ts.map +1 -0
  189. package/lib/types/features/store/collections/SyncMemberHeadsToggle.d.ts +7 -0
  190. package/lib/types/features/store/collections/SyncMemberHeadsToggle.d.ts.map +1 -0
  191. package/lib/types/features/store/collections/index.d.ts +2 -0
  192. package/lib/types/features/store/collections/index.d.ts.map +1 -1
  193. package/lib/types/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
  194. package/lib/types/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  195. package/lib/types/features/store/objects/components/useContentPanelHooks.d.ts +30 -0
  196. package/lib/types/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -0
  197. package/lib/types/features/store/objects/layout/renderers.d.ts.map +1 -1
  198. package/lib/types/features/store/objects/upload/useSmartFileUploadProcessing.d.ts.map +1 -1
  199. package/lib/types/features/utils/index.d.ts +2 -0
  200. package/lib/types/features/utils/index.d.ts.map +1 -1
  201. package/lib/types/features/utils/mimeType.d.ts +1 -0
  202. package/lib/types/features/utils/mimeType.d.ts.map +1 -1
  203. package/lib/types/features/utils/print.d.ts +10 -0
  204. package/lib/types/features/utils/print.d.ts.map +1 -0
  205. package/lib/types/features/utils/workflowStatus.d.ts +10 -0
  206. package/lib/types/features/utils/workflowStatus.d.ts.map +1 -0
  207. package/lib/types/router/HistoryNavigator.d.ts +3 -0
  208. package/lib/types/router/HistoryNavigator.d.ts.map +1 -1
  209. package/lib/types/shell/login/UserInfo.d.ts.map +1 -1
  210. package/lib/types/shell/login/UserSessionMenu.d.ts.map +1 -1
  211. package/lib/types/widgets/form/Form.d.ts.map +1 -1
  212. package/lib/types/widgets/markdown/MarkdownRenderer.d.ts +5 -1
  213. package/lib/types/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
  214. package/lib/types/widgets/schema-editor/ManagedSchema.d.ts.map +1 -1
  215. package/lib/types/widgets/xml-viewer/components/XMLViewer.d.ts.map +1 -1
  216. package/lib/types/widgets/xml-viewer/constants/index.d.ts +10 -0
  217. package/lib/types/widgets/xml-viewer/constants/index.d.ts.map +1 -1
  218. package/lib/vertesia-ui-core.js +1 -1
  219. package/lib/vertesia-ui-core.js.map +1 -1
  220. package/lib/vertesia-ui-env.js +1 -1
  221. package/lib/vertesia-ui-env.js.map +1 -1
  222. package/lib/vertesia-ui-features.js +1 -1
  223. package/lib/vertesia-ui-features.js.map +1 -1
  224. package/lib/vertesia-ui-layout.js +1 -1
  225. package/lib/vertesia-ui-layout.js.map +1 -1
  226. package/lib/vertesia-ui-router.js +1 -1
  227. package/lib/vertesia-ui-router.js.map +1 -1
  228. package/lib/vertesia-ui-session.js +1 -1
  229. package/lib/vertesia-ui-session.js.map +1 -1
  230. package/lib/vertesia-ui-shell.js +1 -1
  231. package/lib/vertesia-ui-shell.js.map +1 -1
  232. package/lib/vertesia-ui-widgets.js +1 -1
  233. package/lib/vertesia-ui-widgets.js.map +1 -1
  234. package/package.json +173 -170
  235. package/src/core/components/MenuList.tsx +3 -6
  236. package/src/core/components/MessageBox.tsx +7 -2
  237. package/src/core/components/SelectBox.tsx +1 -1
  238. package/src/core/components/shadcn/dialog.tsx +19 -1
  239. package/src/core/components/shadcn/filters/filter/SelectFilter.tsx +31 -31
  240. package/src/core/components/shadcn/filters/filterBar.tsx +1 -0
  241. package/src/core/components/shadcn/selectBox.tsx +32 -6
  242. package/src/core/components/shadcn/tabs.tsx +3 -2
  243. package/src/env/index.ts +6 -1
  244. package/src/features/agent/CHART_INSTRUCTIONS.md +228 -0
  245. package/src/features/agent/chat/AgentChart.tsx +601 -0
  246. package/src/features/agent/chat/ModernAgentConversation.tsx +123 -11
  247. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +8 -2
  248. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +12 -2
  249. package/src/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.tsx +6 -1
  250. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +15 -10
  251. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +122 -87
  252. package/src/features/agent/chat/index.ts +1 -0
  253. package/src/features/agent/createChartTool.ts +364 -0
  254. package/src/features/agent/examples.ts +321 -0
  255. package/src/features/agent/index.ts +2 -0
  256. package/src/features/agent/visualization.ts +227 -0
  257. package/src/features/facets/CollectionsFacetsNav.tsx +5 -1
  258. package/src/features/index.ts +1 -0
  259. package/src/features/layout/GenericPageNavHeader.tsx +15 -4
  260. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +482 -0
  261. package/src/features/magic-pdf/DownloadPopover.tsx +45 -40
  262. package/src/features/magic-pdf/ExtractedContentView.tsx +132 -0
  263. package/src/features/magic-pdf/MagicPdfProvider.tsx +297 -0
  264. package/src/features/magic-pdf/MagicPdfView.tsx +184 -91
  265. package/src/features/pdf-viewer/PdfPageRenderer.tsx +612 -0
  266. package/src/features/pdf-viewer/PdfPageSlider.tsx +473 -0
  267. package/src/features/pdf-viewer/SimplePdfViewer.tsx +142 -0
  268. package/src/features/pdf-viewer/index.ts +3 -0
  269. package/src/features/store/collections/EditCollectionView.tsx +3 -5
  270. package/src/features/store/collections/SharedPropsEditor.tsx +1 -2
  271. package/src/features/store/objects/DocumentSearchResults.tsx +0 -7
  272. package/src/features/store/objects/components/ContentOverview.tsx +677 -210
  273. package/src/features/store/objects/components/useContentPanelHooks.ts +169 -0
  274. package/src/features/store/objects/layout/DocumentTableColumn.tsx +3 -3
  275. package/src/features/store/objects/layout/knowledge.md +1 -0
  276. package/src/features/store/objects/layout/renderers.tsx +25 -0
  277. package/src/features/store/objects/upload/useSmartFileUploadProcessing.ts +1 -3
  278. package/src/features/utils/index.ts +3 -1
  279. package/src/features/utils/mimeType.ts +10 -1
  280. package/src/features/utils/print.ts +189 -0
  281. package/src/features/utils/workflowStatus.ts +44 -0
  282. package/src/router/HistoryNavigator.ts +30 -2
  283. package/src/session/UserSessionProvider.tsx +2 -2
  284. package/src/shell/login/UserInfo.tsx +2 -0
  285. package/src/shell/login/UserSessionMenu.tsx +12 -1
  286. package/src/widgets/form/Form.tsx +8 -3
  287. package/src/widgets/markdown/MarkdownRenderer.tsx +350 -6
  288. package/src/widgets/schema-editor/ManagedSchema.ts +0 -3
  289. package/src/widgets/schema-editor/json-schema4-utils.ts +1 -1
  290. package/src/widgets/xml-viewer/components/XMLViewer.tsx +22 -10
  291. package/src/widgets/xml-viewer/constants/index.ts +11 -0
  292. package/lib/esm/features/magic-pdf/PageSlider.js +0 -70
  293. package/lib/esm/features/magic-pdf/PageSlider.js.map +0 -1
  294. package/lib/esm/features/magic-pdf/PdfPageProvider.js +0 -188
  295. package/lib/esm/features/magic-pdf/PdfPageProvider.js.map +0 -1
  296. package/lib/esm/features/magic-pdf/TextPageView.js +0 -62
  297. package/lib/esm/features/magic-pdf/TextPageView.js.map +0 -1
  298. package/lib/esm/features/magic-pdf/useResizeOnDrag.js +0 -34
  299. package/lib/esm/features/magic-pdf/useResizeOnDrag.js.map +0 -1
  300. package/lib/types/features/magic-pdf/PageSlider.d.ts +0 -9
  301. package/lib/types/features/magic-pdf/PageSlider.d.ts.map +0 -1
  302. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts +0 -39
  303. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts.map +0 -1
  304. package/lib/types/features/magic-pdf/TextPageView.d.ts +0 -8
  305. package/lib/types/features/magic-pdf/TextPageView.d.ts.map +0 -1
  306. package/lib/types/features/magic-pdf/useResizeOnDrag.d.ts +0 -9
  307. package/lib/types/features/magic-pdf/useResizeOnDrag.d.ts.map +0 -1
  308. package/src/features/magic-pdf/PageSlider.tsx +0 -142
  309. package/src/features/magic-pdf/PdfPageProvider.tsx +0 -310
  310. package/src/features/magic-pdf/TextPageView.tsx +0 -91
  311. package/src/features/magic-pdf/useResizeOnDrag.ts +0 -42
@@ -0,0 +1,473 @@
1
+ import { Button, Center, VTooltip } from "@vertesia/ui/core";
2
+ import clsx from "clsx";
3
+ import { ChevronsDown, ChevronsUp, Maximize, Minus, Plus } from "lucide-react";
4
+ import { ReactNode, useRef, useEffect, useState, useCallback, KeyboardEvent } from "react";
5
+ import { PdfThumbnailList } from "./PdfPageRenderer";
6
+
7
+ // A4 portrait aspect ratio - used as fallback
8
+ const A4_ASPECT_RATIO = 210 / 297;
9
+
10
+ // Zoom levels as percentages (100 = fit to width)
11
+ const ZOOM_LEVELS = [50, 75, 100, 125, 150, 200, 300];
12
+ const DEFAULT_ZOOM = 100;
13
+
14
+ interface PdfPageSliderProps {
15
+ /** URL to the PDF file */
16
+ pdfUrl: string;
17
+ /** Whether the PDF URL is still loading */
18
+ pdfUrlLoading?: boolean;
19
+ /** Total number of pages in the PDF (initial estimate, will be updated when PDF loads) */
20
+ pageCount: number;
21
+ /** Currently selected page number (1-indexed) */
22
+ currentPage: number;
23
+ /** Callback when page selection changes */
24
+ onChange: (pageNumber: number) => void;
25
+ /** Callback when actual page count is determined from the PDF */
26
+ onPageCountChange?: (pageCount: number) => void;
27
+ /** Additional CSS class names */
28
+ className?: string;
29
+ /** Compact mode reduces padding and navigation bar heights */
30
+ compact?: boolean;
31
+ /** Extra content to render in the header (e.g., fullscreen button) */
32
+ headerExtra?: ReactNode;
33
+ }
34
+
35
+ /**
36
+ * Standalone PDF thumbnail slider component.
37
+ * Displays a vertical list of PDF page thumbnails with navigation controls.
38
+ * Does not depend on any context - all data is passed via props.
39
+ */
40
+ export function PdfPageSlider({
41
+ pdfUrl,
42
+ pdfUrlLoading = false,
43
+ pageCount,
44
+ currentPage,
45
+ onChange,
46
+ onPageCountChange,
47
+ className,
48
+ compact = false,
49
+ headerExtra
50
+ }: PdfPageSliderProps) {
51
+ const ref = useRef<HTMLDivElement>(null);
52
+ const scrollContainerRef = useRef<HTMLDivElement>(null);
53
+ const [baseWidth, setBaseWidth] = useState<number | undefined>(undefined);
54
+ const [zoom, setZoom] = useState<number>(DEFAULT_ZOOM);
55
+ const [aspectRatio, setAspectRatio] = useState<number>(A4_ASPECT_RATIO);
56
+ // Track the actual item height from PdfThumbnailList for accurate scroll calculations
57
+ const [itemHeight, setItemHeight] = useState<number | null>(null);
58
+
59
+ // Track the previous item height to preserve scroll position during resize
60
+ const prevItemHeightRef = useRef<number | null>(null);
61
+
62
+ // Calculate thumbnail width based on zoom level
63
+ const thumbnailWidth = baseWidth ? Math.round(baseWidth * zoom / 100) : undefined;
64
+
65
+ const zoomIn = useCallback(() => {
66
+ let currentIndex = ZOOM_LEVELS.findIndex(level => level >= zoom);
67
+ if (currentIndex === -1) {
68
+ currentIndex = ZOOM_LEVELS.length - 1;
69
+ }
70
+ const nextIndex = Math.min(currentIndex + 1, ZOOM_LEVELS.length - 1);
71
+ setZoom(ZOOM_LEVELS[nextIndex]);
72
+ }, [zoom]);
73
+
74
+ const zoomOut = useCallback(() => {
75
+ let currentIndex = ZOOM_LEVELS.findIndex(level => level >= zoom);
76
+ if (currentIndex === -1) {
77
+ currentIndex = ZOOM_LEVELS.length - 1;
78
+ }
79
+ const prevIndex = Math.max(currentIndex - 1, 0);
80
+ setZoom(ZOOM_LEVELS[prevIndex]);
81
+ }, [zoom]);
82
+
83
+ const fitToView = useCallback(() => {
84
+ setZoom(DEFAULT_ZOOM);
85
+ }, []);
86
+
87
+ // Calculate item height based on placeholder height - this must match the renderThumbnail layout
88
+ // padding (p-1=8 or p-2=16) + text height (~16-20 for compact, ~24 for normal) + gap (gap-1=4 or gap-2=8)
89
+ const calculateItemHeight = useCallback((placeholderHeight: number) => {
90
+ const extraHeight = compact ? 8 + 16 + 4 : 16 + 24 + 8;
91
+ return placeholderHeight + extraHeight;
92
+ }, [compact]);
93
+
94
+ // Legacy function for resize preservation - kept for backwards compatibility
95
+ const getItemHeight = (width: number | undefined, ratio: number) => {
96
+ const placeholderHeight = width ? Math.round(width / ratio) : 200;
97
+ return calculateItemHeight(placeholderHeight);
98
+ };
99
+
100
+ // Single ResizeObserver at parent level to measure thumbnail width
101
+ // Debounced to avoid excessive re-renders during resize
102
+ useEffect(() => {
103
+ const container = scrollContainerRef.current;
104
+ if (!container) return;
105
+
106
+ let debounceTimer: ReturnType<typeof setTimeout> | null = null;
107
+
108
+ const getAvailableWidth = () => {
109
+ // Container width minus padding (px-2 = 8px each side) minus thumbnail padding (p-2 = 8px each side) minus border (2px each side)
110
+ return container.clientWidth - 16 - 16 - 4;
111
+ };
112
+
113
+ const updateWidth = () => {
114
+ const newWidth = getAvailableWidth();
115
+ if (newWidth <= 0) return;
116
+
117
+ // Before updating width, preserve scroll position by calculating which page is at top
118
+ const oldItemHeight = prevItemHeightRef.current;
119
+ if (oldItemHeight && oldItemHeight > 0) {
120
+ const currentScrollTop = container.scrollTop;
121
+ const currentTopPage = Math.round(currentScrollTop / oldItemHeight);
122
+
123
+ // Calculate new item height and adjust scroll position
124
+ const newItemHeight = getItemHeight(newWidth, aspectRatio);
125
+ const newScrollTop = currentTopPage * newItemHeight;
126
+
127
+ // Update width first, then scroll
128
+ setBaseWidth(newWidth);
129
+
130
+ // Use requestAnimationFrame to scroll after the DOM updates
131
+ requestAnimationFrame(() => {
132
+ container.scrollTo({ top: newScrollTop, behavior: 'instant' });
133
+ });
134
+
135
+ prevItemHeightRef.current = newItemHeight;
136
+ } else {
137
+ setBaseWidth(newWidth);
138
+ prevItemHeightRef.current = getItemHeight(newWidth, aspectRatio);
139
+ }
140
+ };
141
+
142
+ // Initial width update
143
+ const initialWidth = getAvailableWidth();
144
+ if (initialWidth > 0) {
145
+ setBaseWidth(initialWidth);
146
+ prevItemHeightRef.current = getItemHeight(initialWidth, aspectRatio);
147
+ }
148
+
149
+ const handleResize = () => {
150
+ // Debounce width updates to avoid re-rendering PDFs during resize
151
+ if (debounceTimer) clearTimeout(debounceTimer);
152
+ debounceTimer = setTimeout(updateWidth, 150);
153
+ };
154
+
155
+ const resizeObserver = new ResizeObserver(handleResize);
156
+ resizeObserver.observe(container);
157
+
158
+ return () => {
159
+ if (debounceTimer) clearTimeout(debounceTimer);
160
+ resizeObserver.disconnect();
161
+ };
162
+ }, [aspectRatio]);
163
+
164
+ // Track whether we're programmatically scrolling to avoid feedback loops
165
+ const isProgrammaticScrollRef = useRef(false);
166
+
167
+ // Track pending zoom scroll - we need to wait for itemHeight to update after zoom change
168
+ const pendingZoomScrollRef = useRef<{ targetPage: number } | null>(null);
169
+
170
+ // When zoom changes, mark that we need to scroll after itemHeight updates
171
+ const prevZoomRef = useRef(zoom);
172
+ useEffect(() => {
173
+ if (prevZoomRef.current !== zoom) {
174
+ prevZoomRef.current = zoom;
175
+ // Mark that we need to scroll to current page after itemHeight updates
176
+ pendingZoomScrollRef.current = { targetPage: currentPage };
177
+ isProgrammaticScrollRef.current = true;
178
+ }
179
+ }, [zoom, currentPage]);
180
+
181
+ // When itemHeight changes (after zoom), perform the pending scroll
182
+ useEffect(() => {
183
+ const container = scrollContainerRef.current;
184
+ const pendingScroll = pendingZoomScrollRef.current;
185
+
186
+ if (pendingScroll && container && itemHeight) {
187
+ pendingZoomScrollRef.current = null;
188
+
189
+ // Calculate scroll position using the NEW itemHeight
190
+ const targetScrollTop = (pendingScroll.targetPage - 1) * itemHeight;
191
+
192
+ // Use requestAnimationFrame to ensure DOM is updated
193
+ requestAnimationFrame(() => {
194
+ container.scrollTo({ top: targetScrollTop, behavior: 'instant' });
195
+ // Reset after scroll completes
196
+ requestAnimationFrame(() => {
197
+ isProgrammaticScrollRef.current = false;
198
+ });
199
+ });
200
+ }
201
+ }, [itemHeight]);
202
+
203
+ // Track if we've done the initial scroll on mount
204
+ const hasInitialScrolledRef = useRef(false);
205
+
206
+ // Initial scroll to current page when component mounts and itemHeight becomes available
207
+ useEffect(() => {
208
+ const container = scrollContainerRef.current;
209
+ if (!container || !itemHeight || hasInitialScrolledRef.current) return;
210
+
211
+ // Only do initial scroll if not on page 1
212
+ if (currentPage > 1) {
213
+ hasInitialScrolledRef.current = true;
214
+ isProgrammaticScrollRef.current = true;
215
+
216
+ const targetScrollTop = (currentPage - 1) * itemHeight;
217
+ container.scrollTo({ top: targetScrollTop, behavior: 'instant' });
218
+
219
+ requestAnimationFrame(() => {
220
+ isProgrammaticScrollRef.current = false;
221
+ });
222
+ } else {
223
+ hasInitialScrolledRef.current = true;
224
+ }
225
+ }, [itemHeight, currentPage]);
226
+
227
+ // Jump to current page when it changes (user navigation)
228
+ // Use a ref to track the previous page to avoid scrolling on resize
229
+ const prevPageRef = useRef(currentPage);
230
+ useEffect(() => {
231
+ const container = scrollContainerRef.current;
232
+ if (!container || !itemHeight) return;
233
+
234
+ // Only scroll if the page actually changed (user navigation)
235
+ if (prevPageRef.current !== currentPage) {
236
+ prevPageRef.current = currentPage;
237
+
238
+ // Mark as programmatic scroll to avoid triggering onChange
239
+ isProgrammaticScrollRef.current = true;
240
+
241
+ // Calculate scroll position directly using itemHeight
242
+ // This is more reliable than DOM queries since virtualization uses spacers
243
+ const targetScrollTop = (currentPage - 1) * itemHeight;
244
+ container.scrollTo({ top: targetScrollTop, behavior: 'instant' });
245
+
246
+ // Reset after a short delay to allow scroll event to fire
247
+ requestAnimationFrame(() => {
248
+ isProgrammaticScrollRef.current = false;
249
+ });
250
+ }
251
+ }, [currentPage, itemHeight]);
252
+
253
+ // Update current page based on scroll position
254
+ useEffect(() => {
255
+ const container = scrollContainerRef.current;
256
+ if (!container || !itemHeight) return;
257
+
258
+ let scrollDebounceTimer: ReturnType<typeof setTimeout> | null = null;
259
+
260
+ const handleScroll = () => {
261
+ // Skip if this is a programmatic scroll
262
+ if (isProgrammaticScrollRef.current) return;
263
+
264
+ // Debounce scroll updates
265
+ if (scrollDebounceTimer) clearTimeout(scrollDebounceTimer);
266
+ scrollDebounceTimer = setTimeout(() => {
267
+ // Calculate current page from scroll position using itemHeight
268
+ // This is more reliable than DOM queries since virtualization uses spacers
269
+ const scrollTop = container.scrollTop;
270
+ const calculatedPage = Math.round(scrollTop / itemHeight) + 1;
271
+
272
+ // Clamp to valid range and update if different
273
+ const clampedPage = Math.max(1, Math.min(calculatedPage, pageCount));
274
+ if (clampedPage !== currentPage) {
275
+ prevPageRef.current = clampedPage;
276
+ onChange(clampedPage);
277
+ }
278
+ }, 50);
279
+ };
280
+
281
+ container.addEventListener('scroll', handleScroll, { passive: true });
282
+
283
+ return () => {
284
+ if (scrollDebounceTimer) clearTimeout(scrollDebounceTimer);
285
+ container.removeEventListener('scroll', handleScroll);
286
+ };
287
+ }, [itemHeight, pageCount, currentPage, onChange]);
288
+
289
+ const goPrev = () => {
290
+ if (currentPage > 1) {
291
+ onChange(currentPage - 1);
292
+ }
293
+ }
294
+ const goNext = () => {
295
+ if (currentPage < pageCount) {
296
+ onChange(currentPage + 1);
297
+ }
298
+ }
299
+
300
+ return (
301
+ <div ref={ref} className={clsx('flex flex-col items-stretch', compact ? 'gap-y-1' : 'gap-y-2', className)}>
302
+ <div className={clsx("relative flex items-center justify-center px-2", compact ? "h-6" : "h-9")}>
303
+ <Button variant="ghost" size="xs" onClick={goPrev} alt="Previous page">
304
+ <ChevronsUp className='size-4' />
305
+ </Button>
306
+ <div className="absolute left-2 flex items-center gap-x-1">
307
+ <ZoomControls
308
+ zoom={zoom}
309
+ onZoomIn={zoomIn}
310
+ onZoomOut={zoomOut}
311
+ onFitToView={fitToView}
312
+ canZoomIn={zoom < ZOOM_LEVELS[ZOOM_LEVELS.length - 1]}
313
+ canZoomOut={zoom > ZOOM_LEVELS[0]}
314
+ />
315
+ {headerExtra && (
316
+ <>
317
+ <div className="w-px h-4 bg-border mx-1" />
318
+ {headerExtra}
319
+ </>
320
+ )}
321
+ </div>
322
+ <div className="absolute right-2">
323
+ <PageNavigator currentPage={currentPage} totalPages={pageCount} onChange={onChange} />
324
+ </div>
325
+ </div>
326
+ <div ref={scrollContainerRef} className={clsx('flex flex-col items-center flex-1 overflow-y-auto px-2', compact ? 'gap-1' : 'gap-2')}>
327
+ <PdfThumbnailList
328
+ pdfUrl={pdfUrl}
329
+ urlLoading={pdfUrlLoading}
330
+ pageCount={pageCount}
331
+ currentPage={currentPage}
332
+ thumbnailWidth={thumbnailWidth}
333
+ onPageSelect={onChange}
334
+ onPageCountChange={onPageCountChange}
335
+ scrollContainerRef={scrollContainerRef}
336
+ onAspectRatioChange={setAspectRatio}
337
+ onItemHeightChange={setItemHeight}
338
+ calculateItemHeight={calculateItemHeight}
339
+ renderThumbnail={({ pageNumber, isSelected, pageElement, onSelect }) => (
340
+ <div key={pageNumber} className={clsx("hover:bg-muted rounded-md w-full", compact ? "p-1" : "p-2")}>
341
+ <div
342
+ className={clsx('relative border-[2px] cursor-pointer overflow-hidden', isSelected ? "border-primary" : "border-border")}
343
+ onClick={onSelect}
344
+ >
345
+ {pageElement}
346
+ </div>
347
+ <Center className={clsx("text-muted-foreground font-semibold", compact ? "text-xs pt-0.5" : "text-sm pt-1")}>{pageNumber}</Center>
348
+ </div>
349
+ )}
350
+ />
351
+ </div>
352
+ <div className={clsx("flex items-center justify-center", compact ? "h-6" : "h-9")}>
353
+ <Button variant="ghost" size="xs" onClick={goNext} alt="Next page">
354
+ <ChevronsDown className='size-4' />
355
+ </Button>
356
+ </div>
357
+ </div>
358
+ )
359
+ }
360
+
361
+ interface PageNavigatorProps {
362
+ currentPage: number;
363
+ totalPages: number;
364
+ onChange: (page: number) => void;
365
+ }
366
+ function PageNavigator({ currentPage, totalPages, onChange }: PageNavigatorProps) {
367
+ const inputRef = useRef<HTMLInputElement>(null);
368
+ const [inputValue, setInputValue] = useState(String(currentPage));
369
+
370
+ // Sync input value when currentPage changes externally
371
+ useEffect(() => {
372
+ setInputValue(String(currentPage));
373
+ }, [currentPage]);
374
+
375
+ const handleSubmit = () => {
376
+ const page = parseInt(inputValue, 10);
377
+ if (!isNaN(page) && page >= 1 && page <= totalPages) {
378
+ onChange(page);
379
+ } else {
380
+ // Reset to current page if invalid
381
+ setInputValue(String(currentPage));
382
+ }
383
+ };
384
+
385
+ const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
386
+ if (e.key === 'Enter') {
387
+ handleSubmit();
388
+ inputRef.current?.blur();
389
+ } else if (e.key === 'Escape') {
390
+ setInputValue(String(currentPage));
391
+ inputRef.current?.blur();
392
+ }
393
+ };
394
+
395
+ const handleBlur = () => {
396
+ handleSubmit();
397
+ };
398
+
399
+ return (
400
+ <div className="flex items-center gap-1 text-xs text-muted-foreground">
401
+ <span>Page</span>
402
+ <input
403
+ ref={inputRef}
404
+ type="text"
405
+ value={inputValue}
406
+ onChange={(e) => setInputValue(e.target.value)}
407
+ onKeyDown={handleKeyDown}
408
+ onBlur={handleBlur}
409
+ className="w-8 h-5 text-center text-xs px-1 py-0 bg-background border border-border rounded focus:outline-none focus:border-primary"
410
+ />
411
+ <span>/ {totalPages}</span>
412
+ </div>
413
+ );
414
+ }
415
+
416
+ interface ZoomControlsProps {
417
+ zoom: number;
418
+ onZoomIn: () => void;
419
+ onZoomOut: () => void;
420
+ onFitToView: () => void;
421
+ canZoomIn: boolean;
422
+ canZoomOut: boolean;
423
+ }
424
+ function ZoomControls({ zoom, onZoomIn, onZoomOut, onFitToView, canZoomIn, canZoomOut }: ZoomControlsProps) {
425
+ return (
426
+ <div className="flex items-center gap-x-0.5">
427
+ <VTooltip description="Zoom out" placement="bottom" size="xs">
428
+ <button
429
+ className={clsx(
430
+ "p-1 rounded cursor-pointer transition-colors",
431
+ canZoomOut
432
+ ? "text-muted-foreground hover:text-foreground hover:bg-muted"
433
+ : "text-muted-foreground/40 cursor-not-allowed"
434
+ )}
435
+ onClick={onZoomOut}
436
+ disabled={!canZoomOut}
437
+ >
438
+ <Minus className="size-4" />
439
+ </button>
440
+ </VTooltip>
441
+ <span className="text-xs text-muted-foreground min-w-[32px] text-center">
442
+ {zoom}%
443
+ </span>
444
+ <VTooltip description="Zoom in" placement="bottom" size="xs">
445
+ <button
446
+ className={clsx(
447
+ "p-1 rounded cursor-pointer transition-colors",
448
+ canZoomIn
449
+ ? "text-muted-foreground hover:text-foreground hover:bg-muted"
450
+ : "text-muted-foreground/40 cursor-not-allowed"
451
+ )}
452
+ onClick={onZoomIn}
453
+ disabled={!canZoomIn}
454
+ >
455
+ <Plus className="size-4" />
456
+ </button>
457
+ </VTooltip>
458
+ <VTooltip description="Fit to width" placement="bottom" size="xs">
459
+ <button
460
+ className={clsx(
461
+ "p-1 rounded cursor-pointer transition-colors",
462
+ zoom !== DEFAULT_ZOOM
463
+ ? "text-muted-foreground hover:text-foreground hover:bg-muted"
464
+ : "text-muted-foreground/40"
465
+ )}
466
+ onClick={onFitToView}
467
+ >
468
+ <Maximize className="size-4" />
469
+ </button>
470
+ </VTooltip>
471
+ </div>
472
+ );
473
+ }
@@ -0,0 +1,142 @@
1
+ import { ContentObject } from "@vertesia/common";
2
+ import { Button, Spinner, VTooltip } from "@vertesia/ui/core";
3
+ import { useUserSession } from "@vertesia/ui/session";
4
+ import { Maximize2, X } from "lucide-react";
5
+ import { useEffect, useState } from "react";
6
+ import { PdfPageSlider } from "./PdfPageSlider";
7
+
8
+ interface SimplePdfViewerProps {
9
+ /** The content object containing the PDF (optional if url or source is provided) */
10
+ object?: ContentObject;
11
+ /** Direct signed URL to the PDF (ready to use, no resolution needed) */
12
+ url?: string;
13
+ /** Storage source path that needs to be resolved to a download URL */
14
+ source?: string;
15
+ /** Additional CSS class names */
16
+ className?: string;
17
+ }
18
+
19
+ /**
20
+ * A standalone PDF viewer component that displays PDF thumbnails with navigation.
21
+ * Fetches the PDF URL from the content object and displays it using PdfThumbnailSlider.
22
+ * Does not depend on any magic-pdf context.
23
+ */
24
+ export function SimplePdfViewer({ object, url, source, className }: SimplePdfViewerProps) {
25
+ const { client } = useUserSession();
26
+ const [currentPage, setCurrentPage] = useState(1);
27
+ const [pdfUrl, setPdfUrl] = useState<string>(url || "");
28
+ const [pdfUrlLoading, setPdfUrlLoading] = useState(!url);
29
+ const [pageCount, setPageCount] = useState(0);
30
+ const [isFullscreen, setIsFullscreen] = useState(false);
31
+
32
+ // Fetch the PDF URL - priority: url > source > object.content.source
33
+ useEffect(() => {
34
+ // If url prop is provided, use it directly (already signed)
35
+ if (url) {
36
+ setPdfUrl(url);
37
+ setPdfUrlLoading(false);
38
+ return;
39
+ }
40
+
41
+ // Determine the source to resolve
42
+ const sourceToResolve = source || object?.content?.source;
43
+ if (!sourceToResolve) {
44
+ setPdfUrlLoading(false);
45
+ return;
46
+ }
47
+
48
+ setPdfUrlLoading(true);
49
+ client.files.getDownloadUrl(sourceToResolve)
50
+ .then((result) => {
51
+ setPdfUrl(result.url);
52
+ })
53
+ .catch((err) => {
54
+ console.error("Failed to get PDF URL:", err);
55
+ })
56
+ .finally(() => {
57
+ setPdfUrlLoading(false);
58
+ });
59
+ }, [url, source, object?.content?.source, client]);
60
+
61
+ // Get initial page count from metadata, but actual count will be updated when PDF loads
62
+ useEffect(() => {
63
+ // Try to get page count from metadata as initial estimate
64
+ const metadata = object?.metadata as { pages?: number; page_count?: number } | undefined;
65
+ const count = metadata?.pages || metadata?.page_count || 0;
66
+
67
+ if (count > 0) {
68
+ setPageCount(count);
69
+ }
70
+ // If no metadata, keep pageCount at 0 - it will be set when PDF loads
71
+ }, [object?.metadata]);
72
+
73
+ // Callback to update page count when PDF loads
74
+ const handlePageCountChange = (count: number) => {
75
+ setPageCount(count);
76
+ };
77
+
78
+ if (pdfUrlLoading) {
79
+ return (
80
+ <div className="flex items-center justify-center h-full">
81
+ <Spinner size="lg" />
82
+ </div>
83
+ );
84
+ }
85
+
86
+ if (!pdfUrl) {
87
+ return (
88
+ <div className="flex items-center justify-center h-full text-muted">
89
+ No PDF available
90
+ </div>
91
+ );
92
+ }
93
+
94
+ // Fullscreen overlay
95
+ if (isFullscreen) {
96
+ return (
97
+ <div className="fixed inset-0 bg-background z-50 flex flex-col overflow-hidden">
98
+ {/* Header with close button */}
99
+ <div className="flex h-9 items-center justify-end shrink-0 bg-sidebar px-2 border-b border-sidebar-border">
100
+ <Button variant="ghost" size="xs" onClick={() => setIsFullscreen(false)} alt="Close fullscreen">
101
+ <X className="size-4" />
102
+ </Button>
103
+ </div>
104
+ {/* PDF viewer - min-h-0 allows flex child to shrink below content size */}
105
+ <PdfPageSlider
106
+ pdfUrl={pdfUrl}
107
+ pdfUrlLoading={pdfUrlLoading}
108
+ pageCount={pageCount || 100}
109
+ currentPage={currentPage}
110
+ onChange={setCurrentPage}
111
+ onPageCountChange={handlePageCountChange}
112
+ className="flex-1 min-h-0"
113
+ />
114
+ </div>
115
+ );
116
+ }
117
+
118
+ return (
119
+ <div className="relative h-full flex flex-col">
120
+ <PdfPageSlider
121
+ pdfUrl={pdfUrl}
122
+ pdfUrlLoading={pdfUrlLoading}
123
+ pageCount={pageCount || 100}
124
+ currentPage={currentPage}
125
+ onChange={setCurrentPage}
126
+ onPageCountChange={handlePageCountChange}
127
+ className={className}
128
+ compact
129
+ headerExtra={
130
+ <VTooltip description="Fullscreen" placement="bottom" size="xs">
131
+ <button
132
+ className="p-1 rounded cursor-pointer transition-colors text-muted-foreground hover:text-foreground hover:bg-muted"
133
+ onClick={() => setIsFullscreen(true)}
134
+ >
135
+ <Maximize2 className="size-4" />
136
+ </button>
137
+ </VTooltip>
138
+ }
139
+ />
140
+ </div>
141
+ );
142
+ }
@@ -0,0 +1,3 @@
1
+ export * from './PdfPageRenderer';
2
+ export * from './PdfPageSlider';
3
+ export * from './SimplePdfViewer';
@@ -1,9 +1,7 @@
1
1
  import { json } from "@codemirror/lang-json";
2
2
  import { Collection, CreateCollectionPayload, JSONSchemaObject } from "@vertesia/common";
3
3
  import { Button, ErrorBox, FormItem, Input, Panel, Styles, Textarea, useFetch, useToast } from "@vertesia/ui/core";
4
- import { UserInfo } from "@vertesia/ui/features";
5
- import { SharedPropsEditor } from "@vertesia/ui/features";
6
- import { SyncMemberHeadsToggle } from "@vertesia/ui/features";
4
+ import { SharedPropsEditor, SyncMemberHeadsToggle, UserInfo } from "@vertesia/ui/features";
7
5
  import { useUserSession } from "@vertesia/ui/session";
8
6
  import { CodeMirrorEditor, EditorApi, GeneratedForm, ManagedObject, Node } from "@vertesia/ui/widgets";
9
7
  import { basicSetup } from "codemirror";
@@ -163,7 +161,7 @@ export function EditCollectionView({ refetch, collection }: EditCollectionViewPr
163
161
  <FormItem label="Description">
164
162
  <Textarea
165
163
  value={metadata.description}
166
- onChange={(e) => setField("description", e)}
164
+ onChange={(e) => setField("description", e.target.value)}
167
165
  />
168
166
  </FormItem>
169
167
  {
@@ -188,7 +186,7 @@ export function EditCollectionView({ refetch, collection }: EditCollectionViewPr
188
186
  <Textarea
189
187
  className={Styles.INPUT}
190
188
  value={metadata.query}
191
- onChange={(e) => setField("query", e)}
189
+ onChange={(e) => setField("query", e.target.value)}
192
190
  />
193
191
  </FormItem>
194
192
  )
@@ -1,6 +1,5 @@
1
1
  import { Collection, ContentObjectType } from "@vertesia/common";
2
- import { Button, Panel, useToast } from "@vertesia/ui/core";
3
- import { TagsInput } from "@vertesia/ui/core";
2
+ import { Button, Panel, TagsInput, useToast } from "@vertesia/ui/core";
4
3
  import { useUserSession } from "@vertesia/ui/session";
5
4
  import { useEffect, useState } from "react";
6
5
 
@@ -27,12 +27,7 @@ const defaultLayout: ColumnLayout[] = [
27
27
 
28
28
  function getTableLayout(registry: TypeRegistry, type: string | undefined): ColumnLayout[] {
29
29
  const layout = type ? registry.getTypeLayout(type) : defaultLayout;
30
- console.log('[DEBUG] getTableLayout called with type:', type);
31
- console.log('[DEBUG] Layout from registry:', layout);
32
- console.log('[DEBUG] Using defaultLayout?', layout === defaultLayout);
33
30
  const result = layout ?? defaultLayout;
34
- console.log('[DEBUG] Final layout:', result);
35
- console.log('[DEBUG] Has Status field?', result.some(col => col.field === 'status'));
36
31
  return result;
37
32
  }
38
33
 
@@ -101,8 +96,6 @@ export function DocumentSearchResults({ layout, onUpload, allowFilter = true, al
101
96
  typeRegistry ? layout || getTableLayout(typeRegistry, search.query.type) : defaultLayout,
102
97
  );
103
98
 
104
- console.log('[DEBUG] DocumentSearchResults - actualLayout:', actualLayout);
105
- console.log('[DEBUG] DocumentSearchResults - actualLayout has Status?', actualLayout.some(col => col.field === 'status'));
106
99
  //TODO _setRefreshTrigger state not used
107
100
  const [refreshTrigger, _setRefreshTrigger] = useState(0);
108
101
  const [loaded, setLoaded] = useState(0);