@arbidocs/blocks 0.5.120 → 0.5.121
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.
- package/dist/ClippingMediaViewer-B6WG7Q64.cjs +156 -0
- package/dist/ClippingMediaViewer-B6WG7Q64.cjs.map +1 -0
- package/dist/ClippingPdfViewer-6GCVTV3V.cjs +79 -0
- package/dist/ClippingPdfViewer-6GCVTV3V.cjs.map +1 -0
- package/dist/{ConnectedCallDock-WER7R222.cjs → ConnectedCallDock-DC5V5OUJ.cjs} +25 -23
- package/dist/ConnectedCallDock-DC5V5OUJ.cjs.map +1 -0
- package/dist/{ConnectedCallRoom-T7OBQTYP.cjs → ConnectedCallRoom-FQLXWTFB.cjs} +18 -16
- package/dist/{ConnectedCallRoom-T7OBQTYP.cjs.map → ConnectedCallRoom-FQLXWTFB.cjs.map} +1 -1
- package/dist/{ConnectedNativeDocxComparison-SGE4R3M4.cjs → ConnectedNativeDocxComparison-4Q5S7VLD.cjs} +17 -17
- package/dist/{ConnectedNativeDocxComparison-SGE4R3M4.cjs.map → ConnectedNativeDocxComparison-4Q5S7VLD.cjs.map} +1 -1
- package/dist/ConnectedPresentation-4HLDZDWV.cjs +183 -0
- package/dist/ConnectedPresentation-4HLDZDWV.cjs.map +1 -0
- package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs → ConnectedProductionSetDialog-4EAY6KAZ.cjs} +3 -3
- package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs.map → ConnectedProductionSetDialog-4EAY6KAZ.cjs.map} +1 -1
- package/dist/ConnectedSlidesTab-7QDE2CZD.cjs +234 -0
- package/dist/ConnectedSlidesTab-7QDE2CZD.cjs.map +1 -0
- package/dist/{ConnectedStreamedWordArtifact-6MCLJRIT.cjs → ConnectedStreamedWordArtifact-FFOQJBOI.cjs} +17 -17
- package/dist/{ConnectedStreamedWordArtifact-6MCLJRIT.cjs.map → ConnectedStreamedWordArtifact-FFOQJBOI.cjs.map} +1 -1
- package/dist/{DocumentReviewCard-BPIAJJED.cjs → DocumentReviewCard-SNWVEZ7S.cjs} +17 -16
- package/dist/DocumentReviewCard-SNWVEZ7S.cjs.map +1 -0
- package/dist/{FilesViewerDialog-67WK3TZC.cjs → FilesViewerDialog-IZI63FOV.cjs} +52 -45
- package/dist/FilesViewerDialog-IZI63FOV.cjs.map +1 -0
- package/dist/{GridViewImpl-ZMJJWTOM.cjs → GridViewImpl-LTYET77Q.cjs} +3 -3
- package/dist/GridViewImpl-LTYET77Q.cjs.map +1 -0
- package/dist/{WorkspaceTableView-J3C6VH4T.cjs → WorkspaceTableView-TEIRB6VJ.cjs} +11 -10
- package/dist/WorkspaceTableView-TEIRB6VJ.cjs.map +1 -0
- package/dist/agents/index.cjs +297 -297
- package/dist/{ai-IM4A23YT.cjs → ai-KBYNRNZ6.cjs} +28 -26
- package/dist/ai-KBYNRNZ6.cjs.map +1 -0
- package/dist/calls/connected/CallControls.d.ts +2 -0
- package/dist/calls/connected/CallControls.js +71 -9
- package/dist/calls/connected/CallControls.js.map +2 -2
- package/dist/calls/connected/ShareDocumentDialog.d.ts +14 -0
- package/dist/calls/connected/ShareDocumentDialog.js +77 -0
- package/dist/calls/connected/ShareDocumentDialog.js.map +7 -0
- package/dist/calls/index.cjs +121 -121
- package/dist/chat/index.cjs +9 -8
- package/dist/{chunk-T23UTIRI.cjs → chunk-2PZT3J34.cjs} +6 -6
- package/dist/{chunk-T23UTIRI.cjs.map → chunk-2PZT3J34.cjs.map} +1 -1
- package/dist/{chunk-SGYSDABK.cjs → chunk-2W5E62EY.cjs} +6 -6
- package/dist/{chunk-SGYSDABK.cjs.map → chunk-2W5E62EY.cjs.map} +1 -1
- package/dist/{chunk-TDO5UWXF.cjs → chunk-3SCNXNHI.cjs} +5 -5
- package/dist/{chunk-TDO5UWXF.cjs.map → chunk-3SCNXNHI.cjs.map} +1 -1
- package/dist/{chunk-KTQOGT2L.cjs → chunk-474GPLCM.cjs} +7 -7
- package/dist/{chunk-KTQOGT2L.cjs.map → chunk-474GPLCM.cjs.map} +1 -1
- package/dist/{chunk-TP5PGWIO.cjs → chunk-4IOYQLKG.cjs} +3 -3
- package/dist/{chunk-TP5PGWIO.cjs.map → chunk-4IOYQLKG.cjs.map} +1 -1
- package/dist/{chunk-NY3YUCOW.cjs → chunk-4NPCDS2X.cjs} +3 -3
- package/dist/{chunk-NY3YUCOW.cjs.map → chunk-4NPCDS2X.cjs.map} +1 -1
- package/dist/{chunk-HA66DHW6.cjs → chunk-4RBQ44RY.cjs} +28 -28
- package/dist/chunk-4RBQ44RY.cjs.map +1 -0
- package/dist/{chunk-BQ5RIWWT.cjs → chunk-4VZZWYEC.cjs} +3 -3
- package/dist/{chunk-BQ5RIWWT.cjs.map → chunk-4VZZWYEC.cjs.map} +1 -1
- package/dist/{chunk-BP3IJ34D.cjs → chunk-52KGMAO5.cjs} +15 -15
- package/dist/{chunk-BP3IJ34D.cjs.map → chunk-52KGMAO5.cjs.map} +1 -1
- package/dist/{chunk-5IZFSAEZ.cjs → chunk-5534FYXP.cjs} +4 -4
- package/dist/{chunk-5IZFSAEZ.cjs.map → chunk-5534FYXP.cjs.map} +1 -1
- package/dist/chunk-5GCCUXMT.cjs +63 -0
- package/dist/chunk-5GCCUXMT.cjs.map +1 -0
- package/dist/chunk-5LTIZ44D.cjs +95 -0
- package/dist/chunk-5LTIZ44D.cjs.map +1 -0
- package/dist/{chunk-DFBDQKGE.cjs → chunk-734NPQNR.cjs} +4 -4
- package/dist/{chunk-DFBDQKGE.cjs.map → chunk-734NPQNR.cjs.map} +1 -1
- package/dist/{chunk-X36UR4A7.cjs → chunk-7VUJGHMY.cjs} +323 -96
- package/dist/chunk-7VUJGHMY.cjs.map +1 -0
- package/dist/chunk-AFQTQC7A.cjs +35 -0
- package/dist/chunk-AFQTQC7A.cjs.map +1 -0
- package/dist/{chunk-YYSBWMDJ.cjs → chunk-AY6EZSZB.cjs} +4 -4
- package/dist/{chunk-YYSBWMDJ.cjs.map → chunk-AY6EZSZB.cjs.map} +1 -1
- package/dist/{chunk-BUVIBHFU.cjs → chunk-BVAT4EVC.cjs} +38 -38
- package/dist/chunk-BVAT4EVC.cjs.map +1 -0
- package/dist/{chunk-ECLUFKYR.cjs → chunk-C2OICDMI.cjs} +10 -10
- package/dist/{chunk-ECLUFKYR.cjs.map → chunk-C2OICDMI.cjs.map} +1 -1
- package/dist/{chunk-CPR6EHG7.cjs → chunk-DR2AH7JL.cjs} +179 -55
- package/dist/chunk-DR2AH7JL.cjs.map +1 -0
- package/dist/{chunk-NJCK6V6U.cjs → chunk-EATIFPKP.cjs} +4 -60
- package/dist/chunk-EATIFPKP.cjs.map +1 -0
- package/dist/{chunk-B3LZITVF.cjs → chunk-EHP6OH5D.cjs} +11 -451
- package/dist/chunk-EHP6OH5D.cjs.map +1 -0
- package/dist/{chunk-775S43W7.cjs → chunk-ENGL7P3I.cjs} +31 -31
- package/dist/{chunk-775S43W7.cjs.map → chunk-ENGL7P3I.cjs.map} +1 -1
- package/dist/{chunk-VZCPMXWC.cjs → chunk-FKFQCK3C.cjs} +4 -4
- package/dist/{chunk-VZCPMXWC.cjs.map → chunk-FKFQCK3C.cjs.map} +1 -1
- package/dist/{chunk-6UTKM5AB.cjs → chunk-GKVE5JGB.cjs} +76 -76
- package/dist/chunk-GKVE5JGB.cjs.map +1 -0
- package/dist/{chunk-Q6CLWOP2.cjs → chunk-GPX5VC57.cjs} +50 -50
- package/dist/{chunk-Q6CLWOP2.cjs.map → chunk-GPX5VC57.cjs.map} +1 -1
- package/dist/{chunk-WAV762GP.cjs → chunk-GQXPNIRE.cjs} +6 -6
- package/dist/{chunk-WAV762GP.cjs.map → chunk-GQXPNIRE.cjs.map} +1 -1
- package/dist/chunk-GX2EBMJW.cjs +133 -0
- package/dist/chunk-GX2EBMJW.cjs.map +1 -0
- package/dist/{chunk-7OPOPYV6.cjs → chunk-H5OLHP2U.cjs} +3 -3
- package/dist/{chunk-7OPOPYV6.cjs.map → chunk-H5OLHP2U.cjs.map} +1 -1
- package/dist/chunk-HYUKPHCT.cjs +66 -0
- package/dist/chunk-HYUKPHCT.cjs.map +1 -0
- package/dist/{chunk-NLSWDP42.cjs → chunk-JQLWKNJO.cjs} +22 -12
- package/dist/chunk-JQLWKNJO.cjs.map +1 -0
- package/dist/{chunk-CKCG4NDB.cjs → chunk-JZEYHDWJ.cjs} +75 -75
- package/dist/{chunk-CKCG4NDB.cjs.map → chunk-JZEYHDWJ.cjs.map} +1 -1
- package/dist/{chunk-PGJYD67F.cjs → chunk-KNGZZC4O.cjs} +7 -6
- package/dist/chunk-KNGZZC4O.cjs.map +1 -0
- package/dist/{chunk-W6INT5GS.cjs → chunk-KP5AITQ4.cjs} +10 -10
- package/dist/{chunk-W6INT5GS.cjs.map → chunk-KP5AITQ4.cjs.map} +1 -1
- package/dist/{chunk-YYPZOEED.cjs → chunk-LHWOKOMP.cjs} +23 -2
- package/dist/chunk-LHWOKOMP.cjs.map +1 -0
- package/dist/{chunk-WXUU3COI.cjs → chunk-MZ2KZXNU.cjs} +3 -3
- package/dist/{chunk-WXUU3COI.cjs.map → chunk-MZ2KZXNU.cjs.map} +1 -1
- package/dist/chunk-NAJN32MF.cjs +154 -0
- package/dist/chunk-NAJN32MF.cjs.map +1 -0
- package/dist/{chunk-557MJ4IH.cjs → chunk-NLOETJCB.cjs} +17 -154
- package/dist/chunk-NLOETJCB.cjs.map +1 -0
- package/dist/{chunk-4XJEHKVZ.cjs → chunk-PIYYBPHH.cjs} +4 -4
- package/dist/{chunk-4XJEHKVZ.cjs.map → chunk-PIYYBPHH.cjs.map} +1 -1
- package/dist/chunk-Q3XJUXID.cjs +4774 -0
- package/dist/chunk-Q3XJUXID.cjs.map +1 -0
- package/dist/{chunk-325GVZE6.cjs → chunk-Q6DQGGP4.cjs} +3 -3
- package/dist/{chunk-325GVZE6.cjs.map → chunk-Q6DQGGP4.cjs.map} +1 -1
- package/dist/chunk-QFXILJMJ.cjs +458 -0
- package/dist/chunk-QFXILJMJ.cjs.map +1 -0
- package/dist/{chunk-QQWHG3KF.cjs → chunk-RYVZDFVO.cjs} +5 -5
- package/dist/{chunk-QQWHG3KF.cjs.map → chunk-RYVZDFVO.cjs.map} +1 -1
- package/dist/{chunk-EOG6OT5I.cjs → chunk-TXP2N3DC.cjs} +4 -4
- package/dist/{chunk-EOG6OT5I.cjs.map → chunk-TXP2N3DC.cjs.map} +1 -1
- package/dist/{chunk-KXIRVKCJ.cjs → chunk-UUENH4BJ.cjs} +3 -3
- package/dist/{chunk-KXIRVKCJ.cjs.map → chunk-UUENH4BJ.cjs.map} +1 -1
- package/dist/chunk-VJ5ZLRBD.cjs +27 -0
- package/dist/chunk-VJ5ZLRBD.cjs.map +1 -0
- package/dist/{chunk-3GWWOYGS.cjs → chunk-W6B3RYTX.cjs} +4 -4
- package/dist/{chunk-3GWWOYGS.cjs.map → chunk-W6B3RYTX.cjs.map} +1 -1
- package/dist/chunk-WOOOMTTA.cjs +19 -0
- package/dist/chunk-WOOOMTTA.cjs.map +1 -0
- package/dist/{chunk-CJYWHUZR.cjs → chunk-XCKHOXRP.cjs} +4 -4
- package/dist/{chunk-CJYWHUZR.cjs.map → chunk-XCKHOXRP.cjs.map} +1 -1
- package/dist/{chunk-6WMMZLEV.cjs → chunk-XJEXFEWG.cjs} +2 -27
- package/dist/chunk-XJEXFEWG.cjs.map +1 -0
- package/dist/chunk-XK4TVJKD.cjs +73 -0
- package/dist/chunk-XK4TVJKD.cjs.map +1 -0
- package/dist/chunk-XTR26TNE.cjs +1358 -0
- package/dist/chunk-XTR26TNE.cjs.map +1 -0
- package/dist/{chunk-E7TE2WVT.cjs → chunk-ZVEW3JBT.cjs} +3 -3
- package/dist/{chunk-E7TE2WVT.cjs.map → chunk-ZVEW3JBT.cjs.map} +1 -1
- package/dist/collaboration/index.cjs +70 -70
- package/dist/components/ZoomSlider.d.ts +25 -0
- package/dist/components/ZoomSlider.js +59 -0
- package/dist/components/ZoomSlider.js.map +7 -0
- package/dist/connect/docx.cjs +20 -20
- package/dist/connect/index.cjs +1150 -1232
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/viewer.cjs +40 -34
- package/dist/connection/ai.d.ts +1 -1
- package/dist/connection/files/ConnectedNewFileMenu.d.ts +2 -1
- package/dist/connection/files/ConnectedNewFileMenu.js +9 -3
- package/dist/connection/files/ConnectedNewFileMenu.js.map +2 -2
- package/dist/connection/files/explorer/ConnectedFilesExplorer.js +1 -1
- package/dist/connection/files/explorer/ConnectedFilesExplorer.js.map +2 -2
- package/dist/connection/files/explorer/FileTiles.js +1 -1
- package/dist/connection/files/explorer/FileTiles.js.map +2 -2
- package/dist/connection/files/fields/documentField.js +1 -1
- package/dist/connection/files/fields/documentField.js.map +2 -2
- package/dist/connection/files/grid/documentColumns.js +1 -1
- package/dist/connection/files/grid/documentColumns.js.map +2 -2
- package/dist/connection/files/page/DocumentsFilterBarActions.js +17 -28
- package/dist/connection/files/page/DocumentsFilterBarActions.js.map +2 -2
- package/dist/connection/mail/useMailboxDefaults.js +1 -1
- package/dist/connection/mail/useMailboxDefaults.js.map +2 -2
- package/dist/connection/panels/useSessionPanelMode.js +3 -2
- package/dist/connection/panels/useSessionPanelMode.js.map +2 -2
- package/dist/connection/presentation/ClippingMediaViewer.d.ts +12 -0
- package/dist/connection/presentation/ClippingMediaViewer.js +153 -0
- package/dist/connection/presentation/ClippingMediaViewer.js.map +7 -0
- package/dist/connection/presentation/ClippingPdfViewer.d.ts +22 -0
- package/dist/connection/presentation/ClippingPdfViewer.js +75 -0
- package/dist/connection/presentation/ClippingPdfViewer.js.map +7 -0
- package/dist/connection/presentation/ConnectedPresentation.d.ts +12 -0
- package/dist/connection/presentation/ConnectedPresentation.js +100 -0
- package/dist/connection/presentation/ConnectedPresentation.js.map +7 -0
- package/dist/connection/presentation/ConnectedSlidesTab.d.ts +20 -0
- package/dist/connection/presentation/ConnectedSlidesTab.js +220 -0
- package/dist/connection/presentation/ConnectedSlidesTab.js.map +7 -0
- package/dist/connection/presentation/CropClipDialog.d.ts +11 -0
- package/dist/connection/presentation/CropClipDialog.js +86 -0
- package/dist/connection/presentation/CropClipDialog.js.map +7 -0
- package/dist/connection/presentation/GenerateTile.d.ts +4 -0
- package/dist/connection/presentation/GenerateTile.js +24 -0
- package/dist/connection/presentation/GenerateTile.js.map +7 -0
- package/dist/connection/presentation/LabelColumnMenu.d.ts +8 -0
- package/dist/connection/presentation/LabelColumnMenu.js +38 -0
- package/dist/connection/presentation/LabelColumnMenu.js.map +7 -0
- package/dist/connection/presentation/PresentationDialogs.d.ts +39 -0
- package/dist/connection/presentation/PresentationDialogs.js +295 -0
- package/dist/connection/presentation/PresentationDialogs.js.map +7 -0
- package/dist/connection/presentation/PresentationFileCard.d.ts +10 -0
- package/dist/connection/presentation/PresentationFileCard.js +35 -0
- package/dist/connection/presentation/PresentationFileCard.js.map +7 -0
- package/dist/connection/presentation/PresentationPill.d.ts +8 -0
- package/dist/connection/presentation/PresentationPill.js +44 -0
- package/dist/connection/presentation/PresentationPill.js.map +7 -0
- package/dist/connection/presentation/PresentationSlot.d.ts +7 -0
- package/dist/connection/presentation/PresentationSlot.js +35 -0
- package/dist/connection/presentation/PresentationSlot.js.map +7 -0
- package/dist/connection/presentation/requests.d.ts +16 -0
- package/dist/connection/presentation/requests.js +20 -0
- package/dist/connection/presentation/requests.js.map +7 -0
- package/dist/connection/presentation/useImageGeneration.d.ts +11 -0
- package/dist/connection/presentation/useImageGeneration.js +66 -0
- package/dist/connection/presentation/useImageGeneration.js.map +7 -0
- package/dist/connection/presentation/useLabelColumns.d.ts +15 -0
- package/dist/connection/presentation/useLabelColumns.js +33 -0
- package/dist/connection/presentation/useLabelColumns.js.map +7 -0
- package/dist/connection/presentation/usePresentationController.d.ts +15 -0
- package/dist/connection/presentation/usePresentationController.js +118 -0
- package/dist/connection/presentation/usePresentationController.js.map +7 -0
- package/dist/connection/presentation/usePresentationFiles.d.ts +44 -0
- package/dist/connection/presentation/usePresentationFiles.js +307 -0
- package/dist/connection/presentation/usePresentationFiles.js.map +7 -0
- package/dist/connection/presentation/useViewerClipping.d.ts +14 -0
- package/dist/connection/presentation/useViewerClipping.js +18 -0
- package/dist/connection/presentation/useViewerClipping.js.map +7 -0
- package/dist/connection/shell/ConnectedAppShell.js +5 -1
- package/dist/connection/shell/ConnectedAppShell.js.map +2 -2
- package/dist/connection/viewer/CleanViewControl.d.ts +8 -0
- package/dist/connection/viewer/CleanViewControl.js +76 -0
- package/dist/connection/viewer/CleanViewControl.js.map +7 -0
- package/dist/connection/viewer/ConnectedDocumentViewer.js +28 -29
- package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
- package/dist/connection/viewer/ViewerCropModal.d.ts +5 -0
- package/dist/connection/viewer/ViewerCropModal.js +22 -0
- package/dist/connection/viewer/ViewerCropModal.js.map +7 -0
- package/dist/connection/viewer/ViewerPdfPane.d.ts +3 -1
- package/dist/connection/viewer/ViewerPdfPane.js +37 -0
- package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
- package/dist/connection/viewer/drafts.js +6 -4
- package/dist/connection/viewer/drafts.js.map +2 -2
- package/dist/connection/viewer/shareDocument.d.ts +11 -0
- package/dist/connection/viewer/shareDocument.js +11 -0
- package/dist/connection/viewer/shareDocument.js.map +7 -0
- package/dist/connection/viewer/slidesTabChunk.d.ts +2 -0
- package/dist/connection/viewer/slidesTabChunk.js +9 -0
- package/dist/connection/viewer/slidesTabChunk.js.map +7 -0
- package/dist/connection/viewer/useCleanView.d.ts +14 -0
- package/dist/connection/viewer/useCleanView.js +29 -0
- package/dist/connection/viewer/useCleanView.js.map +7 -0
- package/dist/connection/viewer/useViewedDocument.d.ts +1 -0
- package/dist/connection/viewer/useViewedDocument.js +9 -1
- package/dist/connection/viewer/useViewedDocument.js.map +2 -2
- package/dist/connection/viewer/useViewerTabs.js +18 -4
- package/dist/connection/viewer/useViewerTabs.js.map +2 -2
- package/dist/connection/workflows/ConnectedWorkflowStart.d.ts +14 -2
- package/dist/connection/workflows/ConnectedWorkflowStart.js +5 -2
- package/dist/connection/workflows/ConnectedWorkflowStart.js.map +2 -2
- package/dist/dashboards/index.cjs +1 -1
- package/dist/databases/index.cjs +49 -49
- package/dist/document-tools/DocumentToolButtons.d.ts +2 -0
- package/dist/document-tools/DocumentToolButtons.js +22 -1
- package/dist/document-tools/DocumentToolButtons.js.map +2 -2
- package/dist/document-tools/index.cjs +16 -12
- package/dist/document-tools/index.d.ts +1 -1
- package/dist/document-tools/index.js +2 -0
- package/dist/document-tools/index.js.map +2 -2
- package/dist/embed/index.cjs +41 -39
- package/dist/files/GridViewImpl.js +1 -1
- package/dist/files/GridViewImpl.js.map +2 -2
- package/dist/files/ViewerChrome.d.ts +5 -1
- package/dist/files/ViewerChrome.js +16 -6
- package/dist/files/ViewerChrome.js.map +2 -2
- package/dist/files/index.cjs +225 -225
- package/dist/files/navigator/DocumentSearchList.js +1 -1
- package/dist/files/navigator/DocumentSearchList.js.map +2 -2
- package/dist/index.cjs +1666 -1664
- package/dist/index.cjs.map +1 -1
- package/dist/presentation/BoxActionBar.d.ts +11 -0
- package/dist/presentation/BoxActionBar.js +182 -0
- package/dist/presentation/BoxActionBar.js.map +7 -0
- package/dist/presentation/ClipActionBar.d.ts +26 -0
- package/dist/presentation/ClipActionBar.js +103 -0
- package/dist/presentation/ClipActionBar.js.map +7 -0
- package/dist/presentation/ClipCaptureOverlay.d.ts +14 -0
- package/dist/presentation/ClipCaptureOverlay.js +69 -0
- package/dist/presentation/ClipCaptureOverlay.js.map +7 -0
- package/dist/presentation/ClipImage.d.ts +21 -0
- package/dist/presentation/ClipImage.js +119 -0
- package/dist/presentation/ClipImage.js.map +7 -0
- package/dist/presentation/ClipTray.d.ts +11 -0
- package/dist/presentation/ClipTray.js +152 -0
- package/dist/presentation/ClipTray.js.map +7 -0
- package/dist/presentation/ClipViewControls.d.ts +11 -0
- package/dist/presentation/ClipViewControls.js +142 -0
- package/dist/presentation/ClipViewControls.js.map +7 -0
- package/dist/presentation/DesignMenu.d.ts +8 -0
- package/dist/presentation/DesignMenu.js +199 -0
- package/dist/presentation/DesignMenu.js.map +7 -0
- package/dist/presentation/LayoutMenu.d.ts +17 -0
- package/dist/presentation/LayoutMenu.js +122 -0
- package/dist/presentation/LayoutMenu.js.map +7 -0
- package/dist/presentation/MediaClip.d.ts +15 -0
- package/dist/presentation/MediaClip.js +67 -0
- package/dist/presentation/MediaClip.js.map +7 -0
- package/dist/presentation/Notice.d.ts +6 -0
- package/dist/presentation/Notice.js +43 -0
- package/dist/presentation/Notice.js.map +7 -0
- package/dist/presentation/PresentationStage.d.ts +32 -0
- package/dist/presentation/PresentationStage.js +232 -0
- package/dist/presentation/PresentationStage.js.map +7 -0
- package/dist/presentation/PresenterView.d.ts +16 -0
- package/dist/presentation/PresenterView.js +69 -0
- package/dist/presentation/PresenterView.js.map +7 -0
- package/dist/presentation/SlideDecor.d.ts +25 -0
- package/dist/presentation/SlideDecor.js +189 -0
- package/dist/presentation/SlideDecor.js.map +7 -0
- package/dist/presentation/SlidesEditor.d.ts +25 -0
- package/dist/presentation/SlidesEditor.js +359 -0
- package/dist/presentation/SlidesEditor.js.map +7 -0
- package/dist/presentation/StageBox.d.ts +30 -0
- package/dist/presentation/StageBox.js +281 -0
- package/dist/presentation/StageBox.js.map +7 -0
- package/dist/presentation/StageItem.d.ts +37 -0
- package/dist/presentation/StageItem.js +211 -0
- package/dist/presentation/StageItem.js.map +7 -0
- package/dist/presentation/box-style.d.ts +6 -0
- package/dist/presentation/box-style.js +19 -0
- package/dist/presentation/box-style.js.map +7 -0
- package/dist/presentation/boxes.d.ts +105 -0
- package/dist/presentation/boxes.js +103 -0
- package/dist/presentation/boxes.js.map +7 -0
- package/dist/presentation/draw-boxes.d.ts +8 -0
- package/dist/presentation/draw-boxes.js +130 -0
- package/dist/presentation/draw-boxes.js.map +7 -0
- package/dist/presentation/export-boxes.d.ts +10 -0
- package/dist/presentation/export-boxes.js +74 -0
- package/dist/presentation/export-boxes.js.map +7 -0
- package/dist/presentation/export-pptx.d.ts +16 -0
- package/dist/presentation/export-pptx.js +194 -0
- package/dist/presentation/export-pptx.js.map +7 -0
- package/dist/presentation/import-pptx.d.ts +35 -0
- package/dist/presentation/import-pptx.js +659 -0
- package/dist/presentation/import-pptx.js.map +7 -0
- package/dist/presentation/merge-outside-edits.d.ts +12 -0
- package/dist/presentation/merge-outside-edits.js +35 -0
- package/dist/presentation/merge-outside-edits.js.map +7 -0
- package/dist/presentation/model.d.ts +201 -0
- package/dist/presentation/model.js +271 -0
- package/dist/presentation/model.js.map +7 -0
- package/dist/presentation/panel-id.d.ts +34 -0
- package/dist/presentation/panel-id.js +24 -0
- package/dist/presentation/panel-id.js.map +7 -0
- package/dist/presentation/persistence.d.ts +121 -0
- package/dist/presentation/persistence.js +141 -0
- package/dist/presentation/persistence.js.map +7 -0
- package/dist/presentation/pptx-data.d.ts +22 -0
- package/dist/presentation/pptx-data.js +83 -0
- package/dist/presentation/pptx-data.js.map +7 -0
- package/dist/presentation/pptx-xml.d.ts +90 -0
- package/dist/presentation/pptx-xml.js +333 -0
- package/dist/presentation/pptx-xml.js.map +7 -0
- package/dist/presentation/render-slides.d.ts +58 -0
- package/dist/presentation/render-slides.js +309 -0
- package/dist/presentation/render-slides.js.map +7 -0
- package/dist/presentation/saved-boxes.d.ts +11 -0
- package/dist/presentation/saved-boxes.js +80 -0
- package/dist/presentation/saved-boxes.js.map +7 -0
- package/dist/presentation/slide-layout.d.ts +54 -0
- package/dist/presentation/slide-layout.js +117 -0
- package/dist/presentation/slide-layout.js.map +7 -0
- package/dist/presentation/stage-videos.d.ts +5 -0
- package/dist/presentation/stage-videos.js +19 -0
- package/dist/presentation/stage-videos.js.map +7 -0
- package/dist/presentation/store.d.ts +203 -0
- package/dist/presentation/store.js +429 -0
- package/dist/presentation/store.js.map +7 -0
- package/dist/presentation/theme.d.ts +102 -0
- package/dist/presentation/theme.js +276 -0
- package/dist/presentation/theme.js.map +7 -0
- package/dist/presentation/useClipDrag.d.ts +26 -0
- package/dist/presentation/useClipDrag.js +65 -0
- package/dist/presentation/useClipDrag.js.map +7 -0
- package/dist/presentation/useObjectUrl.d.ts +6 -0
- package/dist/presentation/useObjectUrl.js +15 -0
- package/dist/presentation/useObjectUrl.js.map +7 -0
- package/dist/presentation/usePresenterKeys.d.ts +13 -0
- package/dist/presentation/usePresenterKeys.js +62 -0
- package/dist/presentation/usePresenterKeys.js.map +7 -0
- package/dist/settings/index.cjs +151 -150
- package/dist/shell/PanelPortal.js +1 -0
- package/dist/shell/PanelPortal.js.map +2 -2
- package/dist/shell/index.cjs +112 -110
- package/dist/shell/panel-windows.d.ts +2 -0
- package/dist/shell/panel-windows.js +7 -2
- package/dist/shell/panel-windows.js.map +2 -2
- package/dist/studio/index.cjs +28 -26
- package/dist/studio/index.cjs.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/workflow-canvas/index.cjs +55 -54
- package/dist/workflow-canvas/index.cjs.map +1 -1
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +6 -5
- package/dist/ConnectedCallDock-WER7R222.cjs.map +0 -1
- package/dist/DocumentReviewCard-BPIAJJED.cjs.map +0 -1
- package/dist/FilesViewerDialog-67WK3TZC.cjs.map +0 -1
- package/dist/GridViewImpl-ZMJJWTOM.cjs.map +0 -1
- package/dist/WorkspaceTableView-J3C6VH4T.cjs.map +0 -1
- package/dist/ai-IM4A23YT.cjs.map +0 -1
- package/dist/chunk-557MJ4IH.cjs.map +0 -1
- package/dist/chunk-6UTKM5AB.cjs.map +0 -1
- package/dist/chunk-6WMMZLEV.cjs.map +0 -1
- package/dist/chunk-B3LZITVF.cjs.map +0 -1
- package/dist/chunk-BUVIBHFU.cjs.map +0 -1
- package/dist/chunk-CPR6EHG7.cjs.map +0 -1
- package/dist/chunk-HA66DHW6.cjs.map +0 -1
- package/dist/chunk-NJCK6V6U.cjs.map +0 -1
- package/dist/chunk-NLSWDP42.cjs.map +0 -1
- package/dist/chunk-PGJYD67F.cjs.map +0 -1
- package/dist/chunk-X36UR4A7.cjs.map +0 -1
- package/dist/chunk-YYPZOEED.cjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/files/GridViewImpl.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * GridView \u2014 a flexible AG Grid presentational core.\n *\n * Pure and app-agnostic: it owns no global state and pulls in no store. Column\n * state persistence (order / width / visibility / sort / filter) is exposed as a\n * controlled/uncontrolled prop pair \u2014 `gridState` (initial state, read once at\n * mount) and `onGridStateChange` (called whenever AG Grid's state changes). An\n * app wires those to wherever it keeps the state (Zustand, localStorage, a URL,\n * a server) via a thin adapter; the core stays decoupled.\n *\n * Themed here (colours/fonts/borders via the host CSS variables, so it inherits the host's\n * light/dark theme). The structural helper classes (cell-numeric, multiline clamp, scrollbars,\n * row kebabs) live in `@arbidocs/blocks/grid.css`, which the consuming app imports globally.\n */\n\nimport React, { useRef, useCallback, useMemo, useEffect } from 'react'\nimport { AgGridReact } from 'ag-grid-react'\nimport {\n ColDef,\n GridOptions,\n GridApi,\n IRowNode,\n GridState,\n themeQuartz,\n CellValueChangedEvent,\n ColumnVisibleEvent,\n GridReadyEvent,\n RowClickedEvent,\n} from 'ag-grid-community'\nimport { AllCommunityModule } from 'ag-grid-community'\nimport { BREAKPOINT_QUERIES, useMediaQuery } from '../lib/use-media-query'\nimport { watchGridTestIds } from './grid-test-ids'\n\n// Create the custom ARBI theme using themeQuartz\n// Colours reference the host CSS variables (hsl(var(--token))), so dark mode follows the app.\n// This enables dark mode support and consistent theming\nconst cssVar = (name: string, alpha?: number): string =>\n alpha === undefined ? `hsl(var(--${name}))` : `hsl(var(--${name}) / ${alpha})`\n\nconst arbiTheme = themeQuartz.withParams({\n // Match TagTable: a plain canvas, muted header, fine row borders and a rounded frame.\n // Every colour is a host CSS variable, so light/dark follow the app with no .dark overrides.\n backgroundColor: cssVar('background'),\n foregroundColor: cssVar('foreground'),\n borderColor: cssVar('border'),\n headerBackgroundColor: cssVar('muted', 0.4),\n headerTextColor: cssVar('foreground'),\n oddRowBackgroundColor: cssVar('background'),\n rowHoverColor: cssVar('muted', 0.6),\n // Checkbox-selected rows: a light accent tint. A row opened elsewhere (e.g. the viewer) may take\n // the full accent, so the two states stay distinguishable.\n selectedRowBackgroundColor: cssVar('accent', 0.6),\n rangeSelectionBackgroundColor: cssVar('accent'),\n accentColor: cssVar('primary'),\n inputFocusBorder: { color: cssVar('primary') },\n headerColumnBorder: false,\n // Keep the header as quiet as TagTable; reveal resize handles on hover (see grid.css).\n headerColumnResizeHandleColor: 'transparent',\n headerColumnResizeHandleHeight: '40%',\n headerColumnResizeHandleWidth: 1,\n\n // Font settings \u2014 inherit the host app's font. A googleFont here never\n // loaded under the apps' CSP, so every grid silently fell back to the\n // browser's default SERIF and read as unstyled.\n fontFamily: 'inherit',\n fontSize: 14,\n headerFontSize: 14,\n headerFontWeight: 500,\n\n // Sizing\n headerHeight: 37,\n rowHeight: 40,\n cellHorizontalPadding: 12,\n\n // Borders - structural settings only.\n // Row border is a real hairline in the theme border colour (not hardcoded\n // white, which was invisible on the light-mode background and wrong in dark\n // mode) so adjacent rows are clearly separated \u2014 important now that rows can\n // be tall and multi-line (e.g. the Abstract column).\n rowBorder: { style: 'solid', width: 1, color: 'hsl(var(--border))' },\n columnBorder: false, // Row hairlines only\n wrapperBorder: { style: 'solid', width: 1, color: cssVar('border') },\n\n // Use the same radius token as TagTable's rounded-lg container.\n borderRadius: 'var(--radius-lg, 8px)',\n wrapperBorderRadius: 'var(--radius-lg, 8px)',\n checkboxBorderRadius: 2, // Keep checkboxes square\n})\n\n// Selection configuration\nexport interface GridViewSelection<T> {\n mode: 'single' | 'multiple'\n selected: T[]\n onSelectionChange: (items: T[]) => void\n /**\n * Keep the grid's ticked rows equal to `selected` after mount (default: `selected` only seeds the\n * grid). For a host that changes the selection itself, e.g. ticking a parent ticks its sub-tasks.\n */\n controlled?: boolean\n}\n\n// Empty state configuration\nexport interface GridViewEmptyState {\n icon?: React.ReactNode\n title?: string\n message?: string\n action?: React.ReactNode\n}\n\n/** Grid events GridView binds itself; `gridOptions` may not override them. */\ntype GridViewOwnedEvent =\n | 'onGridReady'\n | 'onFirstDataRendered'\n | 'onModelUpdated'\n | 'onSelectionChanged'\n | 'onCellValueChanged'\n | 'onRowClicked'\n | 'onStateUpdated'\n | 'onColumnVisible'\n\n// Generic props to make this grid reusable with different data types\nexport interface GridViewProps<T> {\n // Core data\n items: T[]\n // Column configuration\n columnDefs: ColDef<T>[]\n // Row identity function\n getItemId: (item: T) => string\n // Selection handling\n selection?: GridViewSelection<T>\n // Empty state\n emptyState?: GridViewEmptyState\n // Loading state\n isLoading?: boolean\n loadingMessage?: string\n // Grid options. The events GridView handles itself are left out: they are spread over its own\n // handlers, so passing one here silently replaced them (an `onGridReady` here left the grid api\n // unset and selection never reached `selection.onSelectionChange`). Use the dedicated props.\n gridOptions?: Partial<Omit<GridOptions<T>, GridViewOwnedEvent>>\n // Grid initialization\n onGridReady?: (params: { api: GridApi<T> }) => void\n // Cell value changes\n onCellValueChanged?: (event: CellValueChangedEvent<T>) => void\n // Row click handler\n onRowClick?: (item: T) => void\n // State persistence.\n // The core is decoupled from any store: when `persistState` is on it seeds\n // AG Grid from `gridState` (read once at mount) and reports every subsequent\n // state change through `onGridStateChange`. An app-adapter wires these to its\n // own store. `gridId` is retained as an opaque identity hint for adapters\n // (the core itself does not read it).\n persistState?: boolean\n gridId?: string\n // Persisted column/sort/filter state to restore at mount (controlled input).\n gridState?: GridState\n // Called whenever AG Grid's state changes so an adapter can persist it.\n onGridStateChange?: (state: GridState) => void\n // Initial visible columns (applied when no saved state exists)\n initialVisibleColumns?: string[]\n // Basic styling\n className?: string\n height?: string | number\n // Per-instance row height. Applied via the theme (not just gridOptions) so the\n // theme's calculated line-height tracks it and cell content stays vertically\n // centered. Fixed height \u2014 keeps row virtualization on the fast path.\n rowHeight?: number\n testId?: string\n // Pinned rows\n pinnedBottomRowData?: T[]\n pinnedTopRowData?: T[]\n // Pagination (disabled by default)\n pagination?: boolean\n paginationPageSizeSelector?: number[]\n // Test-id hooks: the grid owns its row/cell DOM, so ids are stamped onto it after render.\n // `getRowTestId` names a row; `getCellTestId` a cell (by colId). Without them AG Grid's own\n // `row-id` / `col-id` attributes are still there to select by.\n getRowTestId?: (item: T) => string\n getCellTestId?: (colId: string, item: T) => string\n // Force empty-state UI even when items.length > 0.\n // Used when rows are present but all hidden by an external filter.\n showEmpty?: boolean\n}\n\n/** Minimum row height on coarse pointers: 44px touch target + the 1px row border + breathing room. */\nconst TOUCH_ROW_HEIGHT = 52\n\nexport function GridView<T>({\n items,\n columnDefs,\n getItemId,\n selection,\n emptyState,\n isLoading = false,\n loadingMessage = 'Loading...',\n gridOptions,\n onGridReady,\n onCellValueChanged,\n onRowClick,\n persistState = false,\n gridState,\n onGridStateChange,\n initialVisibleColumns,\n className = 'w-full',\n height = 500,\n rowHeight: rowHeightProp,\n testId = 'grid-view',\n pinnedBottomRowData,\n pinnedTopRowData,\n pagination = false,\n paginationPageSizeSelector,\n getRowTestId,\n getCellTestId,\n showEmpty,\n}: GridViewProps<T>) {\n // Reference to the grid API\n const gridApiRef = useRef<GridApi<T> | null>(null)\n\n // On touch screens rows grow to a 44px-hit-area-friendly height: AG Grid clips cell content\n // (pills, filename buttons, avatar chips) to the row, so a taller hit area needs a taller row.\n const isCoarsePointer = useMediaQuery(BREAKPOINT_QUERIES.coarsePointer)\n const rowHeight = isCoarsePointer\n ? Math.max(rowHeightProp ?? gridOptions?.rowHeight ?? 40, TOUCH_ROW_HEIGHT)\n : rowHeightProp\n\n // Initial row height, captured once so it can live in the (stable) default\n // grid options. rowHeight is NOT passed as a reactive prop \u2014 that would make\n // the AgGridReact wrapper re-process grid options on every change and snap\n // manually-resized columns back to their colDef widths. Subsequent changes are\n // applied imperatively (see effect below).\n const initialRowHeightRef = useRef(rowHeight)\n\n // Persisted state to seed the grid with \u2014 captured once at mount so a reactive\n // `gridState` prop (e.g. an adapter re-reading its store each render) can never\n // re-initialise the grid mid-session. Mirrors AG Grid's own initialState,\n // which is read once.\n const initialGridStateRef = useRef(gridState)\n\n // Get initial state for the grid (read once at mount)\n const initialState = useMemo(() => {\n if (!persistState) return undefined\n return initialGridStateRef.current\n }, [persistState])\n\n // Save grid state via the adapter using modern AG Grid state API\n const saveGridState = useCallback(() => {\n if (!persistState || !onGridStateChange || !gridApiRef.current) return\n\n // Use AG Grid's comprehensive state API to capture complete state\n // This includes: filters, sort, column order, column visibility, column widths, etc.\n const state = gridApiRef.current.getState()\n\n onGridStateChange(state)\n }, [persistState, onGridStateChange])\n\n // Ensure selection column is visible after grid initialization\n const ensureSelectionColumnVisible = useCallback(() => {\n if (!gridApiRef.current || !selection?.mode) return\n\n // IMPORTANT: Force selection column to be visible after state restoration\n // This ensures even old saved states don't hide the selection column\n // Also handles case where selection column is completely missing from state\n const currentState = gridApiRef.current.getColumnState()\n const selectionColumn = currentState.find((col) => col.colId === 'ag-Grid-SelectionColumn')\n const selectionColumnIndex = currentState.findIndex(\n (col) => col.colId === 'ag-Grid-SelectionColumn'\n )\n\n // Fix if column is hidden OR missing entirely OR not in first position\n if (!selectionColumn || selectionColumn.hide || selectionColumnIndex !== 0) {\n // Use setColumnsVisible for more reliable visibility control\n gridApiRef.current.setColumnsVisible(['ag-Grid-SelectionColumn'], true)\n\n // Also apply state to ensure proper width\n gridApiRef.current.applyColumnState({\n state: [\n {\n colId: 'ag-Grid-SelectionColumn',\n hide: false,\n width: selectionColumn?.width || 48,\n pinned: null, // Ensure not pinned in wrong position\n },\n ],\n defaultState: { hide: undefined },\n applyOrder: false,\n })\n\n // Move selection column to first position if it's not there\n if (selectionColumnIndex !== 0) {\n gridApiRef.current.moveColumns(['ag-Grid-SelectionColumn'], 0)\n }\n }\n }, [selection?.mode])\n\n // Stamp host test ids onto AG Grid's rows and cells (it virtualises, so keep watching).\n const containerRef = useRef<HTMLDivElement>(null)\n const itemsRef = useRef(items)\n itemsRef.current = items\n const getItemIdRef = useRef(getItemId)\n getItemIdRef.current = getItemId\n const hasTestIdHooks = Boolean(getRowTestId || getCellTestId)\n useEffect(() => {\n const root = containerRef.current\n if (!root || !hasTestIdHooks) return\n return watchGridTestIds(\n root,\n () => new Map(itemsRef.current.map((item) => [getItemIdRef.current(item), item])),\n { getRowTestId, getCellTestId }\n )\n }, [hasTestIdHooks, getRowTestId, getCellTestId, isLoading])\n\n // Row identity, stable for the grid's life (through the latest `getItemId`): an inline\n // `getItemId` used to change it, and with it the default options and their `defaultColDef`, on\n // every host render; AG Grid then re-applied the columns and recreated every header's label.\n const getRowId = useCallback((params: { data: T }) => getItemIdRef.current(params.data), [])\n\n // Refs for selection \u2014 avoids handleGridReady/handleSelectionChanged recreating\n // when selection object changes (which happens on every selectionConfig recompute)\n const selectionRef = useRef(selection)\n selectionRef.current = selection\n\n const onSelectionChangeRef = useRef(selection?.onSelectionChange)\n onSelectionChangeRef.current = selection?.onSelectionChange\n\n const syncingSelectionRef = useRef(false)\n\n const handleSelectionChanged = useCallback(() => {\n if (syncingSelectionRef.current) return\n if (!onSelectionChangeRef.current || !gridApiRef.current) return\n\n const selectedNodes = gridApiRef.current.getSelectedNodes()\n const selectedData = selectedNodes\n .map((node) => node.data)\n .filter((item): item is T => item !== undefined)\n\n onSelectionChangeRef.current(selectedData)\n }, [])\n\n // Handle row clicks\n // A controlled selection: tick and untick rows so the grid shows exactly `selection.selected`.\n const controlledSelected = selection?.controlled ? selection.selected : undefined\n useEffect(() => {\n const api = gridApiRef.current\n if (!api || api.isDestroyed() || !controlledSelected) return\n const wanted = new Set(controlledSelected.map(getItemId))\n const tick: IRowNode<T>[] = []\n const untick: IRowNode<T>[] = []\n api.forEachNode((node) => {\n if (!node.data) return\n const want = wanted.has(getItemId(node.data))\n if (want && !node.isSelected()) tick.push(node)\n else if (!want && node.isSelected()) untick.push(node)\n })\n syncingSelectionRef.current = true\n try {\n if (tick.length) api.setNodesSelected({ nodes: tick, newValue: true, source: 'api' })\n if (untick.length) api.setNodesSelected({ nodes: untick, newValue: false, source: 'api' })\n } finally {\n syncingSelectionRef.current = false\n }\n }, [controlledSelected, getItemId])\n\n const handleRowClicked = useCallback(\n (event: RowClickedEvent<T>) => {\n if (!onRowClick || !event.data) return\n // Don't fire when the click originated from an interactive element inside the cell\n // (e.g. action buttons). AG Grid fires rowClicked regardless of DOM stopPropagation.\n const target = event.event?.target as HTMLElement | null\n if (target?.closest('button, input, a, select, textarea, [role=\"button\"]')) return\n onRowClick(event.data)\n },\n [onRowClick]\n )\n\n // The visibility the user actually intends, per colId. AG Grid re-processes the\n // column definitions on some React re-renders even when the `columnDefs`\n // reference is unchanged, and that reset restores each colDef's `hide` \u2014 so a\n // column the user turned on (e.g. via a fields menu) silently disappears the\n // next time the host re-renders (opening an editor, selecting a row, \u2026). We\n // remember the intended visibility and restore it whenever such a reset fires.\n // A Map (not a Set of hidden ids) so a genuinely NEW column from a real\n // columnDefs change \u2014 one we've never seen \u2014 is left at its colDef default\n // rather than force-shown.\n const desiredHiddenRef = useRef<Map<string, boolean> | null>(null)\n\n const snapshotDesiredHidden = useCallback(() => {\n const api = gridApiRef.current\n if (!api) return\n desiredHiddenRef.current = new Map(api.getColumnState().map((c) => [c.colId, !!c.hide]))\n }, [])\n\n // Handle grid ready\n const handleGridReady = useCallback(\n (event: GridReadyEvent<T>) => {\n gridApiRef.current = event.api\n\n // Apply initial visible columns when no saved state exists\n // This prevents showing all columns by default for new users\n if (!initialState && initialVisibleColumns?.length) {\n const currentState = event.api.getColumnState()\n const stateMap = new Map(currentState.map((col) => [col.colId, col]))\n const visibleSet = new Set(initialVisibleColumns)\n\n // Build ordered state: selection column first (always visible), then visible columns, then hidden\n const selectionCol = stateMap.get('ag-Grid-SelectionColumn')\n const orderedState = [\n // Selection column first - ALWAYS visible, create if not in state\n selectionCol\n ? { ...selectionCol, hide: false }\n : { colId: 'ag-Grid-SelectionColumn', hide: false, width: 48 },\n // Visible columns in specified order\n ...initialVisibleColumns\n .filter((colId) => colId !== 'ag-Grid-SelectionColumn') // Don't duplicate selection column\n .map((colId) => {\n const col = stateMap.get(colId)\n return col ? { ...col, hide: false } : undefined\n }),\n // Hidden columns (everything else)\n ...currentState\n .filter((col) => col.colId !== 'ag-Grid-SelectionColumn' && !visibleSet.has(col.colId))\n .map((col) => ({ ...col, hide: true })),\n ].filter((col): col is NonNullable<typeof col> => col !== undefined)\n\n event.api.applyColumnState({ state: orderedState, applyOrder: true })\n }\n\n // When restoring persisted state, detect columns from columnDefs that\n // aren't in the saved state (e.g. newly added columns) and append them.\n // AG Grid's maintainColumnOrder adds them but may place them inconsistently;\n // this ensures they appear as hidden at the end so the navigator picks them up.\n if (initialState && initialVisibleColumns?.length) {\n const currentState = event.api.getColumnState()\n const savedColIds = new Set(\n initialState.columnOrder?.orderedColIds ?? currentState.map((c) => c.colId)\n )\n const newCols = currentState.filter(\n (col) => !savedColIds.has(col.colId) && col.colId !== 'ag-Grid-SelectionColumn'\n )\n if (newCols.length > 0) {\n // Make new columns visible if they're in the default visible set\n const defaultVisible = new Set(initialVisibleColumns)\n event.api.applyColumnState({\n state: newCols.map((col) => ({\n ...col,\n hide: !defaultVisible.has(col.colId),\n })),\n })\n }\n }\n\n // Ensure selection column is visible (in case saved state hides it)\n ensureSelectionColumnVisible()\n\n // Seed the intended column visibility from the state AG Grid settled on\n // (colDefs + restored persisted state) so a later colDef-driven reset can\n // be undone rather than silently hiding a user-shown column.\n snapshotDesiredHidden()\n\n // Call the provided onGridReady callback\n if (onGridReady) {\n onGridReady({ api: event.api })\n }\n\n // Restore selection state if needed (read from ref to keep callback stable)\n const sel = selectionRef.current\n if (sel && sel.selected.length > 0) {\n const selectedIds = new Set(sel.selected.map(getItemId))\n event.api.forEachNode((node) => {\n if (node.data && selectedIds.has(getItemId(node.data))) {\n node.setSelected(true)\n }\n })\n }\n },\n [\n onGridReady,\n getItemId,\n ensureSelectionColumnVisible,\n snapshotDesiredHidden,\n initialState,\n initialVisibleColumns,\n ]\n )\n\n // Undo AG Grid's colDef-driven visibility reset; record genuine user changes.\n const handleColumnVisible = useCallback(\n (event: ColumnVisibleEvent<T>) => {\n const api = gridApiRef.current\n if (!api) return\n // A columnDefs re-apply reports `gridOptionsChanged`; a real toggle reports\n // an interaction source (api, toolPanelUi, columnMenu, \u2026).\n if (event.source === 'gridOptionsChanged') {\n const desired = desiredHiddenRef.current\n if (!desired) return\n // Only correct columns we've seen before (in the snapshot); a brand-new\n // column keeps its colDef default.\n const fixes = api\n .getColumnState()\n .filter(\n (c) =>\n c.colId !== 'ag-Grid-SelectionColumn' &&\n desired.has(c.colId) &&\n desired.get(c.colId) !== !!c.hide\n )\n .map((c) => ({ colId: c.colId, hide: desired.get(c.colId) }))\n if (fixes.length) api.applyColumnState({ state: fixes })\n } else if (desiredHiddenRef.current && event.visible !== undefined && event.columns) {\n // Genuine change \u2014 this is now the intended visibility. Taken from the event itself: the\n // column state can still report the previous visibility while it is being dispatched\n // (seen for a change made before the grid's first data render).\n for (const column of event.columns) {\n desiredHiddenRef.current.set(column.getColId(), !event.visible)\n }\n } else {\n // A mixed change (applied column state): read the whole visibility back.\n snapshotDesiredHidden()\n }\n },\n [snapshotDesiredHidden]\n )\n\n // Handle first data rendered - no auto-sizing, let flex columns handle it\n const handleFirstDataRendered = useCallback(() => {\n // Columns with flex will auto-fill, columns with width stay fixed\n // Also ensure selection column is visible as a backup (handles timing issues with initialState)\n ensureSelectionColumnVisible()\n // Seed the intended visibility from the state AG Grid settled on (colDefs +\n // any restored persisted state), so later resets can be undone.\n snapshotDesiredHidden()\n }, [ensureSelectionColumnVisible, snapshotDesiredHidden])\n\n // Track when AG Grid processes row updates\n const handleModelUpdated = useCallback(() => {\n // AG Grid handles model updates internally\n }, [])\n\n // Track row data changes for AG Grid updates\n const prevItemsRef = useRef<T[]>([])\n useEffect(() => {\n prevItemsRef.current = items\n }, [items])\n\n // Handle state updates - save state when it changes (modern AG Grid approach)\n const handleStateUpdated = useCallback(() => {\n saveGridState()\n }, [saveGridState])\n\n // Removed problematic useEffect that caused unnecessary re-renders\n // AG Grid handles selection internally, only sync on initial load\n\n // Default grid options with minimal settings - memoized to prevent re-renders\n const defaultOptions: GridOptions<T> = useMemo(() => {\n return {\n // Initial row height (stable \u2014 captured once). Live changes go through the\n // imperative effect, not this option, to avoid column-state churn.\n rowHeight: initialRowHeightRef.current,\n suppressMenuHide: true, // Prevent hiding columns since we don't have enterprise sidebar\n maintainColumnOrder: true, // Preserve column order when columns are added/removed\n\n // Row virtualization: Render rows as needed for performance\n // rowBuffer renders extra rows above/below viewport for smoother scrolling\n rowBuffer: 10, // Render 10 extra rows above/below viewport for smooth scrolling\n suppressColumnVirtualisation: false, // Keep column virtualization enabled\n suppressRowVirtualisation: false, // ENABLE row virtualization - only render visible rows\n animateRows: false, // Disable row animations\n suppressColumnMoveAnimation: true, // Disable column move/resize animations\n\n // Efficient updates with React Query cache\n // getRowId enables change detection - grid only re-renders changed rows\n // Works perfectly with React Query's cache updates\n getRowId: getRowId,\n\n rowSelection: selection?.mode\n ? {\n mode: selection.mode === 'single' ? 'singleRow' : 'multiRow',\n selectAll: 'filtered', // Header checkbox selects all filtered rows (across all pages)\n // In multi-row mode, only checkboxes should toggle selection (clicking row body would replace selection)\n enableClickSelection: selection.mode === 'single',\n checkboxes: true,\n headerCheckbox: selection.mode === 'multiple',\n }\n : undefined,\n selectionColumnDef: selection?.mode\n ? {\n sortable: selection.mode === 'multiple',\n width: 48,\n lockVisible: true, // Cannot be hidden\n suppressMovable: true, // Cannot be moved\n }\n : undefined,\n // Use normal layout for better performance - autoHeight causes forced reflows\n domLayout: 'normal',\n // Stop editing when clicking outside the cell/grid\n stopEditingWhenCellsLoseFocus: true,\n // Additional performance optimizations\n suppressCellFocus: true, // Don't focus cells on click (faster)\n suppressRowHoverHighlight: true, // Disable hover highlight - reduces DOM manipulation during scroll\n suppressScrollOnNewData: true, // Don't scroll when data updates\n suppressAggFuncInHeader: true, // Don't show aggregation functions (faster)\n // Tooltip UX: the AG Grid default show-delay is 2 s which hurts\n // discoverability for cells where tooltips carry the \"reveal full\n // content\" affordance for non-editable users. 300 ms is snappy\n // without being accidental. tooltipInteraction lets users hover\n // onto the tooltip itself (e.g. to select / copy long text).\n // These are AG Grid's native tooltip controls \u2014 no React / Radix\n // provider involved, zero per-row cost; tooltip DOM is created on\n // demand when hover-delay elapses and destroyed on mouseout.\n tooltipShowDelay: 300,\n tooltipHideDelay: 4000,\n tooltipInteraction: true,\n // Pagination (disabled by default)\n pagination,\n paginationPageSizeSelector,\n defaultColDef: {\n sortable: true,\n resizable: true,\n unSortIcon: false, // Sort glyph only on the sorted column (every header carrying one was noise)\n sortingOrder: ['asc', 'desc', null], // 3-way sorting: asc \u2192 desc \u2192 unsorted (AG Grid default)\n wrapText: false, // Disable text wrapping for cleaner display\n autoHeight: false, // Use fixed row height from theme\n wrapHeaderText: false, // Disable header text wrapping for cleaner look\n autoHeaderHeight: false, // Fixed header height\n filterParams: {\n maxNumConditions: 1,\n buttons: ['reset'],\n },\n },\n }\n }, [selection?.mode, getRowId, pagination, paginationPageSizeSelector])\n\n // Combine default options with passed options - memoized to prevent re-renders\n const combinedOptions = useMemo(\n () => ({ ...defaultOptions, ...gridOptions }),\n [defaultOptions, gridOptions]\n )\n\n // Apply fixed height for better performance \u2014 autoHeight causes forced\n // reflows by measuring all rows, avoid it.\n //\n // Also derive the geometry the wrapping multiline columns (.cell-multiline \u2014\n // Abstract, Author, custom text fields) need so their overflow clip lands on\n // a WHOLE-line boundary (never mid-line, which reads as a half-line\n // \"bleeding\" into the neighbouring row). All computed once here per\n // row-height change and handed to CSS as variables \u2014 zero per-row cost on the\n // million-row grid:\n // --multiline-line-clamp : whole number of lines that fit \u2014 drives the CSS\n // line-clamp that hides overflow lines entirely.\n // --multiline-pad-y : vertical cell padding, shrunk on very short rows so\n // at least one whole line always fits.\n // --multiline-max-h : cap of exactly N whole lines + TOP padding + borders.\n // Deliberately excludes the bottom padding: AG Grid\n // forces cell height, so overflow clips at the\n // padding-box edge and any bottom padding becomes a\n // window onto the next (clamped-away) line. Ending the\n // box right at line N's bottom puts the clip on the\n // line boundary; the row supplies the visual gap below.\n const containerStyle = useMemo(() => {\n const style: React.CSSProperties = { height }\n if (rowHeight) {\n const LINE_PX = 14 * 1.35 // grid font-size \u00D7 multiline line-height (18.9px)\n const BORDER = 2 // multiline cell top + bottom border (1px each, border-box)\n const PREFERRED_PAD = 16 // preferred total vertical padding (8px top + 8px bottom)\n // Don't let padding eat the room a single line needs on short rows.\n const padTotal = Math.max(0, Math.min(PREFERRED_PAD, rowHeight - BORDER - LINE_PX))\n const lines = Math.max(1, Math.floor((rowHeight - BORDER - padTotal) / LINE_PX))\n const vars = style as Record<string, string | number>\n vars['--multiline-line-clamp'] = `${lines}`\n vars['--multiline-pad-y'] = `${padTotal / 2}px`\n vars['--multiline-max-h'] = `${lines * LINE_PX + padTotal / 2 + BORDER}px`\n }\n return style\n }, [height, rowHeight])\n\n // Apply rowHeight changes imperatively via the grid option (not the theme \u2014\n // recreating the theme would re-initialise the grid). This only re-lays-out\n // rows; columns, row virtualization, and the transaction bus are untouched.\n useEffect(() => {\n const api = gridApiRef.current\n if (!api || api.isDestroyed() || !rowHeight) return\n api.setGridOption('rowHeight', rowHeight)\n api.resetRowHeights()\n }, [rowHeight])\n\n const containerClassName = useMemo(() => {\n const baseClass = className || ''\n // Height-adjustable grids vertically center cell content (CSS) so a\n // one-line cell or a lone pill sits in the middle of the row, and multi-line\n // text (e.g. Abstract) is balanced top-to-bottom \u2014 flagged here, applied in\n // grid.css.\n const alignClass = rowHeight ? 'ag-cells-centered' : ''\n return [baseClass, alignClass].filter(Boolean).join(' ')\n }, [className, rowHeight])\n\n // Show loading state \u2014 grey skeleton rows so the page transition feels instant\n if (isLoading) {\n const skeletonRowCount = 12\n return (\n <div\n data-testid={`${testId}-loading`}\n className={`${containerClassName} overflow-hidden rounded-lg border border-border`}\n style={containerStyle}\n aria-busy=\"true\"\n aria-label={loadingMessage}\n >\n {/* Header skeleton */}\n <div className=\"flex h-[37px] items-center gap-4 border-b border-border bg-muted/40 px-3\">\n <div className=\"h-3 w-6 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-32 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-24 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-20 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-28 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-16 rounded bg-muted animate-pulse ml-auto\" />\n </div>\n {/* Row skeletons */}\n {Array.from({ length: skeletonRowCount }).map((_, rowIdx) => (\n <div key={rowIdx} className=\"flex h-10 items-center gap-4 border-b border-border px-3\">\n <div className=\"h-4 w-4 rounded-sm bg-muted/70 animate-pulse\" />\n <div\n className=\"h-3 rounded bg-muted/70 animate-pulse\"\n style={{ width: `${20 + ((rowIdx * 17) % 40)}%` }}\n />\n <div\n className=\"h-3 rounded bg-muted/60 animate-pulse\"\n style={{ width: `${8 + ((rowIdx * 11) % 12)}%` }}\n />\n <div\n className=\"h-3 rounded bg-muted/60 animate-pulse\"\n style={{ width: `${6 + ((rowIdx * 7) % 10)}%` }}\n />\n <div\n className=\"h-3 rounded bg-muted/50 animate-pulse ml-auto\"\n style={{ width: `${5 + ((rowIdx * 5) % 8)}%` }}\n />\n </div>\n ))}\n </div>\n )\n }\n\n // Show empty state\n // showEmpty lets callers force this UI (e.g. when an external filter hid\n // every row but the underlying items array is non-empty).\n if ((showEmpty ?? items.length === 0) && emptyState) {\n return (\n <div\n data-testid={`${testId}-empty`}\n // Capped by its container (a landscape phone is shorter than 24rem) and scrollable, with the\n // content centred by auto margins so a tall one still starts at the top.\n className=\"flex h-96 max-h-full flex-col items-center overflow-y-auto p-6 text-center\"\n >\n <div className=\"my-auto flex flex-col items-center\">\n {emptyState.icon && (\n <div className=\"text-muted-foreground/60 mb-4\">{emptyState.icon}</div>\n )}\n {emptyState.title && <h3 className=\"text-xl font-medium mb-2\">{emptyState.title}</h3>}\n {emptyState.message && (\n <p className=\"text-muted-foreground mb-6 max-w-md\">{emptyState.message}</p>\n )}\n {emptyState.action}\n </div>\n </div>\n )\n }\n\n return (\n <div\n ref={containerRef}\n className={containerClassName}\n style={containerStyle}\n data-testid={testId}\n >\n <AgGridReact\n theme={arbiTheme}\n modules={[AllCommunityModule]}\n columnDefs={columnDefs}\n rowData={items}\n pinnedBottomRowData={pinnedBottomRowData}\n pinnedTopRowData={pinnedTopRowData}\n getRowId={getRowId}\n initialState={initialState}\n {...combinedOptions}\n // The events GridView binds itself come after the host's options, so an options object\n // that names one anyway (it is typed out, but untyped objects slip through) cannot replace\n // them: a no-op `onColumnVisible` there used to switch off the visibility guard.\n onGridReady={handleGridReady}\n onFirstDataRendered={handleFirstDataRendered}\n onModelUpdated={handleModelUpdated}\n onSelectionChanged={handleSelectionChanged}\n onCellValueChanged={onCellValueChanged}\n onRowClicked={handleRowClicked}\n onStateUpdated={handleStateUpdated}\n onColumnVisible={handleColumnVisible}\n />\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": ";AAgsBQ,SACE,KADF;AAjrBR,SAAgB,QAAQ,aAAa,SAAS,iBAAiB;AAC/D,SAAS,mBAAmB;AAC5B;AAAA,EAME;AAAA,OAKK;AACP,SAAS,0BAA0B;AACnC,SAAS,oBAAoB,qBAAqB;AAClD,SAAS,wBAAwB;AAKjC,MAAM,SAAS,CAAC,MAAc,UAC5B,UAAU,SAAY,aAAa,IAAI,OAAO,aAAa,IAAI,OAAO,KAAK;AAE7E,MAAM,YAAY,YAAY,WAAW;AAAA;AAAA;AAAA,EAGvC,iBAAiB,OAAO,YAAY;AAAA,EACpC,iBAAiB,OAAO,YAAY;AAAA,EACpC,aAAa,OAAO,QAAQ;AAAA,EAC5B,uBAAuB,OAAO,SAAS,GAAG;AAAA,EAC1C,iBAAiB,OAAO,YAAY;AAAA,EACpC,uBAAuB,OAAO,YAAY;AAAA,EAC1C,eAAe,OAAO,SAAS,GAAG;AAAA;AAAA;AAAA,EAGlC,4BAA4B,OAAO,UAAU,GAAG;AAAA,EAChD,+BAA+B,OAAO,QAAQ;AAAA,EAC9C,aAAa,OAAO,SAAS;AAAA,EAC7B,kBAAkB,EAAE,OAAO,OAAO,SAAS,EAAE;AAAA,EAC7C,oBAAoB;AAAA;AAAA,EAEpB,+BAA+B;AAAA,EAC/B,gCAAgC;AAAA,EAChC,+BAA+B;AAAA;AAAA;AAAA;AAAA,EAK/B,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,kBAAkB;AAAA;AAAA,EAGlB,cAAc;AAAA,EACd,WAAW;AAAA,EACX,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvB,WAAW,EAAE,OAAO,SAAS,OAAO,GAAG,OAAO,qBAAqB;AAAA,EACnE,cAAc;AAAA;AAAA,EACd,eAAe,EAAE,OAAO,SAAS,OAAO,GAAG,OAAO,OAAO,QAAQ,EAAE;AAAA;AAAA,EAGnE,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,sBAAsB;AAAA;AACxB,CAAC;AAiGD,MAAM,mBAAmB;AAElB,SAAS,SAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AAEnB,QAAM,aAAa,OAA0B,IAAI;AAIjD,QAAM,kBAAkB,cAAc,mBAAmB,aAAa;AACtE,QAAM,YAAY,kBACd,KAAK,IAAI,iBAAiB,aAAa,aAAa,IAAI,gBAAgB,IACxE;AAOJ,QAAM,sBAAsB,OAAO,SAAS;AAM5C,QAAM,sBAAsB,OAAO,SAAS;AAG5C,QAAM,eAAe,QAAQ,MAAM;AACjC,QAAI,CAAC,aAAc,QAAO;AAC1B,WAAO,oBAAoB;AAAA,EAC7B,GAAG,CAAC,YAAY,CAAC;AAGjB,QAAM,gBAAgB,YAAY,MAAM;AACtC,QAAI,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,WAAW,QAAS;AAIhE,UAAM,QAAQ,WAAW,QAAQ,SAAS;AAE1C,sBAAkB,KAAK;AAAA,EACzB,GAAG,CAAC,cAAc,iBAAiB,CAAC;AAGpC,QAAM,+BAA+B,YAAY,MAAM;AACrD,QAAI,CAAC,WAAW,WAAW,CAAC,WAAW,KAAM;AAK7C,UAAM,eAAe,WAAW,QAAQ,eAAe;AACvD,UAAM,kBAAkB,aAAa,KAAK,CAAC,QAAQ,IAAI,UAAU,yBAAyB;AAC1F,UAAM,uBAAuB,aAAa;AAAA,MACxC,CAAC,QAAQ,IAAI,UAAU;AAAA,IACzB;AAGA,QAAI,CAAC,mBAAmB,gBAAgB,QAAQ,yBAAyB,GAAG;AAE1E,iBAAW,QAAQ,kBAAkB,CAAC,yBAAyB,GAAG,IAAI;AAGtE,iBAAW,QAAQ,iBAAiB;AAAA,QAClC,OAAO;AAAA,UACL;AAAA,YACE,OAAO;AAAA,YACP,MAAM;AAAA,YACN,OAAO,iBAAiB,SAAS;AAAA,YACjC,QAAQ;AAAA;AAAA,UACV;AAAA,QACF;AAAA,QACA,cAAc,EAAE,MAAM,OAAU;AAAA,QAChC,YAAY;AAAA,MACd,CAAC;AAGD,UAAI,yBAAyB,GAAG;AAC9B,mBAAW,QAAQ,YAAY,CAAC,yBAAyB,GAAG,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,EACF,GAAG,CAAC,WAAW,IAAI,CAAC;AAGpB,QAAM,eAAe,OAAuB,IAAI;AAChD,QAAM,WAAW,OAAO,KAAK;AAC7B,WAAS,UAAU;AACnB,QAAM,eAAe,OAAO,SAAS;AACrC,eAAa,UAAU;AACvB,QAAM,iBAAiB,QAAQ,gBAAgB,aAAa;AAC5D,YAAU,MAAM;AACd,UAAM,OAAO,aAAa;AAC1B,QAAI,CAAC,QAAQ,CAAC,eAAgB;AAC9B,WAAO;AAAA,MACL;AAAA,MACA,MAAM,IAAI,IAAI,SAAS,QAAQ,IAAI,CAAC,SAAS,CAAC,aAAa,QAAQ,IAAI,GAAG,IAAI,CAAC,CAAC;AAAA,MAChF,EAAE,cAAc,cAAc;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,gBAAgB,cAAc,eAAe,SAAS,CAAC;AAK3D,QAAM,WAAW,YAAY,CAAC,WAAwB,aAAa,QAAQ,OAAO,IAAI,GAAG,CAAC,CAAC;AAI3F,QAAM,eAAe,OAAO,SAAS;AACrC,eAAa,UAAU;AAEvB,QAAM,uBAAuB,OAAO,WAAW,iBAAiB;AAChE,uBAAqB,UAAU,WAAW;AAE1C,QAAM,sBAAsB,OAAO,KAAK;AAExC,QAAM,yBAAyB,YAAY,MAAM;AAC/C,QAAI,oBAAoB,QAAS;AACjC,QAAI,CAAC,qBAAqB,WAAW,CAAC,WAAW,QAAS;AAE1D,UAAM,gBAAgB,WAAW,QAAQ,iBAAiB;AAC1D,UAAM,eAAe,cAClB,IAAI,CAAC,SAAS,KAAK,IAAI,EACvB,OAAO,CAAC,SAAoB,SAAS,MAAS;AAEjD,yBAAqB,QAAQ,YAAY;AAAA,EAC3C,GAAG,CAAC,CAAC;AAIL,QAAM,qBAAqB,WAAW,aAAa,UAAU,WAAW;AACxE,YAAU,MAAM;AACd,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,OAAO,IAAI,YAAY,KAAK,CAAC,mBAAoB;AACtD,UAAM,SAAS,IAAI,IAAI,mBAAmB,IAAI,SAAS,CAAC;AACxD,UAAM,OAAsB,CAAC;AAC7B,UAAM,SAAwB,CAAC;AAC/B,QAAI,YAAY,CAAC,SAAS;AACxB,UAAI,CAAC,KAAK,KAAM;AAChB,YAAM,OAAO,OAAO,IAAI,UAAU,KAAK,IAAI,CAAC;AAC5C,UAAI,QAAQ,CAAC,KAAK,WAAW,EAAG,MAAK,KAAK,IAAI;AAAA,eACrC,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO,KAAK,IAAI;AAAA,IACvD,CAAC;AACD,wBAAoB,UAAU;AAC9B,QAAI;AACF,UAAI,KAAK,OAAQ,KAAI,iBAAiB,EAAE,OAAO,MAAM,UAAU,MAAM,QAAQ,MAAM,CAAC;AACpF,UAAI,OAAO,OAAQ,KAAI,iBAAiB,EAAE,OAAO,QAAQ,UAAU,OAAO,QAAQ,MAAM,CAAC;AAAA,IAC3F,UAAE;AACA,0BAAoB,UAAU;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,oBAAoB,SAAS,CAAC;AAElC,QAAM,mBAAmB;AAAA,IACvB,CAAC,UAA8B;AAC7B,UAAI,CAAC,cAAc,CAAC,MAAM,KAAM;AAGhC,YAAM,SAAS,MAAM,OAAO;AAC5B,UAAI,QAAQ,QAAQ,qDAAqD,EAAG;AAC5E,iBAAW,MAAM,IAAI;AAAA,IACvB;AAAA,IACA,CAAC,UAAU;AAAA,EACb;AAWA,QAAM,mBAAmB,OAAoC,IAAI;AAEjE,QAAM,wBAAwB,YAAY,MAAM;AAC9C,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAK;AACV,qBAAiB,UAAU,IAAI,IAAI,IAAI,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAAA,EACzF,GAAG,CAAC,CAAC;AAGL,QAAM,kBAAkB;AAAA,IACtB,CAAC,UAA6B;AAC5B,iBAAW,UAAU,MAAM;AAI3B,UAAI,CAAC,gBAAgB,uBAAuB,QAAQ;AAClD,cAAM,eAAe,MAAM,IAAI,eAAe;AAC9C,cAAM,WAAW,IAAI,IAAI,aAAa,IAAI,CAAC,QAAQ,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;AACpE,cAAM,aAAa,IAAI,IAAI,qBAAqB;AAGhD,cAAM,eAAe,SAAS,IAAI,yBAAyB;AAC3D,cAAM,eAAe;AAAA;AAAA,UAEnB,eACI,EAAE,GAAG,cAAc,MAAM,MAAM,IAC/B,EAAE,OAAO,2BAA2B,MAAM,OAAO,OAAO,GAAG;AAAA;AAAA,UAE/D,GAAG,sBACA,OAAO,CAAC,UAAU,UAAU,yBAAyB,EACrD,IAAI,CAAC,UAAU;AACd,kBAAM,MAAM,SAAS,IAAI,KAAK;AAC9B,mBAAO,MAAM,EAAE,GAAG,KAAK,MAAM,MAAM,IAAI;AAAA,UACzC,CAAC;AAAA;AAAA,UAEH,GAAG,aACA,OAAO,CAAC,QAAQ,IAAI,UAAU,6BAA6B,CAAC,WAAW,IAAI,IAAI,KAAK,CAAC,EACrF,IAAI,CAAC,SAAS,EAAE,GAAG,KAAK,MAAM,KAAK,EAAE;AAAA,QAC1C,EAAE,OAAO,CAAC,QAAwC,QAAQ,MAAS;AAEnE,cAAM,IAAI,iBAAiB,EAAE,OAAO,cAAc,YAAY,KAAK,CAAC;AAAA,MACtE;AAMA,UAAI,gBAAgB,uBAAuB,QAAQ;AACjD,cAAM,eAAe,MAAM,IAAI,eAAe;AAC9C,cAAM,cAAc,IAAI;AAAA,UACtB,aAAa,aAAa,iBAAiB,aAAa,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,QAC5E;AACA,cAAM,UAAU,aAAa;AAAA,UAC3B,CAAC,QAAQ,CAAC,YAAY,IAAI,IAAI,KAAK,KAAK,IAAI,UAAU;AAAA,QACxD;AACA,YAAI,QAAQ,SAAS,GAAG;AAEtB,gBAAM,iBAAiB,IAAI,IAAI,qBAAqB;AACpD,gBAAM,IAAI,iBAAiB;AAAA,YACzB,OAAO,QAAQ,IAAI,CAAC,SAAS;AAAA,cAC3B,GAAG;AAAA,cACH,MAAM,CAAC,eAAe,IAAI,IAAI,KAAK;AAAA,YACrC,EAAE;AAAA,UACJ,CAAC;AAAA,QACH;AAAA,MACF;AAGA,mCAA6B;AAK7B,4BAAsB;AAGtB,UAAI,aAAa;AACf,oBAAY,EAAE,KAAK,MAAM,IAAI,CAAC;AAAA,MAChC;AAGA,YAAM,MAAM,aAAa;AACzB,UAAI,OAAO,IAAI,SAAS,SAAS,GAAG;AAClC,cAAM,cAAc,IAAI,IAAI,IAAI,SAAS,IAAI,SAAS,CAAC;AACvD,cAAM,IAAI,YAAY,CAAC,SAAS;AAC9B,cAAI,KAAK,QAAQ,YAAY,IAAI,UAAU,KAAK,IAAI,CAAC,GAAG;AACtD,iBAAK,YAAY,IAAI;AAAA,UACvB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,sBAAsB;AAAA,IAC1B,CAAC,UAAiC;AAChC,YAAM,MAAM,WAAW;AACvB,UAAI,CAAC,IAAK;AAGV,UAAI,MAAM,WAAW,sBAAsB;AACzC,cAAM,UAAU,iBAAiB;AACjC,YAAI,CAAC,QAAS;AAGd,cAAM,QAAQ,IACX,eAAe,EACf;AAAA,UACC,CAAC,MACC,EAAE,UAAU,6BACZ,QAAQ,IAAI,EAAE,KAAK,KACnB,QAAQ,IAAI,EAAE,KAAK,MAAM,CAAC,CAAC,EAAE;AAAA,QACjC,EACC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,MAAM,QAAQ,IAAI,EAAE,KAAK,EAAE,EAAE;AAC9D,YAAI,MAAM,OAAQ,KAAI,iBAAiB,EAAE,OAAO,MAAM,CAAC;AAAA,MACzD,WAAW,iBAAiB,WAAW,MAAM,YAAY,UAAa,MAAM,SAAS;AAInF,mBAAW,UAAU,MAAM,SAAS;AAClC,2BAAiB,QAAQ,IAAI,OAAO,SAAS,GAAG,CAAC,MAAM,OAAO;AAAA,QAChE;AAAA,MACF,OAAO;AAEL,8BAAsB;AAAA,MACxB;AAAA,IACF;AAAA,IACA,CAAC,qBAAqB;AAAA,EACxB;AAGA,QAAM,0BAA0B,YAAY,MAAM;AAGhD,iCAA6B;AAG7B,0BAAsB;AAAA,EACxB,GAAG,CAAC,8BAA8B,qBAAqB,CAAC;AAGxD,QAAM,qBAAqB,YAAY,MAAM;AAAA,EAE7C,GAAG,CAAC,CAAC;AAGL,QAAM,eAAe,OAAY,CAAC,CAAC;AACnC,YAAU,MAAM;AACd,iBAAa,UAAU;AAAA,EACzB,GAAG,CAAC,KAAK,CAAC;AAGV,QAAM,qBAAqB,YAAY,MAAM;AAC3C,kBAAc;AAAA,EAChB,GAAG,CAAC,aAAa,CAAC;AAMlB,QAAM,iBAAiC,QAAQ,MAAM;AACnD,WAAO;AAAA;AAAA;AAAA,MAGL,WAAW,oBAAoB;AAAA,MAC/B,kBAAkB;AAAA;AAAA,MAClB,qBAAqB;AAAA;AAAA;AAAA;AAAA,MAIrB,WAAW;AAAA;AAAA,MACX,8BAA8B;AAAA;AAAA,MAC9B,2BAA2B;AAAA;AAAA,MAC3B,aAAa;AAAA;AAAA,MACb,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA,MAK7B;AAAA,MAEA,cAAc,WAAW,OACrB;AAAA,QACE,MAAM,UAAU,SAAS,WAAW,cAAc;AAAA,QAClD,WAAW;AAAA;AAAA;AAAA,QAEX,sBAAsB,UAAU,SAAS;AAAA,QACzC,YAAY;AAAA,QACZ,gBAAgB,UAAU,SAAS;AAAA,MACrC,IACA;AAAA,MACJ,oBAAoB,WAAW,OAC3B;AAAA,QACE,UAAU,UAAU,SAAS;AAAA,QAC7B,OAAO;AAAA,QACP,aAAa;AAAA;AAAA,QACb,iBAAiB;AAAA;AAAA,MACnB,IACA;AAAA;AAAA,MAEJ,WAAW;AAAA;AAAA,MAEX,+BAA+B;AAAA;AAAA,MAE/B,mBAAmB;AAAA;AAAA,MACnB,2BAA2B;AAAA;AAAA,MAC3B,yBAAyB;AAAA;AAAA,MACzB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASzB,kBAAkB;AAAA,MAClB,kBAAkB;AAAA,MAClB,oBAAoB;AAAA;AAAA,MAEpB;AAAA,MACA;AAAA,MACA,eAAe;AAAA,QACb,UAAU;AAAA,QACV,WAAW;AAAA,QACX,YAAY;AAAA;AAAA,QACZ,cAAc,CAAC,OAAO,QAAQ,IAAI;AAAA;AAAA,QAClC,UAAU;AAAA;AAAA,QACV,YAAY;AAAA;AAAA,QACZ,gBAAgB;AAAA;AAAA,QAChB,kBAAkB;AAAA;AAAA,QAClB,cAAc;AAAA,UACZ,kBAAkB;AAAA,UAClB,SAAS,CAAC,OAAO;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,WAAW,MAAM,UAAU,YAAY,0BAA0B,CAAC;AAGtE,QAAM,kBAAkB;AAAA,IACtB,OAAO,EAAE,GAAG,gBAAgB,GAAG,YAAY;AAAA,IAC3C,CAAC,gBAAgB,WAAW;AAAA,EAC9B;AAsBA,QAAM,iBAAiB,QAAQ,MAAM;AACnC,UAAM,QAA6B,EAAE,OAAO;AAC5C,QAAI,WAAW;AACb,YAAM,UAAU,KAAK;AACrB,YAAM,SAAS;AACf,YAAM,gBAAgB;AAEtB,YAAM,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,eAAe,YAAY,SAAS,OAAO,CAAC;AAClF,YAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,OAAO,YAAY,SAAS,YAAY,OAAO,CAAC;AAC/E,YAAM,OAAO;AACb,WAAK,wBAAwB,IAAI,GAAG,KAAK;AACzC,WAAK,mBAAmB,IAAI,GAAG,WAAW,CAAC;AAC3C,WAAK,mBAAmB,IAAI,GAAG,QAAQ,UAAU,WAAW,IAAI,MAAM;AAAA,IACxE;AACA,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,SAAS,CAAC;AAKtB,YAAU,MAAM;AACd,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,OAAO,IAAI,YAAY,KAAK,CAAC,UAAW;AAC7C,QAAI,cAAc,aAAa,SAAS;AACxC,QAAI,gBAAgB;AAAA,EACtB,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,qBAAqB,QAAQ,MAAM;AACvC,UAAM,YAAY,aAAa;AAK/B,UAAM,aAAa,YAAY,sBAAsB;AACrD,WAAO,CAAC,WAAW,UAAU,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,EACzD,GAAG,CAAC,WAAW,SAAS,CAAC;AAGzB,MAAI,WAAW;AACb,UAAM,mBAAmB;AACzB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,eAAa,GAAG,MAAM;AAAA,QACtB,WAAW,GAAG,kBAAkB;AAAA,QAChC,OAAO;AAAA,QACP,aAAU;AAAA,QACV,cAAY;AAAA,QAGZ;AAAA,+BAAC,SAAI,WAAU,4EACb;AAAA,gCAAC,SAAI,WAAU,0CAAyC;AAAA,YACxD,oBAAC,SAAI,WAAU,2CAA0C;AAAA,YACzD,oBAAC,SAAI,WAAU,2CAA0C;AAAA,YACzD,oBAAC,SAAI,WAAU,2CAA0C;AAAA,YACzD,oBAAC,SAAI,WAAU,2CAA0C;AAAA,YACzD,oBAAC,SAAI,WAAU,mDAAkD;AAAA,aACnE;AAAA,UAEC,MAAM,KAAK,EAAE,QAAQ,iBAAiB,CAAC,EAAE,IAAI,CAAC,GAAG,WAChD,qBAAC,SAAiB,WAAU,4DAC1B;AAAA,gCAAC,SAAI,WAAU,gDAA+C;AAAA,YAC9D;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO,EAAE,OAAO,GAAG,KAAO,SAAS,KAAM,EAAG,IAAI;AAAA;AAAA,YAClD;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO,EAAE,OAAO,GAAG,IAAM,SAAS,KAAM,EAAG,IAAI;AAAA;AAAA,YACjD;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO,EAAE,OAAO,GAAG,IAAM,SAAS,IAAK,EAAG,IAAI;AAAA;AAAA,YAChD;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO,EAAE,OAAO,GAAG,IAAM,SAAS,IAAK,CAAE,IAAI;AAAA;AAAA,YAC/C;AAAA,eAjBQ,MAkBV,CACD;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AAKA,OAAK,aAAa,MAAM,WAAW,MAAM,YAAY;AACnD,WACE;AAAA,MAAC;AAAA;AAAA,QACC,eAAa,GAAG,MAAM;AAAA,QAGtB,WAAU;AAAA,QAEV,+BAAC,SAAI,WAAU,sCACZ;AAAA,qBAAW,QACV,oBAAC,SAAI,WAAU,iCAAiC,qBAAW,MAAK;AAAA,UAEjE,WAAW,SAAS,oBAAC,QAAG,WAAU,4BAA4B,qBAAW,OAAM;AAAA,UAC/E,WAAW,WACV,oBAAC,OAAE,WAAU,uCAAuC,qBAAW,SAAQ;AAAA,UAExE,WAAW;AAAA,WACd;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW;AAAA,MACX,OAAO;AAAA,MACP,eAAa;AAAA,MAEb;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,SAAS,CAAC,kBAAkB;AAAA,UAC5B;AAAA,UACA,SAAS;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACC,GAAG;AAAA,UAIJ,aAAa;AAAA,UACb,qBAAqB;AAAA,UACrB,gBAAgB;AAAA,UAChB,oBAAoB;AAAA,UACpB;AAAA,UACA,cAAc;AAAA,UACd,gBAAgB;AAAA,UAChB,iBAAiB;AAAA;AAAA,MACnB;AAAA;AAAA,EACF;AAEJ;",
|
|
4
|
+
"sourcesContent": ["/**\n * GridView \u2014 a flexible AG Grid presentational core.\n *\n * Pure and app-agnostic: it owns no global state and pulls in no store. Column\n * state persistence (order / width / visibility / sort / filter) is exposed as a\n * controlled/uncontrolled prop pair \u2014 `gridState` (initial state, read once at\n * mount) and `onGridStateChange` (called whenever AG Grid's state changes). An\n * app wires those to wherever it keeps the state (Zustand, localStorage, a URL,\n * a server) via a thin adapter; the core stays decoupled.\n *\n * Themed here (colours/fonts/borders via the host CSS variables, so it inherits the host's\n * light/dark theme). The structural helper classes (cell-numeric, multiline clamp, scrollbars,\n * row kebabs) live in `@arbidocs/blocks/grid.css`, which the consuming app imports globally.\n */\n\nimport React, { useRef, useCallback, useMemo, useEffect } from 'react'\nimport { AgGridReact } from 'ag-grid-react'\nimport {\n ColDef,\n GridOptions,\n GridApi,\n IRowNode,\n GridState,\n themeQuartz,\n CellValueChangedEvent,\n ColumnVisibleEvent,\n GridReadyEvent,\n RowClickedEvent,\n} from 'ag-grid-community'\nimport { AllCommunityModule } from 'ag-grid-community'\nimport { BREAKPOINT_QUERIES, useMediaQuery } from '../lib/use-media-query'\nimport { watchGridTestIds } from './grid-test-ids'\n\n// Create the custom ARBI theme using themeQuartz\n// Colours reference the host CSS variables (hsl(var(--token))), so dark mode follows the app.\n// This enables dark mode support and consistent theming\nconst cssVar = (name: string, alpha?: number): string =>\n alpha === undefined ? `hsl(var(--${name}))` : `hsl(var(--${name}) / ${alpha})`\n\nconst arbiTheme = themeQuartz.withParams({\n // Match TagTable: a plain canvas, muted header, fine row borders and a rounded frame.\n // Every colour is a host CSS variable, so light/dark follow the app with no .dark overrides.\n backgroundColor: cssVar('background'),\n foregroundColor: cssVar('foreground'),\n borderColor: cssVar('border'),\n headerBackgroundColor: cssVar('muted', 0.4),\n headerTextColor: cssVar('foreground'),\n oddRowBackgroundColor: cssVar('background'),\n rowHoverColor: cssVar('muted', 0.6),\n // Checkbox-selected rows: a light accent tint. A row opened elsewhere (e.g. the viewer) may take\n // the full accent, so the two states stay distinguishable.\n selectedRowBackgroundColor: cssVar('accent', 0.6),\n rangeSelectionBackgroundColor: cssVar('accent'),\n accentColor: cssVar('primary'),\n inputFocusBorder: { color: cssVar('primary') },\n headerColumnBorder: false,\n // Keep the header as quiet as TagTable; reveal resize handles on hover (see grid.css).\n headerColumnResizeHandleColor: 'transparent',\n headerColumnResizeHandleHeight: '40%',\n headerColumnResizeHandleWidth: 1,\n\n // Font settings \u2014 inherit the host app's font. A googleFont here never\n // loaded under the apps' CSP, so every grid silently fell back to the\n // browser's default SERIF and read as unstyled.\n fontFamily: 'inherit',\n fontSize: 14,\n headerFontSize: 14,\n headerFontWeight: 500,\n\n // Sizing\n headerHeight: 37,\n rowHeight: 40,\n cellHorizontalPadding: 12,\n\n // Borders - structural settings only.\n // Row border is a real hairline in the theme border colour (not hardcoded\n // white, which was invisible on the light-mode background and wrong in dark\n // mode) so adjacent rows are clearly separated \u2014 important now that rows can\n // be tall and multi-line (e.g. the Abstract column).\n rowBorder: { style: 'solid', width: 1, color: 'hsl(var(--border))' },\n columnBorder: false, // Row hairlines only\n wrapperBorder: { style: 'solid', width: 1, color: cssVar('border') },\n\n // Use the same radius token as TagTable's rounded-lg container.\n borderRadius: 'var(--radius-lg, 8px)',\n wrapperBorderRadius: 'var(--radius-lg, 8px)',\n checkboxBorderRadius: 2, // Keep checkboxes square\n})\n\n// Selection configuration\nexport interface GridViewSelection<T> {\n mode: 'single' | 'multiple'\n selected: T[]\n onSelectionChange: (items: T[]) => void\n /**\n * Keep the grid's ticked rows equal to `selected` after mount (default: `selected` only seeds the\n * grid). For a host that changes the selection itself, e.g. ticking a parent ticks its sub-tasks.\n */\n controlled?: boolean\n}\n\n// Empty state configuration\nexport interface GridViewEmptyState {\n icon?: React.ReactNode\n title?: string\n message?: string\n action?: React.ReactNode\n}\n\n/** Grid events GridView binds itself; `gridOptions` may not override them. */\ntype GridViewOwnedEvent =\n | 'onGridReady'\n | 'onFirstDataRendered'\n | 'onModelUpdated'\n | 'onSelectionChanged'\n | 'onCellValueChanged'\n | 'onRowClicked'\n | 'onStateUpdated'\n | 'onColumnVisible'\n\n// Generic props to make this grid reusable with different data types\nexport interface GridViewProps<T> {\n // Core data\n items: T[]\n // Column configuration\n columnDefs: ColDef<T>[]\n // Row identity function\n getItemId: (item: T) => string\n // Selection handling\n selection?: GridViewSelection<T>\n // Empty state\n emptyState?: GridViewEmptyState\n // Loading state\n isLoading?: boolean\n loadingMessage?: string\n // Grid options. The events GridView handles itself are left out: they are spread over its own\n // handlers, so passing one here silently replaced them (an `onGridReady` here left the grid api\n // unset and selection never reached `selection.onSelectionChange`). Use the dedicated props.\n gridOptions?: Partial<Omit<GridOptions<T>, GridViewOwnedEvent>>\n // Grid initialization\n onGridReady?: (params: { api: GridApi<T> }) => void\n // Cell value changes\n onCellValueChanged?: (event: CellValueChangedEvent<T>) => void\n // Row click handler\n onRowClick?: (item: T) => void\n // State persistence.\n // The core is decoupled from any store: when `persistState` is on it seeds\n // AG Grid from `gridState` (read once at mount) and reports every subsequent\n // state change through `onGridStateChange`. An app-adapter wires these to its\n // own store. `gridId` is retained as an opaque identity hint for adapters\n // (the core itself does not read it).\n persistState?: boolean\n gridId?: string\n // Persisted column/sort/filter state to restore at mount (controlled input).\n gridState?: GridState\n // Called whenever AG Grid's state changes so an adapter can persist it.\n onGridStateChange?: (state: GridState) => void\n // Initial visible columns (applied when no saved state exists)\n initialVisibleColumns?: string[]\n // Basic styling\n className?: string\n height?: string | number\n // Per-instance row height. Applied via the theme (not just gridOptions) so the\n // theme's calculated line-height tracks it and cell content stays vertically\n // centered. Fixed height \u2014 keeps row virtualization on the fast path.\n rowHeight?: number\n testId?: string\n // Pinned rows\n pinnedBottomRowData?: T[]\n pinnedTopRowData?: T[]\n // Pagination (disabled by default)\n pagination?: boolean\n paginationPageSizeSelector?: number[]\n // Test-id hooks: the grid owns its row/cell DOM, so ids are stamped onto it after render.\n // `getRowTestId` names a row; `getCellTestId` a cell (by colId). Without them AG Grid's own\n // `row-id` / `col-id` attributes are still there to select by.\n getRowTestId?: (item: T) => string\n getCellTestId?: (colId: string, item: T) => string\n // Force empty-state UI even when items.length > 0.\n // Used when rows are present but all hidden by an external filter.\n showEmpty?: boolean\n}\n\n/** Minimum row height on coarse pointers: 44px touch target + the 1px row border + breathing room. */\nconst TOUCH_ROW_HEIGHT = 52\n\nexport function GridView<T>({\n items,\n columnDefs,\n getItemId,\n selection,\n emptyState,\n isLoading = false,\n loadingMessage = 'Loading...',\n gridOptions,\n onGridReady,\n onCellValueChanged,\n onRowClick,\n persistState = false,\n gridState,\n onGridStateChange,\n initialVisibleColumns,\n className = 'w-full',\n height = 500,\n rowHeight: rowHeightProp,\n testId = 'grid-view',\n pinnedBottomRowData,\n pinnedTopRowData,\n pagination = false,\n paginationPageSizeSelector,\n getRowTestId,\n getCellTestId,\n showEmpty,\n}: GridViewProps<T>) {\n // Reference to the grid API\n const gridApiRef = useRef<GridApi<T> | null>(null)\n\n // On touch screens rows grow to a 44px-hit-area-friendly height: AG Grid clips cell content\n // (pills, filename buttons, avatar chips) to the row, so a taller hit area needs a taller row.\n const isCoarsePointer = useMediaQuery(BREAKPOINT_QUERIES.coarsePointer)\n const rowHeight = isCoarsePointer\n ? Math.max(rowHeightProp ?? gridOptions?.rowHeight ?? 40, TOUCH_ROW_HEIGHT)\n : rowHeightProp\n\n // Initial row height, captured once so it can live in the (stable) default\n // grid options. rowHeight is NOT passed as a reactive prop \u2014 that would make\n // the AgGridReact wrapper re-process grid options on every change and snap\n // manually-resized columns back to their colDef widths. Subsequent changes are\n // applied imperatively (see effect below).\n const initialRowHeightRef = useRef(rowHeight)\n\n // Persisted state to seed the grid with \u2014 captured once at mount so a reactive\n // `gridState` prop (e.g. an adapter re-reading its store each render) can never\n // re-initialise the grid mid-session. Mirrors AG Grid's own initialState,\n // which is read once.\n const initialGridStateRef = useRef(gridState)\n\n // Get initial state for the grid (read once at mount)\n const initialState = useMemo(() => {\n if (!persistState) return undefined\n return initialGridStateRef.current\n }, [persistState])\n\n // Save grid state via the adapter using modern AG Grid state API\n const saveGridState = useCallback(() => {\n if (!persistState || !onGridStateChange || !gridApiRef.current) return\n\n // Use AG Grid's comprehensive state API to capture complete state\n // This includes: filters, sort, column order, column visibility, column widths, etc.\n const state = gridApiRef.current.getState()\n\n onGridStateChange(state)\n }, [persistState, onGridStateChange])\n\n // Ensure selection column is visible after grid initialization\n const ensureSelectionColumnVisible = useCallback(() => {\n if (!gridApiRef.current || !selection?.mode) return\n\n // IMPORTANT: Force selection column to be visible after state restoration\n // This ensures even old saved states don't hide the selection column\n // Also handles case where selection column is completely missing from state\n const currentState = gridApiRef.current.getColumnState()\n const selectionColumn = currentState.find((col) => col.colId === 'ag-Grid-SelectionColumn')\n const selectionColumnIndex = currentState.findIndex(\n (col) => col.colId === 'ag-Grid-SelectionColumn'\n )\n\n // Fix if column is hidden OR missing entirely OR not in first position\n if (!selectionColumn || selectionColumn.hide || selectionColumnIndex !== 0) {\n // Use setColumnsVisible for more reliable visibility control\n gridApiRef.current.setColumnsVisible(['ag-Grid-SelectionColumn'], true)\n\n // Also apply state to ensure proper width\n gridApiRef.current.applyColumnState({\n state: [\n {\n colId: 'ag-Grid-SelectionColumn',\n hide: false,\n width: selectionColumn?.width || 48,\n pinned: null, // Ensure not pinned in wrong position\n },\n ],\n defaultState: { hide: undefined },\n applyOrder: false,\n })\n\n // Move selection column to first position if it's not there\n if (selectionColumnIndex !== 0) {\n gridApiRef.current.moveColumns(['ag-Grid-SelectionColumn'], 0)\n }\n }\n }, [selection?.mode])\n\n // Stamp host test ids onto AG Grid's rows and cells (it virtualises, so keep watching).\n const containerRef = useRef<HTMLDivElement>(null)\n const itemsRef = useRef(items)\n itemsRef.current = items\n const getItemIdRef = useRef(getItemId)\n getItemIdRef.current = getItemId\n const hasTestIdHooks = Boolean(getRowTestId || getCellTestId)\n useEffect(() => {\n const root = containerRef.current\n if (!root || !hasTestIdHooks) return\n return watchGridTestIds(\n root,\n () => new Map(itemsRef.current.map((item) => [getItemIdRef.current(item), item])),\n { getRowTestId, getCellTestId }\n )\n }, [hasTestIdHooks, getRowTestId, getCellTestId, isLoading])\n\n // Row identity, stable for the grid's life (through the latest `getItemId`): an inline\n // `getItemId` used to change it, and with it the default options and their `defaultColDef`, on\n // every host render; AG Grid then re-applied the columns and recreated every header's label.\n const getRowId = useCallback((params: { data: T }) => getItemIdRef.current(params.data), [])\n\n // Refs for selection \u2014 avoids handleGridReady/handleSelectionChanged recreating\n // when selection object changes (which happens on every selectionConfig recompute)\n const selectionRef = useRef(selection)\n selectionRef.current = selection\n\n const onSelectionChangeRef = useRef(selection?.onSelectionChange)\n onSelectionChangeRef.current = selection?.onSelectionChange\n\n const syncingSelectionRef = useRef(false)\n\n const handleSelectionChanged = useCallback(() => {\n if (syncingSelectionRef.current) return\n if (!onSelectionChangeRef.current || !gridApiRef.current) return\n\n const selectedNodes = gridApiRef.current.getSelectedNodes()\n const selectedData = selectedNodes\n .map((node) => node.data)\n .filter((item): item is T => item !== undefined)\n\n onSelectionChangeRef.current(selectedData)\n }, [])\n\n // Handle row clicks\n // A controlled selection: tick and untick rows so the grid shows exactly `selection.selected`.\n const controlledSelected = selection?.controlled ? selection.selected : undefined\n useEffect(() => {\n const api = gridApiRef.current\n if (!api || api.isDestroyed() || !controlledSelected) return\n const wanted = new Set(controlledSelected.map(getItemId))\n const tick: IRowNode<T>[] = []\n const untick: IRowNode<T>[] = []\n api.forEachNode((node) => {\n if (!node.data) return\n const want = wanted.has(getItemId(node.data))\n if (want && !node.isSelected()) tick.push(node)\n else if (!want && node.isSelected()) untick.push(node)\n })\n syncingSelectionRef.current = true\n try {\n if (tick.length) api.setNodesSelected({ nodes: tick, newValue: true, source: 'api' })\n if (untick.length) api.setNodesSelected({ nodes: untick, newValue: false, source: 'api' })\n } finally {\n syncingSelectionRef.current = false\n }\n }, [controlledSelected, getItemId])\n\n const handleRowClicked = useCallback(\n (event: RowClickedEvent<T>) => {\n if (!onRowClick || !event.data) return\n // Don't fire when the click originated from an interactive element inside the cell\n // (e.g. action buttons). AG Grid fires rowClicked regardless of DOM stopPropagation.\n const target = event.event?.target as HTMLElement | null\n if (target?.closest('button, input, a, select, textarea, [role=\"button\"]')) return\n onRowClick(event.data)\n },\n [onRowClick]\n )\n\n // The visibility the user actually intends, per colId. AG Grid re-processes the\n // column definitions on some React re-renders even when the `columnDefs`\n // reference is unchanged, and that reset restores each colDef's `hide` \u2014 so a\n // column the user turned on (e.g. via a fields menu) silently disappears the\n // next time the host re-renders (opening an editor, selecting a row, \u2026). We\n // remember the intended visibility and restore it whenever such a reset fires.\n // A Map (not a Set of hidden ids) so a genuinely NEW column from a real\n // columnDefs change \u2014 one we've never seen \u2014 is left at its colDef default\n // rather than force-shown.\n const desiredHiddenRef = useRef<Map<string, boolean> | null>(null)\n\n const snapshotDesiredHidden = useCallback(() => {\n const api = gridApiRef.current\n if (!api) return\n desiredHiddenRef.current = new Map(api.getColumnState().map((c) => [c.colId, !!c.hide]))\n }, [])\n\n // Handle grid ready\n const handleGridReady = useCallback(\n (event: GridReadyEvent<T>) => {\n gridApiRef.current = event.api\n\n // Apply initial visible columns when no saved state exists\n // This prevents showing all columns by default for new users\n if (!initialState && initialVisibleColumns?.length) {\n const currentState = event.api.getColumnState()\n const stateMap = new Map(currentState.map((col) => [col.colId, col]))\n const visibleSet = new Set(initialVisibleColumns)\n\n // Build ordered state: selection column first (always visible), then visible columns, then hidden\n const selectionCol = stateMap.get('ag-Grid-SelectionColumn')\n const orderedState = [\n // Selection column first - ALWAYS visible, create if not in state\n selectionCol\n ? { ...selectionCol, hide: false }\n : { colId: 'ag-Grid-SelectionColumn', hide: false, width: 48 },\n // Visible columns in specified order\n ...initialVisibleColumns\n .filter((colId) => colId !== 'ag-Grid-SelectionColumn') // Don't duplicate selection column\n .map((colId) => {\n const col = stateMap.get(colId)\n return col ? { ...col, hide: false } : undefined\n }),\n // Hidden columns (everything else)\n ...currentState\n .filter((col) => col.colId !== 'ag-Grid-SelectionColumn' && !visibleSet.has(col.colId))\n .map((col) => ({ ...col, hide: true })),\n ].filter((col): col is NonNullable<typeof col> => col !== undefined)\n\n event.api.applyColumnState({ state: orderedState, applyOrder: true })\n }\n\n // When restoring persisted state, detect columns from columnDefs that\n // aren't in the saved state (e.g. newly added columns) and append them.\n // AG Grid's maintainColumnOrder adds them but may place them inconsistently;\n // this ensures they appear as hidden at the end so the navigator picks them up.\n if (initialState && initialVisibleColumns?.length) {\n const currentState = event.api.getColumnState()\n const savedColIds = new Set(\n initialState.columnOrder?.orderedColIds ?? currentState.map((c) => c.colId)\n )\n const newCols = currentState.filter(\n (col) => !savedColIds.has(col.colId) && col.colId !== 'ag-Grid-SelectionColumn'\n )\n if (newCols.length > 0) {\n // Make new columns visible if they're in the default visible set\n const defaultVisible = new Set(initialVisibleColumns)\n event.api.applyColumnState({\n state: newCols.map((col) => ({\n ...col,\n hide: !defaultVisible.has(col.colId),\n })),\n })\n }\n }\n\n // Ensure selection column is visible (in case saved state hides it)\n ensureSelectionColumnVisible()\n\n // Seed the intended column visibility from the state AG Grid settled on\n // (colDefs + restored persisted state) so a later colDef-driven reset can\n // be undone rather than silently hiding a user-shown column.\n snapshotDesiredHidden()\n\n // Call the provided onGridReady callback\n if (onGridReady) {\n onGridReady({ api: event.api })\n }\n\n // Restore selection state if needed (read from ref to keep callback stable)\n const sel = selectionRef.current\n if (sel && sel.selected.length > 0) {\n const selectedIds = new Set(sel.selected.map(getItemId))\n event.api.forEachNode((node) => {\n if (node.data && selectedIds.has(getItemId(node.data))) {\n node.setSelected(true)\n }\n })\n }\n },\n [\n onGridReady,\n getItemId,\n ensureSelectionColumnVisible,\n snapshotDesiredHidden,\n initialState,\n initialVisibleColumns,\n ]\n )\n\n // Undo AG Grid's colDef-driven visibility reset; record genuine user changes.\n const handleColumnVisible = useCallback(\n (event: ColumnVisibleEvent<T>) => {\n const api = gridApiRef.current\n if (!api) return\n // A columnDefs re-apply reports `gridOptionsChanged`; a real toggle reports\n // an interaction source (api, toolPanelUi, columnMenu, \u2026).\n if (event.source === 'gridOptionsChanged') {\n const desired = desiredHiddenRef.current\n if (!desired) return\n // Only correct columns we've seen before (in the snapshot); a brand-new\n // column keeps its colDef default.\n const fixes = api\n .getColumnState()\n .filter(\n (c) =>\n c.colId !== 'ag-Grid-SelectionColumn' &&\n desired.has(c.colId) &&\n desired.get(c.colId) !== !!c.hide\n )\n .map((c) => ({ colId: c.colId, hide: desired.get(c.colId) }))\n if (fixes.length) api.applyColumnState({ state: fixes })\n } else if (desiredHiddenRef.current && event.visible !== undefined && event.columns) {\n // Genuine change \u2014 this is now the intended visibility. Taken from the event itself: the\n // column state can still report the previous visibility while it is being dispatched\n // (seen for a change made before the grid's first data render).\n for (const column of event.columns) {\n desiredHiddenRef.current.set(column.getColId(), !event.visible)\n }\n } else {\n // A mixed change (applied column state): read the whole visibility back.\n snapshotDesiredHidden()\n }\n },\n [snapshotDesiredHidden]\n )\n\n // Handle first data rendered - no auto-sizing, let flex columns handle it\n const handleFirstDataRendered = useCallback(() => {\n // Columns with flex will auto-fill, columns with width stay fixed\n // Also ensure selection column is visible as a backup (handles timing issues with initialState)\n ensureSelectionColumnVisible()\n // Seed the intended visibility if grid-ready did not. Never re-read it here: grid-ready already\n // seeded it (colDefs + restored state) and every change since is recorded from its event, while\n // the column state read now can still show the visibility from before a change just made.\n if (!desiredHiddenRef.current) snapshotDesiredHidden()\n }, [ensureSelectionColumnVisible, snapshotDesiredHidden])\n\n // Track when AG Grid processes row updates\n const handleModelUpdated = useCallback(() => {\n // AG Grid handles model updates internally\n }, [])\n\n // Track row data changes for AG Grid updates\n const prevItemsRef = useRef<T[]>([])\n useEffect(() => {\n prevItemsRef.current = items\n }, [items])\n\n // Handle state updates - save state when it changes (modern AG Grid approach)\n const handleStateUpdated = useCallback(() => {\n saveGridState()\n }, [saveGridState])\n\n // Removed problematic useEffect that caused unnecessary re-renders\n // AG Grid handles selection internally, only sync on initial load\n\n // Default grid options with minimal settings - memoized to prevent re-renders\n const defaultOptions: GridOptions<T> = useMemo(() => {\n return {\n // Initial row height (stable \u2014 captured once). Live changes go through the\n // imperative effect, not this option, to avoid column-state churn.\n rowHeight: initialRowHeightRef.current,\n suppressMenuHide: true, // Prevent hiding columns since we don't have enterprise sidebar\n maintainColumnOrder: true, // Preserve column order when columns are added/removed\n\n // Row virtualization: Render rows as needed for performance\n // rowBuffer renders extra rows above/below viewport for smoother scrolling\n rowBuffer: 10, // Render 10 extra rows above/below viewport for smooth scrolling\n suppressColumnVirtualisation: false, // Keep column virtualization enabled\n suppressRowVirtualisation: false, // ENABLE row virtualization - only render visible rows\n animateRows: false, // Disable row animations\n suppressColumnMoveAnimation: true, // Disable column move/resize animations\n\n // Efficient updates with React Query cache\n // getRowId enables change detection - grid only re-renders changed rows\n // Works perfectly with React Query's cache updates\n getRowId: getRowId,\n\n rowSelection: selection?.mode\n ? {\n mode: selection.mode === 'single' ? 'singleRow' : 'multiRow',\n selectAll: 'filtered', // Header checkbox selects all filtered rows (across all pages)\n // In multi-row mode, only checkboxes should toggle selection (clicking row body would replace selection)\n enableClickSelection: selection.mode === 'single',\n checkboxes: true,\n headerCheckbox: selection.mode === 'multiple',\n }\n : undefined,\n selectionColumnDef: selection?.mode\n ? {\n sortable: selection.mode === 'multiple',\n width: 48,\n lockVisible: true, // Cannot be hidden\n suppressMovable: true, // Cannot be moved\n }\n : undefined,\n // Use normal layout for better performance - autoHeight causes forced reflows\n domLayout: 'normal',\n // Stop editing when clicking outside the cell/grid\n stopEditingWhenCellsLoseFocus: true,\n // Additional performance optimizations\n suppressCellFocus: true, // Don't focus cells on click (faster)\n suppressRowHoverHighlight: true, // Disable hover highlight - reduces DOM manipulation during scroll\n suppressScrollOnNewData: true, // Don't scroll when data updates\n suppressAggFuncInHeader: true, // Don't show aggregation functions (faster)\n // Tooltip UX: the AG Grid default show-delay is 2 s which hurts\n // discoverability for cells where tooltips carry the \"reveal full\n // content\" affordance for non-editable users. 300 ms is snappy\n // without being accidental. tooltipInteraction lets users hover\n // onto the tooltip itself (e.g. to select / copy long text).\n // These are AG Grid's native tooltip controls \u2014 no React / Radix\n // provider involved, zero per-row cost; tooltip DOM is created on\n // demand when hover-delay elapses and destroyed on mouseout.\n tooltipShowDelay: 300,\n tooltipHideDelay: 4000,\n tooltipInteraction: true,\n // Pagination (disabled by default)\n pagination,\n paginationPageSizeSelector,\n defaultColDef: {\n sortable: true,\n resizable: true,\n unSortIcon: false, // Sort glyph only on the sorted column (every header carrying one was noise)\n sortingOrder: ['asc', 'desc', null], // 3-way sorting: asc \u2192 desc \u2192 unsorted (AG Grid default)\n wrapText: false, // Disable text wrapping for cleaner display\n autoHeight: false, // Use fixed row height from theme\n wrapHeaderText: false, // Disable header text wrapping for cleaner look\n autoHeaderHeight: false, // Fixed header height\n filterParams: {\n maxNumConditions: 1,\n buttons: ['reset'],\n },\n },\n }\n }, [selection?.mode, getRowId, pagination, paginationPageSizeSelector])\n\n // Combine default options with passed options - memoized to prevent re-renders\n const combinedOptions = useMemo(\n () => ({ ...defaultOptions, ...gridOptions }),\n [defaultOptions, gridOptions]\n )\n\n // Apply fixed height for better performance \u2014 autoHeight causes forced\n // reflows by measuring all rows, avoid it.\n //\n // Also derive the geometry the wrapping multiline columns (.cell-multiline \u2014\n // Abstract, Author, custom text fields) need so their overflow clip lands on\n // a WHOLE-line boundary (never mid-line, which reads as a half-line\n // \"bleeding\" into the neighbouring row). All computed once here per\n // row-height change and handed to CSS as variables \u2014 zero per-row cost on the\n // million-row grid:\n // --multiline-line-clamp : whole number of lines that fit \u2014 drives the CSS\n // line-clamp that hides overflow lines entirely.\n // --multiline-pad-y : vertical cell padding, shrunk on very short rows so\n // at least one whole line always fits.\n // --multiline-max-h : cap of exactly N whole lines + TOP padding + borders.\n // Deliberately excludes the bottom padding: AG Grid\n // forces cell height, so overflow clips at the\n // padding-box edge and any bottom padding becomes a\n // window onto the next (clamped-away) line. Ending the\n // box right at line N's bottom puts the clip on the\n // line boundary; the row supplies the visual gap below.\n const containerStyle = useMemo(() => {\n const style: React.CSSProperties = { height }\n if (rowHeight) {\n const LINE_PX = 14 * 1.35 // grid font-size \u00D7 multiline line-height (18.9px)\n const BORDER = 2 // multiline cell top + bottom border (1px each, border-box)\n const PREFERRED_PAD = 16 // preferred total vertical padding (8px top + 8px bottom)\n // Don't let padding eat the room a single line needs on short rows.\n const padTotal = Math.max(0, Math.min(PREFERRED_PAD, rowHeight - BORDER - LINE_PX))\n const lines = Math.max(1, Math.floor((rowHeight - BORDER - padTotal) / LINE_PX))\n const vars = style as Record<string, string | number>\n vars['--multiline-line-clamp'] = `${lines}`\n vars['--multiline-pad-y'] = `${padTotal / 2}px`\n vars['--multiline-max-h'] = `${lines * LINE_PX + padTotal / 2 + BORDER}px`\n }\n return style\n }, [height, rowHeight])\n\n // Apply rowHeight changes imperatively via the grid option (not the theme \u2014\n // recreating the theme would re-initialise the grid). This only re-lays-out\n // rows; columns, row virtualization, and the transaction bus are untouched.\n useEffect(() => {\n const api = gridApiRef.current\n if (!api || api.isDestroyed() || !rowHeight) return\n api.setGridOption('rowHeight', rowHeight)\n api.resetRowHeights()\n }, [rowHeight])\n\n const containerClassName = useMemo(() => {\n const baseClass = className || ''\n // Height-adjustable grids vertically center cell content (CSS) so a\n // one-line cell or a lone pill sits in the middle of the row, and multi-line\n // text (e.g. Abstract) is balanced top-to-bottom \u2014 flagged here, applied in\n // grid.css.\n const alignClass = rowHeight ? 'ag-cells-centered' : ''\n return [baseClass, alignClass].filter(Boolean).join(' ')\n }, [className, rowHeight])\n\n // Show loading state \u2014 grey skeleton rows so the page transition feels instant\n if (isLoading) {\n const skeletonRowCount = 12\n return (\n <div\n data-testid={`${testId}-loading`}\n className={`${containerClassName} overflow-hidden rounded-lg border border-border`}\n style={containerStyle}\n aria-busy=\"true\"\n aria-label={loadingMessage}\n >\n {/* Header skeleton */}\n <div className=\"flex h-[37px] items-center gap-4 border-b border-border bg-muted/40 px-3\">\n <div className=\"h-3 w-6 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-32 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-24 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-20 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-28 rounded bg-muted animate-pulse\" />\n <div className=\"h-3 w-16 rounded bg-muted animate-pulse ml-auto\" />\n </div>\n {/* Row skeletons */}\n {Array.from({ length: skeletonRowCount }).map((_, rowIdx) => (\n <div key={rowIdx} className=\"flex h-10 items-center gap-4 border-b border-border px-3\">\n <div className=\"h-4 w-4 rounded-sm bg-muted/70 animate-pulse\" />\n <div\n className=\"h-3 rounded bg-muted/70 animate-pulse\"\n style={{ width: `${20 + ((rowIdx * 17) % 40)}%` }}\n />\n <div\n className=\"h-3 rounded bg-muted/60 animate-pulse\"\n style={{ width: `${8 + ((rowIdx * 11) % 12)}%` }}\n />\n <div\n className=\"h-3 rounded bg-muted/60 animate-pulse\"\n style={{ width: `${6 + ((rowIdx * 7) % 10)}%` }}\n />\n <div\n className=\"h-3 rounded bg-muted/50 animate-pulse ml-auto\"\n style={{ width: `${5 + ((rowIdx * 5) % 8)}%` }}\n />\n </div>\n ))}\n </div>\n )\n }\n\n // Show empty state\n // showEmpty lets callers force this UI (e.g. when an external filter hid\n // every row but the underlying items array is non-empty).\n if ((showEmpty ?? items.length === 0) && emptyState) {\n return (\n <div\n data-testid={`${testId}-empty`}\n // Capped by its container (a landscape phone is shorter than 24rem) and scrollable, with the\n // content centred by auto margins so a tall one still starts at the top.\n className=\"flex h-96 max-h-full flex-col items-center overflow-y-auto p-6 text-center\"\n >\n <div className=\"my-auto flex flex-col items-center\">\n {emptyState.icon && (\n <div className=\"text-muted-foreground/60 mb-4\">{emptyState.icon}</div>\n )}\n {emptyState.title && <h3 className=\"text-xl font-medium mb-2\">{emptyState.title}</h3>}\n {emptyState.message && (\n <p className=\"text-muted-foreground mb-6 max-w-md\">{emptyState.message}</p>\n )}\n {emptyState.action}\n </div>\n </div>\n )\n }\n\n return (\n <div\n ref={containerRef}\n className={containerClassName}\n style={containerStyle}\n data-testid={testId}\n >\n <AgGridReact\n theme={arbiTheme}\n modules={[AllCommunityModule]}\n columnDefs={columnDefs}\n rowData={items}\n pinnedBottomRowData={pinnedBottomRowData}\n pinnedTopRowData={pinnedTopRowData}\n getRowId={getRowId}\n initialState={initialState}\n {...combinedOptions}\n // The events GridView binds itself come after the host's options, so an options object\n // that names one anyway (it is typed out, but untyped objects slip through) cannot replace\n // them: a no-op `onColumnVisible` there used to switch off the visibility guard.\n onGridReady={handleGridReady}\n onFirstDataRendered={handleFirstDataRendered}\n onModelUpdated={handleModelUpdated}\n onSelectionChanged={handleSelectionChanged}\n onCellValueChanged={onCellValueChanged}\n onRowClicked={handleRowClicked}\n onStateUpdated={handleStateUpdated}\n onColumnVisible={handleColumnVisible}\n />\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -34,12 +34,16 @@ export interface ViewerFrameProps {
|
|
|
34
34
|
children: ReactNode;
|
|
35
35
|
/** Rendered after the content area (modals owned by the viewer, e.g. crop). */
|
|
36
36
|
footer?: ReactNode;
|
|
37
|
+
/** The content alone, on black (a clean view to share or put full screen): no header. */
|
|
38
|
+
bare?: boolean;
|
|
39
|
+
/** Over the content, e.g. the control leaving the clean view. */
|
|
40
|
+
overlay?: ReactNode;
|
|
37
41
|
frameRef?: React.Ref<HTMLDivElement>;
|
|
38
42
|
className?: string;
|
|
39
43
|
testIds?: Partial<ViewerFrameTestIds>;
|
|
40
44
|
}
|
|
41
45
|
/** The document viewer shell: sticky header, optional compare row, scrolling content. */
|
|
42
|
-
export declare const ViewerFrame: ({ header, compareRow, contentId, children, footer, frameRef, className, testIds, }: ViewerFrameProps) => import("react").JSX.Element;
|
|
46
|
+
export declare const ViewerFrame: ({ header, compareRow, contentId, children, footer, frameRef, className, testIds, bare, overlay, }: ViewerFrameProps) => import("react").JSX.Element;
|
|
43
47
|
/** Centered muted status line for loading / error states inside the viewer. */
|
|
44
48
|
export declare function ViewerMessage({ children, testId }: {
|
|
45
49
|
children: ReactNode;
|
|
@@ -33,16 +33,23 @@ const ViewerFrame = ({
|
|
|
33
33
|
footer,
|
|
34
34
|
frameRef,
|
|
35
35
|
className,
|
|
36
|
-
testIds
|
|
36
|
+
testIds,
|
|
37
|
+
bare = false,
|
|
38
|
+
overlay
|
|
37
39
|
}) => /* @__PURE__ */ jsxs(
|
|
38
40
|
"div",
|
|
39
41
|
{
|
|
40
42
|
ref: frameRef,
|
|
41
|
-
className: cn(
|
|
43
|
+
className: cn(
|
|
44
|
+
"flex h-full w-full flex-col",
|
|
45
|
+
bare && "bg-black [&_[data-slot=pdf-scroller]]:bg-black",
|
|
46
|
+
className
|
|
47
|
+
),
|
|
42
48
|
"data-slot": "viewer-frame",
|
|
49
|
+
"data-bare": bare || void 0,
|
|
43
50
|
"data-testid": testIdOr(testIds?.root, { testId: "document-viewer" }),
|
|
44
51
|
children: [
|
|
45
|
-
/* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-10 bg-background", children: [
|
|
52
|
+
!bare && /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-10 bg-background", children: [
|
|
46
53
|
header,
|
|
47
54
|
compareRow && /* @__PURE__ */ jsx(
|
|
48
55
|
"div",
|
|
@@ -53,12 +60,15 @@ const ViewerFrame = ({
|
|
|
53
60
|
}
|
|
54
61
|
)
|
|
55
62
|
] }),
|
|
56
|
-
/* @__PURE__ */
|
|
63
|
+
/* @__PURE__ */ jsxs(
|
|
57
64
|
"div",
|
|
58
65
|
{
|
|
59
|
-
className: "flex-1 overflow-hidden",
|
|
66
|
+
className: "relative flex-1 overflow-hidden",
|
|
60
67
|
"data-testid": testIdOr(testIds?.content, { testId: `document-viewer-content-${contentId}` }),
|
|
61
|
-
children
|
|
68
|
+
children: [
|
|
69
|
+
children,
|
|
70
|
+
overlay
|
|
71
|
+
]
|
|
62
72
|
}
|
|
63
73
|
),
|
|
64
74
|
footer
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/files/ViewerChrome.tsx"],
|
|
4
|
-
"sourcesContent": ["import type { ReactNode } from 'react'\nimport {\n Check,\n ChevronLeft,\n ChevronRight,\n Crop,\n GitCompare,\n ImagePlus,\n Loader2,\n Pencil,\n X,\n ZoomIn,\n} from 'lucide-react'\nimport { Button, cn } from '@arbidocs/react/ui'\nimport { testIdOr } from '../chat/test-id'\n\n/** Every fixed string of the viewer chrome and parts. Pass a partial `labels` to translate or reword. */\nexport interface ViewerLabels {\n useAsReference: string\n useAsReferenceTitle: string\n crop: string\n cropTitle: string\n previousPage: string\n nextPage: string\n /** The zoom button's accessible name; `level` is the current zoom, e.g. \"150%\". */\n zoom: (level: string) => string\n pageInput: string\n pageOfTitle: string\n pageOf: (page: number, total: number) => string\n previewUnavailable: string\n cannotPreview: (extension: string) => string\n downloadToOpen: string\n download: string\n}\n\nexport const DEFAULT_VIEWER_LABELS: ViewerLabels = {\n useAsReference: 'Use as reference',\n useAsReferenceTitle: 'Use as reference for a new image generation',\n crop: 'Crop',\n cropTitle: 'Crop and save as a new version',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n zoom: (level) => `Zoom ${level}. Click to zoom in further, then back to fit the page width.`,\n pageInput: 'Page number input',\n pageOfTitle: 'Click to go to page',\n pageOf: (page, total) => `Page ${page} of ${total}. Click to navigate.`,\n previewUnavailable: 'Preview not available',\n cannotPreview: (extension) => `${extension} files cannot be previewed in the browser.`,\n downloadToOpen: 'Download to open',\n download: 'Download',\n}\n\nexport interface ViewerFrameTestIds {\n root: string\n compareRow: string\n /** Replaces the whole `document-viewer-content-<id>` id. */\n content: string\n}\n\n// \u2500\u2500 Frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ViewerFrameProps {\n /** The sticky top bar (tabs + title + actions). */\n header: ReactNode\n /** \"Comparing against...\" chips, shown on their own row under the header when set. */\n compareRow?: ReactNode\n /** Document id; the content area's test id is `document-viewer-content-{id}`. */\n contentId: string\n children: ReactNode\n /** Rendered after the content area (modals owned by the viewer, e.g. crop). */\n footer?: ReactNode\n frameRef?: React.Ref<HTMLDivElement>\n className?: string\n testIds?: Partial<ViewerFrameTestIds>\n}\n\n/** The document viewer shell: sticky header, optional compare row, scrolling content. */\nexport const ViewerFrame = ({\n header,\n compareRow,\n contentId,\n children,\n footer,\n frameRef,\n className,\n testIds,\n}: ViewerFrameProps) => (\n <div\n ref={frameRef}\n className={cn('flex h-full w-full flex-col', className)}\n data-slot=\"viewer-frame\"\n data-testid={testIdOr(testIds?.root, { testId: 'document-viewer' })}\n >\n <div className=\"sticky top-0 z-10 bg-background\">\n {header}\n {compareRow && (\n <div\n className=\"flex flex-wrap items-center gap-1.5 border-t border-border px-3 py-1.5\"\n data-testid={testIdOr(testIds?.compareRow, { testId: 'compare-indicator-row' })}\n >\n {compareRow}\n </div>\n )}\n </div>\n <div\n className=\"flex-1 overflow-hidden\"\n data-testid={testIdOr(testIds?.content, { testId: `document-viewer-content-${contentId}` })}\n >\n {children}\n </div>\n {footer}\n </div>\n)\n\n/** Centered muted status line for loading / error states inside the viewer. */\nexport function ViewerMessage({ children, testId }: { children: ReactNode; testId?: string }) {\n return (\n <div className=\"flex h-full items-center justify-center\" data-testid={testId}>\n <div className=\"text-sm text-muted-foreground\">{children}</div>\n </div>\n )\n}\n\n// \u2500\u2500 Title \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ViewerTitleProps {\n title: string\n /** e.g. \"v3\". */\n versionLabel?: string | null\n /** Let the pill shrink (live artifacts share the row with more controls). */\n shrink?: boolean\n}\n\n/** Read-only document name (plain text, no fill) with the version label. */\nexport function ViewerTitle({ title, versionLabel, shrink }: ViewerTitleProps) {\n return (\n <span\n className={cn(\n 'inline-flex min-w-0 items-center gap-1.5 px-1 py-1 text-sm font-medium',\n shrink ? 'shrink' : 'shrink-0'\n )}\n title={title}\n >\n <span className=\"truncate\">{title}</span>\n {versionLabel && (\n <span className=\"shrink-0 text-xs font-normal text-muted-foreground\">{versionLabel}</span>\n )}\n </span>\n )\n}\n\n// \u2500\u2500 Actions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ViewerImageActionsProps {\n compact: boolean\n /** Start a generation from the image. Omitted: not offered. */\n onUseAsReference?: () => void\n onCrop: () => void\n labels?: Partial<ViewerLabels>\n testIds?: Partial<{ useAsReference: string; crop: string }>\n}\n\n/** Image-only actions: feed it into a new generation, or crop it into a new version. */\nexport function ViewerImageActions({\n compact,\n onUseAsReference,\n onCrop,\n labels,\n testIds,\n}: ViewerImageActionsProps) {\n const l = { ...DEFAULT_VIEWER_LABELS, ...labels }\n const size = compact ? 'icon' : 'sm'\n return (\n <>\n {onUseAsReference && (\n <Button\n onClick={onUseAsReference}\n variant=\"outline\"\n size={size}\n title={l.useAsReferenceTitle}\n aria-label={l.useAsReference}\n data-testid={testIdOr(testIds?.useAsReference, {\n testId: 'image-use-as-reference-button',\n })}\n className=\"pointer-coarse:min-h-11\"\n >\n <ImagePlus className=\"size-4\" />\n {!compact && <span className=\"ml-1\">{l.useAsReference}</span>}\n </Button>\n )}\n <Button\n onClick={onCrop}\n variant=\"outline\"\n size={size}\n title={l.cropTitle}\n aria-label={l.crop}\n data-testid={testIdOr(testIds?.crop, { testId: 'image-crop-button' })}\n className=\"pointer-coarse:min-h-11\"\n >\n <Crop className=\"size-4\" />\n {!compact && <span className=\"ml-1\">{l.crop}</span>}\n </Button>\n </>\n )\n}\n\n// \u2500\u2500 PDF page navigation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface PdfPageNavProps {\n canPrev: boolean\n canNext: boolean\n onPrev: () => void\n onNext: () => void\n /** The \"3 / 12\" counter between the arrows (the host owns its editing behaviour). */\n counter: ReactNode\n labels?: Partial<ViewerLabels>\n testIds?: Partial<{ overlay: string; prev: string; next: string }>\n}\n\n/** Floating prev / counter / next control over a rendered PDF. */\nexport function PdfPageNav({\n canPrev,\n canNext,\n onPrev,\n onNext,\n counter,\n labels,\n testIds,\n}: PdfPageNavProps) {\n const l = { ...DEFAULT_VIEWER_LABELS, ...labels }\n return (\n <div\n className=\"absolute bottom-4 left-1/2 z-10 flex -translate-x-1/2 items-center gap-1 rounded-lg border border-border bg-background/95 px-2 py-1.5 shadow-lg backdrop-blur\"\n data-testid={testIdOr(testIds?.overlay, { testId: 'pdf-page-nav-overlay' })}\n >\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 shrink-0 pointer-coarse:size-11\"\n onClick={onPrev}\n disabled={!canPrev}\n aria-label={l.previousPage}\n data-testid={testIdOr(testIds?.prev, { testId: 'pdf-page-nav-prev' })}\n >\n <ChevronLeft className=\"size-4\" />\n </Button>\n {counter}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 shrink-0 pointer-coarse:size-11\"\n onClick={onNext}\n disabled={!canNext}\n aria-label={l.nextPage}\n data-testid={testIdOr(testIds?.next, { testId: 'pdf-page-nav-next' })}\n >\n <ChevronRight className=\"size-4\" />\n </Button>\n </div>\n )\n}\n\n// \u2500\u2500 Zoom \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ViewerZoomControlProps {\n /** Multiplier of the fit-width size (1 = fit width). */\n zoom: number\n /** Steps to the next zoom level (and back to fit width after the last). */\n onCycle: () => void\n labels?: Partial<ViewerLabels>\n testIds?: Partial<{ button: string; level: string }>\n}\n\n/**\n * The viewer's zoom button, on every pointer: a docked panel on a desktop screen still leaves the\n * text too small to read, so mouse users need a way to enlarge it too. It stays quiet at fit width\n * and shows the level once zoomed; pinch and double-tap work alongside it.\n */\nexport function ViewerZoomControl({ zoom, onCycle, labels, testIds }: ViewerZoomControlProps) {\n const l = { ...DEFAULT_VIEWER_LABELS, ...labels }\n const level = `${Math.round(zoom * 100)}%`\n const isZoomed = Math.abs(zoom - 1) > 0.02\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={onCycle}\n title={`Zoom ${level}`}\n aria-label={l.zoom(level)}\n data-testid={testIdOr(testIds?.button, { testId: 'viewer-zoom-button' })}\n className=\"absolute right-3 bottom-4 z-10 h-9 min-w-9 items-center justify-center gap-1 rounded-full border border-border bg-background/95 px-2 shadow-md backdrop-blur pointer-coarse:h-11 pointer-coarse:min-w-11 pointer-coarse:px-2.5\"\n >\n <ZoomIn className=\"size-4\" />\n {isZoomed && (\n <span\n className=\"text-xs font-medium tabular-nums\"\n data-testid={testIdOr(testIds?.level, { testId: 'viewer-zoom-level' })}\n >\n {level}\n </span>\n )}\n </Button>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["import type { ReactNode } from 'react'\nimport {\n Check,\n ChevronLeft,\n ChevronRight,\n Crop,\n GitCompare,\n ImagePlus,\n Loader2,\n Pencil,\n X,\n ZoomIn,\n} from 'lucide-react'\nimport { Button, cn } from '@arbidocs/react/ui'\nimport { testIdOr } from '../chat/test-id'\n\n/** Every fixed string of the viewer chrome and parts. Pass a partial `labels` to translate or reword. */\nexport interface ViewerLabels {\n useAsReference: string\n useAsReferenceTitle: string\n crop: string\n cropTitle: string\n previousPage: string\n nextPage: string\n /** The zoom button's accessible name; `level` is the current zoom, e.g. \"150%\". */\n zoom: (level: string) => string\n pageInput: string\n pageOfTitle: string\n pageOf: (page: number, total: number) => string\n previewUnavailable: string\n cannotPreview: (extension: string) => string\n downloadToOpen: string\n download: string\n}\n\nexport const DEFAULT_VIEWER_LABELS: ViewerLabels = {\n useAsReference: 'Use as reference',\n useAsReferenceTitle: 'Use as reference for a new image generation',\n crop: 'Crop',\n cropTitle: 'Crop and save as a new version',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n zoom: (level) => `Zoom ${level}. Click to zoom in further, then back to fit the page width.`,\n pageInput: 'Page number input',\n pageOfTitle: 'Click to go to page',\n pageOf: (page, total) => `Page ${page} of ${total}. Click to navigate.`,\n previewUnavailable: 'Preview not available',\n cannotPreview: (extension) => `${extension} files cannot be previewed in the browser.`,\n downloadToOpen: 'Download to open',\n download: 'Download',\n}\n\nexport interface ViewerFrameTestIds {\n root: string\n compareRow: string\n /** Replaces the whole `document-viewer-content-<id>` id. */\n content: string\n}\n\n// \u2500\u2500 Frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ViewerFrameProps {\n /** The sticky top bar (tabs + title + actions). */\n header: ReactNode\n /** \"Comparing against...\" chips, shown on their own row under the header when set. */\n compareRow?: ReactNode\n /** Document id; the content area's test id is `document-viewer-content-{id}`. */\n contentId: string\n children: ReactNode\n /** Rendered after the content area (modals owned by the viewer, e.g. crop). */\n footer?: ReactNode\n /** The content alone, on black (a clean view to share or put full screen): no header. */\n bare?: boolean\n /** Over the content, e.g. the control leaving the clean view. */\n overlay?: ReactNode\n frameRef?: React.Ref<HTMLDivElement>\n className?: string\n testIds?: Partial<ViewerFrameTestIds>\n}\n\n/** The document viewer shell: sticky header, optional compare row, scrolling content. */\nexport const ViewerFrame = ({\n header,\n compareRow,\n contentId,\n children,\n footer,\n frameRef,\n className,\n testIds,\n bare = false,\n overlay,\n}: ViewerFrameProps) => (\n <div\n ref={frameRef}\n className={cn(\n 'flex h-full w-full flex-col',\n bare && 'bg-black [&_[data-slot=pdf-scroller]]:bg-black',\n className\n )}\n data-slot=\"viewer-frame\"\n data-bare={bare || undefined}\n data-testid={testIdOr(testIds?.root, { testId: 'document-viewer' })}\n >\n {!bare && (\n <div className=\"sticky top-0 z-10 bg-background\">\n {header}\n {compareRow && (\n <div\n className=\"flex flex-wrap items-center gap-1.5 border-t border-border px-3 py-1.5\"\n data-testid={testIdOr(testIds?.compareRow, { testId: 'compare-indicator-row' })}\n >\n {compareRow}\n </div>\n )}\n </div>\n )}\n <div\n className=\"relative flex-1 overflow-hidden\"\n data-testid={testIdOr(testIds?.content, { testId: `document-viewer-content-${contentId}` })}\n >\n {children}\n {overlay}\n </div>\n {footer}\n </div>\n)\n\n/** Centered muted status line for loading / error states inside the viewer. */\nexport function ViewerMessage({ children, testId }: { children: ReactNode; testId?: string }) {\n return (\n <div className=\"flex h-full items-center justify-center\" data-testid={testId}>\n <div className=\"text-sm text-muted-foreground\">{children}</div>\n </div>\n )\n}\n\n// \u2500\u2500 Title \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ViewerTitleProps {\n title: string\n /** e.g. \"v3\". */\n versionLabel?: string | null\n /** Let the pill shrink (live artifacts share the row with more controls). */\n shrink?: boolean\n}\n\n/** Read-only document name (plain text, no fill) with the version label. */\nexport function ViewerTitle({ title, versionLabel, shrink }: ViewerTitleProps) {\n return (\n <span\n className={cn(\n 'inline-flex min-w-0 items-center gap-1.5 px-1 py-1 text-sm font-medium',\n shrink ? 'shrink' : 'shrink-0'\n )}\n title={title}\n >\n <span className=\"truncate\">{title}</span>\n {versionLabel && (\n <span className=\"shrink-0 text-xs font-normal text-muted-foreground\">{versionLabel}</span>\n )}\n </span>\n )\n}\n\n// \u2500\u2500 Actions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ViewerImageActionsProps {\n compact: boolean\n /** Start a generation from the image. Omitted: not offered. */\n onUseAsReference?: () => void\n onCrop: () => void\n labels?: Partial<ViewerLabels>\n testIds?: Partial<{ useAsReference: string; crop: string }>\n}\n\n/** Image-only actions: feed it into a new generation, or crop it into a new version. */\nexport function ViewerImageActions({\n compact,\n onUseAsReference,\n onCrop,\n labels,\n testIds,\n}: ViewerImageActionsProps) {\n const l = { ...DEFAULT_VIEWER_LABELS, ...labels }\n const size = compact ? 'icon' : 'sm'\n return (\n <>\n {onUseAsReference && (\n <Button\n onClick={onUseAsReference}\n variant=\"outline\"\n size={size}\n title={l.useAsReferenceTitle}\n aria-label={l.useAsReference}\n data-testid={testIdOr(testIds?.useAsReference, {\n testId: 'image-use-as-reference-button',\n })}\n className=\"pointer-coarse:min-h-11\"\n >\n <ImagePlus className=\"size-4\" />\n {!compact && <span className=\"ml-1\">{l.useAsReference}</span>}\n </Button>\n )}\n <Button\n onClick={onCrop}\n variant=\"outline\"\n size={size}\n title={l.cropTitle}\n aria-label={l.crop}\n data-testid={testIdOr(testIds?.crop, { testId: 'image-crop-button' })}\n className=\"pointer-coarse:min-h-11\"\n >\n <Crop className=\"size-4\" />\n {!compact && <span className=\"ml-1\">{l.crop}</span>}\n </Button>\n </>\n )\n}\n\n// \u2500\u2500 PDF page navigation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface PdfPageNavProps {\n canPrev: boolean\n canNext: boolean\n onPrev: () => void\n onNext: () => void\n /** The \"3 / 12\" counter between the arrows (the host owns its editing behaviour). */\n counter: ReactNode\n labels?: Partial<ViewerLabels>\n testIds?: Partial<{ overlay: string; prev: string; next: string }>\n}\n\n/** Floating prev / counter / next control over a rendered PDF. */\nexport function PdfPageNav({\n canPrev,\n canNext,\n onPrev,\n onNext,\n counter,\n labels,\n testIds,\n}: PdfPageNavProps) {\n const l = { ...DEFAULT_VIEWER_LABELS, ...labels }\n return (\n <div\n className=\"absolute bottom-4 left-1/2 z-10 flex -translate-x-1/2 items-center gap-1 rounded-lg border border-border bg-background/95 px-2 py-1.5 shadow-lg backdrop-blur\"\n data-testid={testIdOr(testIds?.overlay, { testId: 'pdf-page-nav-overlay' })}\n >\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 shrink-0 pointer-coarse:size-11\"\n onClick={onPrev}\n disabled={!canPrev}\n aria-label={l.previousPage}\n data-testid={testIdOr(testIds?.prev, { testId: 'pdf-page-nav-prev' })}\n >\n <ChevronLeft className=\"size-4\" />\n </Button>\n {counter}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 shrink-0 pointer-coarse:size-11\"\n onClick={onNext}\n disabled={!canNext}\n aria-label={l.nextPage}\n data-testid={testIdOr(testIds?.next, { testId: 'pdf-page-nav-next' })}\n >\n <ChevronRight className=\"size-4\" />\n </Button>\n </div>\n )\n}\n\n// \u2500\u2500 Zoom \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ViewerZoomControlProps {\n /** Multiplier of the fit-width size (1 = fit width). */\n zoom: number\n /** Steps to the next zoom level (and back to fit width after the last). */\n onCycle: () => void\n labels?: Partial<ViewerLabels>\n testIds?: Partial<{ button: string; level: string }>\n}\n\n/**\n * The viewer's zoom button, on every pointer: a docked panel on a desktop screen still leaves the\n * text too small to read, so mouse users need a way to enlarge it too. It stays quiet at fit width\n * and shows the level once zoomed; pinch and double-tap work alongside it.\n */\nexport function ViewerZoomControl({ zoom, onCycle, labels, testIds }: ViewerZoomControlProps) {\n const l = { ...DEFAULT_VIEWER_LABELS, ...labels }\n const level = `${Math.round(zoom * 100)}%`\n const isZoomed = Math.abs(zoom - 1) > 0.02\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={onCycle}\n title={`Zoom ${level}`}\n aria-label={l.zoom(level)}\n data-testid={testIdOr(testIds?.button, { testId: 'viewer-zoom-button' })}\n className=\"absolute right-3 bottom-4 z-10 h-9 min-w-9 items-center justify-center gap-1 rounded-full border border-border bg-background/95 px-2 shadow-md backdrop-blur pointer-coarse:h-11 pointer-coarse:min-w-11 pointer-coarse:px-2.5\"\n >\n <ZoomIn className=\"size-4\" />\n {isZoomed && (\n <span\n className=\"text-xs font-medium tabular-nums\"\n data-testid={testIdOr(testIds?.level, { testId: 'viewer-zoom-level' })}\n >\n {level}\n </span>\n )}\n </Button>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|