@arbidocs/blocks 0.5.122 → 0.5.124

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/{ClippingMediaViewer-IEIBT74X.cjs → ClippingMediaViewer-ZFEX5A3U.cjs} +11 -10
  2. package/dist/ClippingMediaViewer-ZFEX5A3U.cjs.map +1 -0
  3. package/dist/{ClippingPdfViewer-OGYLMVCE.cjs → ClippingPdfViewer-3LRTEPHV.cjs} +45 -11
  4. package/dist/ClippingPdfViewer-3LRTEPHV.cjs.map +1 -0
  5. package/dist/{ConnectedPresentation-AU25OW25.cjs → ConnectedPresentation-OV2KBOLK.cjs} +27 -153
  6. package/dist/ConnectedPresentation-OV2KBOLK.cjs.map +1 -0
  7. package/dist/{ConnectedSlidesTab-I75LKKN7.cjs → ConnectedSlidesTab-LUAGZ6FD.cjs} +60 -36
  8. package/dist/ConnectedSlidesTab-LUAGZ6FD.cjs.map +1 -0
  9. package/dist/{FilesViewerDialog-4352KIOG.cjs → FilesViewerDialog-JWKNJLWG.cjs} +10 -7
  10. package/dist/FilesViewerDialog-JWKNJLWG.cjs.map +1 -0
  11. package/dist/SpotlightStrip-ED22UYTM.cjs +398 -0
  12. package/dist/SpotlightStrip-ED22UYTM.cjs.map +1 -0
  13. package/dist/{chunk-LHWOKOMP.cjs → chunk-3IH55CDE.cjs} +4 -4
  14. package/dist/chunk-3IH55CDE.cjs.map +1 -0
  15. package/dist/chunk-3ZZZO4F7.cjs +145 -0
  16. package/dist/chunk-3ZZZO4F7.cjs.map +1 -0
  17. package/dist/{chunk-WFMWKPGY.cjs → chunk-ADPRIBSH.cjs} +9 -33
  18. package/dist/chunk-ADPRIBSH.cjs.map +1 -0
  19. package/dist/{chunk-UTJ223TI.cjs → chunk-BX6G2ZCI.cjs} +138 -146
  20. package/dist/chunk-BX6G2ZCI.cjs.map +1 -0
  21. package/dist/{chunk-WRLGLZIA.cjs → chunk-EMRY62HS.cjs} +2 -2
  22. package/dist/{chunk-WRLGLZIA.cjs.map → chunk-EMRY62HS.cjs.map} +1 -1
  23. package/dist/{chunk-USNTRL22.cjs → chunk-H236SNEV.cjs} +199 -1616
  24. package/dist/chunk-H236SNEV.cjs.map +1 -0
  25. package/dist/chunk-JITYC4OS.cjs +66 -0
  26. package/dist/chunk-JITYC4OS.cjs.map +1 -0
  27. package/dist/chunk-JY7UUZQG.cjs +1513 -0
  28. package/dist/chunk-JY7UUZQG.cjs.map +1 -0
  29. package/dist/chunk-MVXHTAJ4.cjs +111 -0
  30. package/dist/chunk-MVXHTAJ4.cjs.map +1 -0
  31. package/dist/{chunk-4TTX6ZNS.cjs → chunk-ORNLCBNE.cjs} +24 -2
  32. package/dist/chunk-ORNLCBNE.cjs.map +1 -0
  33. package/dist/chunk-WVZLAAIZ.cjs +31 -0
  34. package/dist/chunk-WVZLAAIZ.cjs.map +1 -0
  35. package/dist/chunk-ZZZITHGK.cjs +119 -0
  36. package/dist/chunk-ZZZITHGK.cjs.map +1 -0
  37. package/dist/connect/index.cjs +52 -52
  38. package/dist/connect/viewer.cjs +8 -5
  39. package/dist/connection/presentation/ClippingMediaViewer.js +3 -3
  40. package/dist/connection/presentation/ClippingMediaViewer.js.map +2 -2
  41. package/dist/connection/presentation/ClippingPdfViewer.d.ts +4 -3
  42. package/dist/connection/presentation/ClippingPdfViewer.js +48 -9
  43. package/dist/connection/presentation/ClippingPdfViewer.js.map +2 -2
  44. package/dist/connection/presentation/ConnectedSlidesTab.js +35 -13
  45. package/dist/connection/presentation/ConnectedSlidesTab.js.map +2 -2
  46. package/dist/connection/presentation/SpotlightLayer.d.ts +5 -0
  47. package/dist/connection/presentation/SpotlightLayer.js +19 -0
  48. package/dist/connection/presentation/SpotlightLayer.js.map +7 -0
  49. package/dist/connection/presentation/SpotlightStrip.d.ts +10 -0
  50. package/dist/connection/presentation/SpotlightStrip.js +237 -0
  51. package/dist/connection/presentation/SpotlightStrip.js.map +7 -0
  52. package/dist/connection/presentation/useViewerClipping.d.ts +4 -3
  53. package/dist/connection/presentation/useViewerClipping.js +8 -4
  54. package/dist/connection/presentation/useViewerClipping.js.map +2 -2
  55. package/dist/connection/viewer/ConnectedDocumentViewer.js +52 -61
  56. package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
  57. package/dist/connection/viewer/ViewerMoreMenu.d.ts +18 -0
  58. package/dist/connection/viewer/ViewerMoreMenu.js +45 -0
  59. package/dist/connection/viewer/ViewerMoreMenu.js.map +7 -0
  60. package/dist/connection/viewer/pdf/PdfPassageHighlights.js +3 -2
  61. package/dist/connection/viewer/pdf/PdfPassageHighlights.js.map +2 -2
  62. package/dist/connection/viewer/pdf/passageHighlights.d.ts +5 -0
  63. package/dist/connection/viewer/pdf/passageHighlights.js +14 -1
  64. package/dist/connection/viewer/pdf/passageHighlights.js.map +2 -2
  65. package/dist/connection/viewer/useCleanView.d.ts +3 -1
  66. package/dist/connection/viewer/useCleanView.js +6 -3
  67. package/dist/connection/viewer/useCleanView.js.map +2 -2
  68. package/dist/document-tools/DocumentToolButtons.js +3 -3
  69. package/dist/document-tools/DocumentToolButtons.js.map +2 -2
  70. package/dist/document-tools/index.cjs +13 -13
  71. package/dist/index.cjs +53 -53
  72. package/dist/presentation/BoxActionBar.d.ts +2 -2
  73. package/dist/presentation/BoxActionBar.js +62 -30
  74. package/dist/presentation/BoxActionBar.js.map +2 -2
  75. package/dist/presentation/ClipActionBar.js +60 -7
  76. package/dist/presentation/ClipActionBar.js.map +2 -2
  77. package/dist/presentation/ClipCaptureOverlay.d.ts +7 -3
  78. package/dist/presentation/ClipCaptureOverlay.js +43 -14
  79. package/dist/presentation/ClipCaptureOverlay.js.map +2 -2
  80. package/dist/presentation/ClipViewControls.d.ts +3 -3
  81. package/dist/presentation/ClipViewControls.js +59 -64
  82. package/dist/presentation/ClipViewControls.js.map +2 -2
  83. package/dist/presentation/PresentControls.d.ts +8 -0
  84. package/dist/presentation/PresentControls.js +1 -0
  85. package/dist/presentation/PresentControls.js.map +2 -2
  86. package/dist/presentation/PresentationStage.d.ts +10 -2
  87. package/dist/presentation/PresentationStage.js +6 -3
  88. package/dist/presentation/PresentationStage.js.map +2 -2
  89. package/dist/presentation/PresenterView.js +1 -22
  90. package/dist/presentation/PresenterView.js.map +2 -2
  91. package/dist/presentation/SlidesEditor.js +56 -42
  92. package/dist/presentation/SlidesEditor.js.map +2 -2
  93. package/dist/presentation/SpotlightView.d.ts +19 -0
  94. package/dist/presentation/SpotlightView.js +180 -0
  95. package/dist/presentation/SpotlightView.js.map +7 -0
  96. package/dist/presentation/StageItem.js +0 -5
  97. package/dist/presentation/StageItem.js.map +2 -2
  98. package/dist/presentation/passage-clip.d.ts +17 -0
  99. package/dist/presentation/passage-clip.js +25 -0
  100. package/dist/presentation/passage-clip.js.map +7 -0
  101. package/dist/presentation/spotlight.d.ts +58 -0
  102. package/dist/presentation/spotlight.js +110 -0
  103. package/dist/presentation/spotlight.js.map +7 -0
  104. package/dist/presentation/store.d.ts +5 -0
  105. package/dist/presentation/store.js +19 -0
  106. package/dist/presentation/store.js.map +2 -2
  107. package/dist/presentation/usePointerActive.d.ts +2 -0
  108. package/dist/presentation/usePointerActive.js +28 -0
  109. package/dist/presentation/usePointerActive.js.map +7 -0
  110. package/dist/styles.css +1 -1
  111. package/node_modules/@arbidocs/coedit/package.json +1 -1
  112. package/package.json +5 -5
  113. package/dist/ClippingMediaViewer-IEIBT74X.cjs.map +0 -1
  114. package/dist/ClippingPdfViewer-OGYLMVCE.cjs.map +0 -1
  115. package/dist/ConnectedPresentation-AU25OW25.cjs.map +0 -1
  116. package/dist/ConnectedSlidesTab-I75LKKN7.cjs.map +0 -1
  117. package/dist/FilesViewerDialog-4352KIOG.cjs.map +0 -1
  118. package/dist/chunk-4TTX6ZNS.cjs.map +0 -1
  119. package/dist/chunk-LHWOKOMP.cjs.map +0 -1
  120. package/dist/chunk-USNTRL22.cjs.map +0 -1
  121. package/dist/chunk-UTJ223TI.cjs.map +0 -1
  122. package/dist/chunk-WFMWKPGY.cjs.map +0 -1
  123. package/dist/chunk-XK4TVJKD.cjs +0 -73
  124. package/dist/chunk-XK4TVJKD.cjs.map +0 -1
@@ -1,13 +1,13 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
+ var chunkVWBYE3XY_cjs = require('../chunk-VWBYE3XY.cjs');
4
5
  var chunk6OK7ESTL_cjs = require('../chunk-6OK7ESTL.cjs');
5
6
  var chunkE3L5DB5F_cjs = require('../chunk-E3L5DB5F.cjs');
6
7
  var chunkVWTOIGX4_cjs = require('../chunk-VWTOIGX4.cjs');
7
8
  var chunkMLA2BJ2Y_cjs = require('../chunk-MLA2BJ2Y.cjs');
8
- var chunkVWBYE3XY_cjs = require('../chunk-VWBYE3XY.cjs');
9
- var chunk5GCCUXMT_cjs = require('../chunk-5GCCUXMT.cjs');
10
9
  var chunkPSIKUQYM_cjs = require('../chunk-PSIKUQYM.cjs');
10
+ var chunk5GCCUXMT_cjs = require('../chunk-5GCCUXMT.cjs');
11
11
  var chunk7L4X6QN2_cjs = require('../chunk-7L4X6QN2.cjs');
12
12
  var chunkXGM4VVNV_cjs = require('../chunk-XGM4VVNV.cjs');
13
13
  var chunkCMGNRMPA_cjs = require('../chunk-CMGNRMPA.cjs');
@@ -54,7 +54,7 @@ require('../chunk-JH6JTI76.cjs');
54
54
  var chunkQQMMCXBP_cjs = require('../chunk-QQMMCXBP.cjs');
55
55
  require('../chunk-DTMBAFIL.cjs');
56
56
  require('../chunk-ZESMRGDV.cjs');
57
- var chunkWRLGLZIA_cjs = require('../chunk-WRLGLZIA.cjs');
57
+ var chunkEMRY62HS_cjs = require('../chunk-EMRY62HS.cjs');
58
58
  var chunkSGYSDABK_cjs = require('../chunk-SGYSDABK.cjs');
59
59
  require('../chunk-NEGFHF3V.cjs');
60
60
  var chunkZ3LFF3YT_cjs = require('../chunk-Z3LFF3YT.cjs');
@@ -264,7 +264,7 @@ function ConnectedWorkspaceActivity({
264
264
  [feed.data]
265
265
  );
266
266
  return /* @__PURE__ */ jsxRuntime.jsx(
267
- chunkWRLGLZIA_cjs.WorkspaceActivityList,
267
+ chunkEMRY62HS_cjs.WorkspaceActivityList,
268
268
  {
269
269
  ...listProps,
270
270
  items,
@@ -3374,7 +3374,7 @@ function ConnectedTagTable({
3374
3374
  const fail2 = (fallback) => (e) => notify19(browser.refusalReason(e, fallback), "error");
3375
3375
  const snapshot2 = (data) => {
3376
3376
  const title = exportTitle ?? ui.tagKindTitle(kind, { plural: true });
3377
- const bytes = chunkWRLGLZIA_cjs.tagTableDocx(data, {
3377
+ const bytes = chunkEMRY62HS_cjs.tagTableDocx(data, {
3378
3378
  title,
3379
3379
  nameOf: (id) => people.find((p) => p.value === id)?.label
3380
3380
  });
@@ -3383,7 +3383,7 @@ function ConnectedTagTable({
3383
3383
  return { blob: new Blob([bytes], { type: chunkUKOYN2WD_cjs.DOCX_MIME_TYPE }), name };
3384
3384
  };
3385
3385
  return /* @__PURE__ */ jsxRuntime.jsx(
3386
- chunkWRLGLZIA_cjs.TagTable,
3386
+ chunkEMRY62HS_cjs.TagTable,
3387
3387
  {
3388
3388
  ...props,
3389
3389
  table,
@@ -3760,9 +3760,9 @@ function GlossaryExport({ labelId, nameOf }) {
3760
3760
  const narrowed = agreements.find((a) => a.id === narrowTo);
3761
3761
  const title = narrowed ? `Glossary - ${narrowed.name}` : "Glossary";
3762
3762
  const download = (format) => {
3763
- const entries = chunkWRLGLZIA_cjs.glossaryEntries(sources, { labelId: narrowed?.id });
3764
- const blob = format === "docx" ? new Blob([chunkWRLGLZIA_cjs.glossaryDocx(entries, { title })], { type: chunkUKOYN2WD_cjs.DOCX_MIME_TYPE }) : new Blob([chunkWRLGLZIA_cjs.glossaryMarkdown(entries, { title })], { type: "text/markdown" });
3765
- documentTools.downloadBlob(blob, chunkWRLGLZIA_cjs.glossaryFileName(title, format));
3763
+ const entries = chunkEMRY62HS_cjs.glossaryEntries(sources, { labelId: narrowed?.id });
3764
+ const blob = format === "docx" ? new Blob([chunkEMRY62HS_cjs.glossaryDocx(entries, { title })], { type: chunkUKOYN2WD_cjs.DOCX_MIME_TYPE }) : new Blob([chunkEMRY62HS_cjs.glossaryMarkdown(entries, { title })], { type: "text/markdown" });
3765
+ documentTools.downloadBlob(blob, chunkEMRY62HS_cjs.glossaryFileName(title, format));
3766
3766
  };
3767
3767
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", "data-testid": "tags-glossary", children: [
3768
3768
  agreements.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -4291,7 +4291,7 @@ function KindSection({
4291
4291
  {
4292
4292
  testId: `tags-kind-${kind}`,
4293
4293
  title: ui.tagKindTitle(kind, { plural: true }),
4294
- description: chunkWRLGLZIA_cjs.tagKindDescription(kind),
4294
+ description: chunkEMRY62HS_cjs.tagKindDescription(kind),
4295
4295
  children: [
4296
4296
  browser.isEntityTag({ kind }) && extractingCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
4297
4297
  "p",
@@ -4301,9 +4301,9 @@ function KindSection({
4301
4301
  children: [
4302
4302
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }),
4303
4303
  "Extracting ",
4304
- chunkWRLGLZIA_cjs.entitiesPhrase().toLowerCase(),
4304
+ chunkEMRY62HS_cjs.entitiesPhrase().toLowerCase(),
4305
4305
  " from ",
4306
- chunkWRLGLZIA_cjs.documentCount(extractingCount),
4306
+ chunkEMRY62HS_cjs.documentCount(extractingCount),
4307
4307
  "\u2026"
4308
4308
  ]
4309
4309
  }
@@ -4321,7 +4321,7 @@ function KindSection({
4321
4321
  onOpenTag: ctx.onOpenTag,
4322
4322
  onOpenRow: ctx.onOpenTag,
4323
4323
  onOpenTaggedItems: ctx.onOpenTaggedItems,
4324
- labels: chunkWRLGLZIA_cjs.tagTableLabels(kind),
4324
+ labels: chunkEMRY62HS_cjs.tagTableLabels(kind),
4325
4325
  testId: `tags-table-${kind}`
4326
4326
  }
4327
4327
  )
@@ -4429,15 +4429,15 @@ function TagSection({
4429
4429
  onOpenTag: ctx.onOpenTag,
4430
4430
  onOpenRow: ctx.onOpenTag,
4431
4431
  onOpenTaggedItems: ctx.onOpenTaggedItems,
4432
- labels: chunkWRLGLZIA_cjs.tagTableLabels(tag.kind),
4432
+ labels: chunkEMRY62HS_cjs.tagTableLabels(tag.kind),
4433
4433
  testId: "tags-rows"
4434
4434
  }
4435
4435
  ),
4436
4436
  /* @__PURE__ */ jsxRuntime.jsx(
4437
- chunkWRLGLZIA_cjs.TagDetail,
4437
+ chunkEMRY62HS_cjs.TagDetail,
4438
4438
  {
4439
4439
  onOpenTaggedItems: ctx.onOpenTaggedItems,
4440
- fieldLabels: chunkWRLGLZIA_cjs.tagTableLabels(tag.kind),
4440
+ fieldLabels: chunkEMRY62HS_cjs.tagTableLabels(tag.kind),
4441
4441
  row: detailRow,
4442
4442
  fields: schema.data?.fields ?? [],
4443
4443
  isLoading: detail.isLoading,
@@ -4451,7 +4451,7 @@ function TagSection({
4451
4451
  throw e;
4452
4452
  })
4453
4453
  ),
4454
- labels: chunkWRLGLZIA_cjs.tagDetailLabels(),
4454
+ labels: chunkEMRY62HS_cjs.tagDetailLabels(),
4455
4455
  testId: "tags-detail"
4456
4456
  }
4457
4457
  )
@@ -4526,7 +4526,7 @@ function ConnectedTagsPage() {
4526
4526
  const onDelete = async (t) => {
4527
4527
  const nested = browser.getChildTags([...tags], t.external_id);
4528
4528
  const uses = browser.tagUseCount(t);
4529
- const n2 = chunkWRLGLZIA_cjs.tagsPageNouns();
4529
+ const n2 = chunkEMRY62HS_cjs.tagsPageNouns();
4530
4530
  const tagNoun = (count2) => (count2 === 1 ? n2.tag : n2.tags).toLowerCase();
4531
4531
  const carriers = uses === 1 ? `${n2.document}, ${n2.fact} or ${n2.thread}` : `${n2.documents}, ${n2.facts} and ${n2.threads}`;
4532
4532
  const message = `Delete ${ui.tagKindNouns(t.kind).singular} "${t.name}"?` + (uses > 0 ? `
@@ -4547,11 +4547,11 @@ ${nested.length} nested ${tagNoun(nested.length)} ${nested.length === 1 ? "moves
4547
4547
  try {
4548
4548
  await extract.mutateAsync(docIds);
4549
4549
  notify19(
4550
- `Extracting ${chunkWRLGLZIA_cjs.entitiesPhrase().toLowerCase()} from ${chunkWRLGLZIA_cjs.documentCount(docIds.length)}. You will be notified when it is done.`,
4550
+ `Extracting ${chunkEMRY62HS_cjs.entitiesPhrase().toLowerCase()} from ${chunkEMRY62HS_cjs.documentCount(docIds.length)}. You will be notified when it is done.`,
4551
4551
  "info"
4552
4552
  );
4553
4553
  } catch (error) {
4554
- notify19(browser.refusalReason(error, `Could not extract ${chunkWRLGLZIA_cjs.entitiesPhrase().toLowerCase()}`), "error");
4554
+ notify19(browser.refusalReason(error, `Could not extract ${chunkEMRY62HS_cjs.entitiesPhrase().toLowerCase()}`), "error");
4555
4555
  throw error;
4556
4556
  }
4557
4557
  };
@@ -4565,10 +4565,10 @@ ${nested.length} nested ${tagNoun(nested.length)} ${nested.length === 1 ? "moves
4565
4565
  onOpenTag: openTag,
4566
4566
  onOpenTaggedItems
4567
4567
  };
4568
- const n = chunkWRLGLZIA_cjs.tagsPageNouns();
4568
+ const n = chunkEMRY62HS_cjs.tagsPageNouns();
4569
4569
  const action = view === "person" || view === "organisation" ? {
4570
4570
  label: "Extract",
4571
- title: `Extract ${chunkWRLGLZIA_cjs.entitiesPhrase().toLowerCase()} from ${n.documents.toLowerCase()}`,
4571
+ title: `Extract ${chunkEMRY62HS_cjs.entitiesPhrase().toLowerCase()} from ${n.documents.toLowerCase()}`,
4572
4572
  icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "h-4 w-4" }),
4573
4573
  run: () => setExtracting(true),
4574
4574
  testId: "tags-extract-entities"
@@ -4737,7 +4737,7 @@ ${nested.length} nested ${tagNoun(nested.length)} ${nested.length === 1 ? "moves
4737
4737
  }
4738
4738
  ),
4739
4739
  /* @__PURE__ */ jsxRuntime.jsx(
4740
- chunkWRLGLZIA_cjs.ExtractEntitiesDialog,
4740
+ chunkEMRY62HS_cjs.ExtractEntitiesDialog,
4741
4741
  {
4742
4742
  open: extracting,
4743
4743
  onOpenChange: setExtracting,
@@ -7739,7 +7739,7 @@ function ConnectedFactsPage() {
7739
7739
  onNewFact: composing && !editingId ? () => void 0 : composer.startNewFact,
7740
7740
  navSlotRef: setNavSlot,
7741
7741
  navigator: view === "table" ? /* @__PURE__ */ jsxRuntime.jsx(
7742
- chunkWRLGLZIA_cjs.GridRowNavigator,
7742
+ chunkEMRY62HS_cjs.GridRowNavigator,
7743
7743
  {
7744
7744
  gridApi,
7745
7745
  selectedId: editingId,
@@ -12760,13 +12760,13 @@ function ConnectedWorkspaceSettings({
12760
12760
  const [membersExpanded, setMembersExpanded] = react$1.useState(false);
12761
12761
  const [shareOpen, setShareOpen] = react$1.useState(false);
12762
12762
  if (!workspace) {
12763
- return /* @__PURE__ */ jsxRuntime.jsx(chunkCMGNRMPA_cjs.PageLoading, { children: /* @__PURE__ */ jsxRuntime.jsx(chunkWRLGLZIA_cjs.LoadingIndicator, { message: "Loading workspace..." }) });
12763
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkCMGNRMPA_cjs.PageLoading, { children: /* @__PURE__ */ jsxRuntime.jsx(chunkEMRY62HS_cjs.LoadingIndicator, { message: "Loading workspace..." }) });
12764
12764
  }
12765
12765
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
12766
12766
  /* @__PURE__ */ jsxRuntime.jsxs(chunkCMGNRMPA_cjs.WorkspacePageFrame, { testId, children: [
12767
12767
  /* @__PURE__ */ jsxRuntime.jsxs(chunkCMGNRMPA_cjs.WorkspaceIdentityPanel, { children: [
12768
12768
  /* @__PURE__ */ jsxRuntime.jsx(
12769
- chunkWRLGLZIA_cjs.EntityIdentityBar,
12769
+ chunkEMRY62HS_cjs.EntityIdentityBar,
12770
12770
  {
12771
12771
  testId: "workspace-identity-bar",
12772
12772
  canEdit: isOwner,
@@ -12783,7 +12783,7 @@ function ConnectedWorkspaceSettings({
12783
12783
  label: "Name",
12784
12784
  value: workspace.name,
12785
12785
  placeholder: "Untitled",
12786
- maxLength: chunkWRLGLZIA_cjs.IDENTITY_NAME_MAX_LENGTH,
12786
+ maxLength: chunkEMRY62HS_cjs.IDENTITY_NAME_MAX_LENGTH,
12787
12787
  valueClassName: "truncate text-base font-semibold",
12788
12788
  testId: "workspace-home-title",
12789
12789
  hideLabel: true,
@@ -17231,7 +17231,7 @@ function ConnectedWorkspaceList({
17231
17231
  }
17232
17232
  );
17233
17233
  }
17234
- if (list.isLoading) return /* @__PURE__ */ jsxRuntime.jsx(chunkWRLGLZIA_cjs.LoadingIndicator, { message: "Loading workspaces..." });
17234
+ if (list.isLoading) return /* @__PURE__ */ jsxRuntime.jsx(chunkEMRY62HS_cjs.LoadingIndicator, { message: "Loading workspaces..." });
17235
17235
  if (list.error) {
17236
17236
  return /* @__PURE__ */ jsxRuntime.jsx(
17237
17237
  chunkH7PHOTX2_cjs.HomeLoadError,
@@ -17304,7 +17304,7 @@ function ConnectedWorkspaceList({
17304
17304
  workspaceState
17305
17305
  }
17306
17306
  ) })
17307
- ) : /* @__PURE__ */ jsxRuntime.jsx(react$1.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(chunkWRLGLZIA_cjs.LoadingIndicator, { message: "Loading grid..." }), children: /* @__PURE__ */ jsxRuntime.jsx(chunkH7PHOTX2_cjs.HomeCenteredColumn, { children: /* @__PURE__ */ jsxRuntime.jsx(
17307
+ ) : /* @__PURE__ */ jsxRuntime.jsx(react$1.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(chunkEMRY62HS_cjs.LoadingIndicator, { message: "Loading grid..." }), children: /* @__PURE__ */ jsxRuntime.jsx(chunkH7PHOTX2_cjs.HomeCenteredColumn, { children: /* @__PURE__ */ jsxRuntime.jsx(
17308
17308
  WorkspaceTableView,
17309
17309
  {
17310
17310
  list,
@@ -17565,7 +17565,7 @@ function ConnectedProjectsListPage({
17565
17565
  }
17566
17566
  ),
17567
17567
  /* @__PURE__ */ jsxRuntime.jsx(
17568
- chunkWRLGLZIA_cjs.Toolbar,
17568
+ chunkEMRY62HS_cjs.Toolbar,
17569
17569
  {
17570
17570
  search,
17571
17571
  onSearch: setSearch,
@@ -26980,7 +26980,7 @@ function ConnectedSecureMailClaimPage({
26980
26980
  }
26981
26981
  })();
26982
26982
  }, [authenticated, claimId, key]);
26983
- if (!error) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loading ?? /* @__PURE__ */ jsxRuntime.jsx(chunkWRLGLZIA_cjs.LoadingIndicator, { variant: "splash" }) });
26983
+ if (!error) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loading ?? /* @__PURE__ */ jsxRuntime.jsx(chunkEMRY62HS_cjs.LoadingIndicator, { variant: "splash" }) });
26984
26984
  return /* @__PURE__ */ jsxRuntime.jsx("main", { className: "flex min-h-screen items-center justify-center bg-background p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "w-full max-w-md rounded-lg border border-border bg-card p-6", children: [
26985
26985
  /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mb-4 text-sm text-destructive", children: error }),
26986
26986
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -33110,7 +33110,7 @@ function useBatchCompleteToasts() {
33110
33110
  }
33111
33111
  }, AI_FIELDS_NOTICE_WINDOW_MS);
33112
33112
  } else if (message.batch_type === "entity_extract") {
33113
- say(`${chunkWRLGLZIA_cjs.entitiesPhrase()} extracted from ${chunkWRLGLZIA_cjs.documentCount(docIds.length)}`, "success", {
33113
+ say(`${chunkEMRY62HS_cjs.entitiesPhrase()} extracted from ${chunkEMRY62HS_cjs.documentCount(docIds.length)}`, "success", {
33114
33114
  ...openTags && { action: { label: "View", onClick: openTags } }
33115
33115
  });
33116
33116
  } else if (message.batch_type === "upload") {
@@ -33925,10 +33925,10 @@ var DocumentReviewCard = react$1.lazy(
33925
33925
  () => import('../DocumentReviewCard-M53XFLI2.cjs').then((module) => ({ default: module.DocumentReviewCard }))
33926
33926
  );
33927
33927
  var FilesViewerDialog = react$1.lazy(
33928
- () => import('../FilesViewerDialog-4352KIOG.cjs').then((module) => ({ default: module.FilesViewerDialog }))
33928
+ () => import('../FilesViewerDialog-JWKNJLWG.cjs').then((module) => ({ default: module.FilesViewerDialog }))
33929
33929
  );
33930
33930
  function defaultReviewCard(props) {
33931
- return /* @__PURE__ */ jsxRuntime.jsx(react$1.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(chunkWRLGLZIA_cjs.LoadingIndicator, { message: "Loading document viewer..." }), children: /* @__PURE__ */ jsxRuntime.jsx(DocumentReviewCard, { ...props }, `navigator-${props.currentDocument.external_id}`) });
33931
+ return /* @__PURE__ */ jsxRuntime.jsx(react$1.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(chunkEMRY62HS_cjs.LoadingIndicator, { message: "Loading document viewer..." }), children: /* @__PURE__ */ jsxRuntime.jsx(DocumentReviewCard, { ...props }, `navigator-${props.currentDocument.external_id}`) });
33932
33932
  }
33933
33933
  function ConnectedFilesPage({
33934
33934
  isModal = false,
@@ -34506,7 +34506,7 @@ function ConnectedFilesPage({
34506
34506
  viewMode === "grid" ? (
34507
34507
  // ‹ n / N › over the table's displayed rows; a step opens the document.
34508
34508
  /* @__PURE__ */ jsxRuntime.jsx(
34509
- chunkWRLGLZIA_cjs.GridRowNavigator,
34509
+ chunkEMRY62HS_cjs.GridRowNavigator,
34510
34510
  {
34511
34511
  gridApi,
34512
34512
  selectedId: viewingDocumentId ?? selectedDocumentIds[0] ?? null,
@@ -36943,7 +36943,7 @@ function GuidedRuns() {
36943
36943
  chunkOHHKBURG_cjs.useRemoteControlSessionReset();
36944
36944
  const { cursorMark } = chunkORELHENJ_cjs.useGuidedRuns();
36945
36945
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
36946
- /* @__PURE__ */ jsxRuntime.jsx(chunkWRLGLZIA_cjs.GuidedCursor, { markSrc: cursorMark }),
36946
+ /* @__PURE__ */ jsxRuntime.jsx(chunkEMRY62HS_cjs.GuidedCursor, { markSrc: cursorMark }),
36947
36947
  /* @__PURE__ */ jsxRuntime.jsx(ConnectedRemoteControlConsent, {})
36948
36948
  ] });
36949
36949
  }
@@ -36977,7 +36977,7 @@ function ConnectedAppRuntime({
36977
36977
  on("pageTransition") && /* @__PURE__ */ jsxRuntime.jsx(PageTransition, {}),
36978
36978
  on("freshChatModel") && /* @__PURE__ */ jsxRuntime.jsx(FreshChatModel, {}),
36979
36979
  on("workspaceOpenMetrics") && measure && /* @__PURE__ */ jsxRuntime.jsx(WorkspaceOpenMetrics, { measure }),
36980
- on("prefetch") && /* @__PURE__ */ jsxRuntime.jsx(Prefetch, { loaders: [...prefetch ?? [], ...chunkWRLGLZIA_cjs.KIT_CHUNK_LOADERS] }),
36980
+ on("prefetch") && /* @__PURE__ */ jsxRuntime.jsx(Prefetch, { loaders: [...prefetch ?? [], ...chunkEMRY62HS_cjs.KIT_CHUNK_LOADERS] }),
36981
36981
  on("guidedRuns") && /* @__PURE__ */ jsxRuntime.jsx(GuidedRuns, {})
36982
36982
  ] });
36983
36983
  }
@@ -41919,7 +41919,7 @@ function SsoResendVerificationButton({
41919
41919
  onClick: async () => handleResendEmailVerification(),
41920
41920
  disabled: loading || disabled,
41921
41921
  "aria-label": "Resend verification email",
41922
- children: loading ? /* @__PURE__ */ jsxRuntime.jsx(chunkWRLGLZIA_cjs.LoadingIndicator, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
41922
+ children: loading ? /* @__PURE__ */ jsxRuntime.jsx(chunkEMRY62HS_cjs.LoadingIndicator, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
41923
41923
  "Didn't get a verification email? ",
41924
41924
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: "Resend" })
41925
41925
  ] })
@@ -43190,7 +43190,7 @@ function ShellNavigationProvider({
43190
43190
  );
43191
43191
  }
43192
43192
  var ConnectedPresentation = react$1.lazy(
43193
- () => import('../ConnectedPresentation-AU25OW25.cjs').then((m) => ({ default: m.ConnectedPresentation }))
43193
+ () => import('../ConnectedPresentation-OV2KBOLK.cjs').then((m) => ({ default: m.ConnectedPresentation }))
43194
43194
  );
43195
43195
  function PresentationSlot() {
43196
43196
  const session = react.useArbiSessionStore();
@@ -43374,7 +43374,7 @@ function ConnectedTipBar({
43374
43374
  workspaceOpen,
43375
43375
  ...state
43376
43376
  };
43377
- const { tip, index, count: count2, previous, next, onHoverChange } = chunkWRLGLZIA_cjs.useTipsPlacement({
43377
+ const { tip, index, count: count2, previous, next, onHoverChange } = chunkEMRY62HS_cjs.useTipsPlacement({
43378
43378
  registry,
43379
43379
  context,
43380
43380
  state: situation,
@@ -43672,6 +43672,18 @@ function ChromeInstallDialog({
43672
43672
  ] }) });
43673
43673
  }
43674
43674
 
43675
+ Object.defineProperty(exports, "DEFAULT_ASK_SUGGESTIONS", {
43676
+ enumerable: true,
43677
+ get: function () { return chunkVWBYE3XY_cjs.DEFAULT_ASK_SUGGESTIONS; }
43678
+ });
43679
+ Object.defineProperty(exports, "DEFAULT_DOCUMENT_VIEWER_LABELS", {
43680
+ enumerable: true,
43681
+ get: function () { return chunkVWBYE3XY_cjs.DEFAULT_DOCUMENT_VIEWER_LABELS; }
43682
+ });
43683
+ Object.defineProperty(exports, "DEFAULT_DOCUMENT_VIEWER_TABS", {
43684
+ enumerable: true,
43685
+ get: function () { return chunkVWBYE3XY_cjs.DEFAULT_DOCUMENT_VIEWER_TABS; }
43686
+ });
43675
43687
  Object.defineProperty(exports, "ConnectedPanelHost", {
43676
43688
  enumerable: true,
43677
43689
  get: function () { return chunk6OK7ESTL_cjs.ConnectedPanelHost; }
@@ -43748,18 +43760,6 @@ Object.defineProperty(exports, "useMemberLookup", {
43748
43760
  enumerable: true,
43749
43761
  get: function () { return chunkMLA2BJ2Y_cjs.useMemberLookup; }
43750
43762
  });
43751
- Object.defineProperty(exports, "DEFAULT_ASK_SUGGESTIONS", {
43752
- enumerable: true,
43753
- get: function () { return chunkVWBYE3XY_cjs.DEFAULT_ASK_SUGGESTIONS; }
43754
- });
43755
- Object.defineProperty(exports, "DEFAULT_DOCUMENT_VIEWER_LABELS", {
43756
- enumerable: true,
43757
- get: function () { return chunkVWBYE3XY_cjs.DEFAULT_DOCUMENT_VIEWER_LABELS; }
43758
- });
43759
- Object.defineProperty(exports, "DEFAULT_DOCUMENT_VIEWER_TABS", {
43760
- enumerable: true,
43761
- get: function () { return chunkVWBYE3XY_cjs.DEFAULT_DOCUMENT_VIEWER_TABS; }
43762
- });
43763
43763
  Object.defineProperty(exports, "ConnectedAssistantDock", {
43764
43764
  enumerable: true,
43765
43765
  get: function () { return chunk7L4X6QN2_cjs.ConnectedAssistantDock; }
@@ -1,9 +1,12 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkUTJ223TI_cjs = require('../chunk-UTJ223TI.cjs');
5
- require('../chunk-WFMWKPGY.cjs');
6
- require('../chunk-4TTX6ZNS.cjs');
4
+ var chunkBX6G2ZCI_cjs = require('../chunk-BX6G2ZCI.cjs');
5
+ require('../chunk-JITYC4OS.cjs');
6
+ require('../chunk-WVZLAAIZ.cjs');
7
+ require('../chunk-MVXHTAJ4.cjs');
8
+ require('../chunk-ADPRIBSH.cjs');
9
+ require('../chunk-ORNLCBNE.cjs');
7
10
  require('../chunk-4CIVQWAX.cjs');
8
11
  var chunkPL7HUTM3_cjs = require('../chunk-PL7HUTM3.cjs');
9
12
  require('../chunk-GFUOCGY6.cjs');
@@ -20,7 +23,7 @@ require('../chunk-4ONPEVTP.cjs');
20
23
  require('../chunk-V3KLUWQQ.cjs');
21
24
  require('../chunk-P5AQYC4D.cjs');
22
25
  require('../chunk-WAV762GP.cjs');
23
- require('../chunk-LHWOKOMP.cjs');
26
+ require('../chunk-3IH55CDE.cjs');
24
27
  require('../chunk-GNZAH6UI.cjs');
25
28
  require('../chunk-JH6JTI76.cjs');
26
29
  require('../chunk-QQMMCXBP.cjs');
@@ -92,7 +95,7 @@ require('../chunk-PLIF5CUV.cjs');
92
95
 
93
96
  Object.defineProperty(exports, "ConnectedDocumentViewer", {
94
97
  enumerable: true,
95
- get: function () { return chunkUTJ223TI_cjs.ConnectedDocumentViewer; }
98
+ get: function () { return chunkBX6G2ZCI_cjs.ConnectedDocumentViewer; }
96
99
  });
97
100
  Object.defineProperty(exports, "ConnectedDocumentToolsProvider", {
98
101
  enumerable: true,
@@ -5,7 +5,7 @@ import { Pause, Play, Plus } from "lucide-react";
5
5
  import { Button } from "@arbidocs/react/ui";
6
6
  import { ClipCaptureOverlay } from "../../presentation/ClipCaptureOverlay.js";
7
7
  import { formatTime, mediaCaption } from "../../presentation/model.js";
8
- import { usePresentation } from "../../presentation/store.js";
8
+ import { useSpotlight } from "../../presentation/spotlight.js";
9
9
  import { useObjectUrl } from "../../presentation/useObjectUrl.js";
10
10
  const WHOLE = { x: 0, y: 0, w: 1, h: 1 };
11
11
  function ClippingMediaViewer({
@@ -38,7 +38,7 @@ function ClippingMediaViewer({
38
38
  const capture = useCallback(
39
39
  ({ rect, aspect }) => {
40
40
  const start = kind === "video" ? videoRef.current?.currentTime ?? 0 : void 0;
41
- usePresentation.getState().addClip({
41
+ useSpotlight.getState().gather({
42
42
  kind,
43
43
  documentId,
44
44
  fileName,
@@ -54,7 +54,7 @@ function ClippingMediaViewer({
54
54
  [kind, documentId, fileName, file]
55
55
  );
56
56
  return /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-0 flex-col", "data-testid": "clipping-media-viewer", children: [
57
- /* @__PURE__ */ jsx("div", { className: "border-b border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground", children: kind === "video" ? "Drag over the video to clip that area from this moment, or add the whole frame." : "Drag over the part of the image to show it in the presentation." }),
57
+ /* @__PURE__ */ jsx("div", { className: "border-b border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground", children: kind === "video" ? "Drag over the video to clip that area from this moment, or add the whole frame." : "Drag over the part of the image to clip it." }),
58
58
  /* @__PURE__ */ jsx("div", { className: "relative min-h-0 flex-1 bg-black", style: { containerType: "size" }, children: /* @__PURE__ */ jsxs(
59
59
  "div",
60
60
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/presentation/ClippingMediaViewer.tsx"],
4
- "sourcesContent": ["/**\n * An image or a video while clipping for a presentation: drag over it and that area becomes a clip\n * (of a video: from the moment on screen). A video has its own small bar (play / pause, scrub, and\n * \"Add whole frame\"), since the drag area covers the picture.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { Pause, Play, Plus } from 'lucide-react'\nimport { Button } from '@arbidocs/react/ui'\nimport { ClipCaptureOverlay } from '../../presentation/ClipCaptureOverlay'\nimport { formatTime, mediaCaption, type Rect } from '../../presentation/model'\nimport { usePresentation } from '../../presentation/store'\nimport { useObjectUrl } from '../../presentation/useObjectUrl'\n\nexport interface ClippingMediaViewerProps {\n file: Blob\n kind: 'image' | 'video'\n documentId: string\n fileName: string\n}\n\nconst WHOLE: Rect = { x: 0, y: 0, w: 1, h: 1 }\n\nexport function ClippingMediaViewer({\n file,\n kind,\n documentId,\n fileName,\n}: ClippingMediaViewerProps) {\n const url = useObjectUrl(file)\n const videoRef = useRef<HTMLVideoElement>(null)\n const imageRef = useRef<HTMLImageElement>(null)\n // The picture's own width / height, once known.\n const [natural, setNatural] = useState<number | null>(null)\n const [time, setTime] = useState(0)\n const [duration, setDuration] = useState(0)\n const [playing, setPlaying] = useState(false)\n\n // Its size, read as soon as it is known: at once if it already loaded (a cached file can load\n // before any handler is attached), else when it does.\n useEffect(() => {\n const media = videoRef.current ?? imageRef.current\n if (!media || !url) return\n const read = () => {\n const width = media instanceof HTMLVideoElement ? media.videoWidth : media.naturalWidth\n const height = media instanceof HTMLVideoElement ? media.videoHeight : media.naturalHeight\n if (width && height) setNatural(width / height)\n if (media instanceof HTMLVideoElement) setDuration(media.duration || 0)\n }\n read()\n const event = media instanceof HTMLVideoElement ? 'loadedmetadata' : 'load'\n media.addEventListener(event, read)\n return () => media.removeEventListener(event, read)\n }, [url])\n\n const capture = useCallback(\n ({ rect, aspect }: { rect: Rect; aspect: number }) => {\n const start = kind === 'video' ? (videoRef.current?.currentTime ?? 0) : undefined\n usePresentation.getState().addClip({\n kind,\n documentId,\n fileName,\n page: 1,\n rect,\n aspect,\n masks: [],\n source: file,\n start,\n caption: mediaCaption(fileName, start),\n })\n },\n [kind, documentId, fileName, file]\n )\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\" data-testid=\"clipping-media-viewer\">\n <div className=\"border-b border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground\">\n {kind === 'video'\n ? 'Drag over the video to clip that area from this moment, or add the whole frame.'\n : 'Drag over the part of the image to show it in the presentation.'}\n </div>\n <div className=\"relative min-h-0 flex-1 bg-black\" style={{ containerType: 'size' }}>\n {/* The picture as large as fits, aspect kept; the drag area covers exactly it. */}\n <div\n className=\"absolute inset-0 m-auto\"\n style={\n natural\n ? {\n width: `min(100cqw, calc(100cqh * ${natural}))`,\n height: `min(100cqh, calc(100cqw / ${natural}))`,\n }\n : { width: '100%', height: '100%' }\n }\n >\n {kind === 'video' ? (\n <video\n ref={videoRef}\n src={url}\n playsInline\n preload=\"auto\"\n className=\"block h-full w-full\"\n onTimeUpdate={(event) => setTime(event.currentTarget.currentTime)}\n onPlay={() => setPlaying(true)}\n onPause={() => setPlaying(false)}\n />\n ) : (\n <img\n ref={imageRef}\n src={url}\n alt={fileName}\n draggable={false}\n className=\"block h-full w-full select-none\"\n />\n )}\n {natural && <ClipCaptureOverlay page={1} onCapture={capture} />}\n </div>\n </div>\n {kind === 'video' && (\n <div className=\"flex items-center gap-2 border-t border-border px-3 py-1.5\">\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n className=\"size-8\"\n onClick={() => {\n const v = videoRef.current\n if (!v) return\n if (v.paused) void v.play()\n else v.pause()\n }}\n aria-label={playing ? 'Pause' : 'Play'}\n >\n {playing ? <Pause className=\"size-4\" /> : <Play className=\"size-4\" />}\n </Button>\n <input\n type=\"range\"\n min={0}\n max={duration || 0}\n step={0.1}\n value={time}\n onChange={(event) => {\n const v = videoRef.current\n if (v) v.currentTime = Number(event.target.value)\n }}\n className=\"min-w-0 flex-1\"\n aria-label=\"Position in the video\"\n />\n <span className=\"text-xs tabular-nums text-muted-foreground\">\n {formatTime(time)} / {formatTime(duration)}\n </span>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={!natural}\n onClick={() => natural && capture({ rect: WHOLE, aspect: natural })}\n data-testid=\"clip-whole-frame\"\n >\n <Plus className=\"mr-1 size-4\" />\n Add whole frame\n </Button>\n </div>\n )}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * An image or a video while clipping for a presentation: drag over it and that area becomes a clip\n * (of a video: from the moment on screen). A video has its own small bar (play / pause, scrub, and\n * \"Add whole frame\"), since the drag area covers the picture.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { Pause, Play, Plus } from 'lucide-react'\nimport { Button } from '@arbidocs/react/ui'\nimport { ClipCaptureOverlay } from '../../presentation/ClipCaptureOverlay'\nimport { formatTime, mediaCaption, type Rect } from '../../presentation/model'\nimport { useSpotlight } from '../../presentation/spotlight'\nimport { useObjectUrl } from '../../presentation/useObjectUrl'\n\nexport interface ClippingMediaViewerProps {\n file: Blob\n kind: 'image' | 'video'\n documentId: string\n fileName: string\n}\n\nconst WHOLE: Rect = { x: 0, y: 0, w: 1, h: 1 }\n\nexport function ClippingMediaViewer({\n file,\n kind,\n documentId,\n fileName,\n}: ClippingMediaViewerProps) {\n const url = useObjectUrl(file)\n const videoRef = useRef<HTMLVideoElement>(null)\n const imageRef = useRef<HTMLImageElement>(null)\n // The picture's own width / height, once known.\n const [natural, setNatural] = useState<number | null>(null)\n const [time, setTime] = useState(0)\n const [duration, setDuration] = useState(0)\n const [playing, setPlaying] = useState(false)\n\n // Its size, read as soon as it is known: at once if it already loaded (a cached file can load\n // before any handler is attached), else when it does.\n useEffect(() => {\n const media = videoRef.current ?? imageRef.current\n if (!media || !url) return\n const read = () => {\n const width = media instanceof HTMLVideoElement ? media.videoWidth : media.naturalWidth\n const height = media instanceof HTMLVideoElement ? media.videoHeight : media.naturalHeight\n if (width && height) setNatural(width / height)\n if (media instanceof HTMLVideoElement) setDuration(media.duration || 0)\n }\n read()\n const event = media instanceof HTMLVideoElement ? 'loadedmetadata' : 'load'\n media.addEventListener(event, read)\n return () => media.removeEventListener(event, read)\n }, [url])\n\n const capture = useCallback(\n ({ rect, aspect }: { rect: Rect; aspect: number }) => {\n const start = kind === 'video' ? (videoRef.current?.currentTime ?? 0) : undefined\n useSpotlight.getState().gather({\n kind,\n documentId,\n fileName,\n page: 1,\n rect,\n aspect,\n masks: [],\n source: file,\n start,\n caption: mediaCaption(fileName, start),\n })\n },\n [kind, documentId, fileName, file]\n )\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\" data-testid=\"clipping-media-viewer\">\n <div className=\"border-b border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground\">\n {kind === 'video'\n ? 'Drag over the video to clip that area from this moment, or add the whole frame.'\n : 'Drag over the part of the image to clip it.'}\n </div>\n <div className=\"relative min-h-0 flex-1 bg-black\" style={{ containerType: 'size' }}>\n {/* The picture as large as fits, aspect kept; the drag area covers exactly it. */}\n <div\n className=\"absolute inset-0 m-auto\"\n style={\n natural\n ? {\n width: `min(100cqw, calc(100cqh * ${natural}))`,\n height: `min(100cqh, calc(100cqw / ${natural}))`,\n }\n : { width: '100%', height: '100%' }\n }\n >\n {kind === 'video' ? (\n <video\n ref={videoRef}\n src={url}\n playsInline\n preload=\"auto\"\n className=\"block h-full w-full\"\n onTimeUpdate={(event) => setTime(event.currentTarget.currentTime)}\n onPlay={() => setPlaying(true)}\n onPause={() => setPlaying(false)}\n />\n ) : (\n <img\n ref={imageRef}\n src={url}\n alt={fileName}\n draggable={false}\n className=\"block h-full w-full select-none\"\n />\n )}\n {natural && <ClipCaptureOverlay page={1} onCapture={capture} />}\n </div>\n </div>\n {kind === 'video' && (\n <div className=\"flex items-center gap-2 border-t border-border px-3 py-1.5\">\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n className=\"size-8\"\n onClick={() => {\n const v = videoRef.current\n if (!v) return\n if (v.paused) void v.play()\n else v.pause()\n }}\n aria-label={playing ? 'Pause' : 'Play'}\n >\n {playing ? <Pause className=\"size-4\" /> : <Play className=\"size-4\" />}\n </Button>\n <input\n type=\"range\"\n min={0}\n max={duration || 0}\n step={0.1}\n value={time}\n onChange={(event) => {\n const v = videoRef.current\n if (v) v.currentTime = Number(event.target.value)\n }}\n className=\"min-w-0 flex-1\"\n aria-label=\"Position in the video\"\n />\n <span className=\"text-xs tabular-nums text-muted-foreground\">\n {formatTime(time)} / {formatTime(duration)}\n </span>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={!natural}\n onClick={() => natural && capture({ rect: WHOLE, aspect: natural })}\n data-testid=\"clip-whole-frame\"\n >\n <Plus className=\"mr-1 size-4\" />\n Add whole frame\n </Button>\n </div>\n )}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  /**
2
- * The PDF while clipping for a presentation: drag over a page and the area becomes a clip in the
3
- * presentation (and goes on the current slide while that has fewer than two).
2
+ * The PDF while clipping: a click on a passage clips that passage (outlined under the pointer), a
3
+ * drag over a page clips that area. Clips are gathered in the viewer's spotlight strip
4
+ * (`SpotlightStrip`), to show over the document or keep as a slide.
4
5
  *
5
6
  * Redactions are honoured: when the version has markup, its redaction marks (all but rejected
6
7
  * ones) are read first and every clip carries those over its area as black masks, so a redacted
@@ -8,7 +9,7 @@
8
9
  * read.
9
10
  */
10
11
  import { type ComponentType } from 'react';
11
- import type { PdfViewerProps } from '@arbidocs/react/viewers';
12
+ import { type PdfViewerProps } from '@arbidocs/react/viewers';
12
13
  export interface ClippingPdfViewerProps extends Omit<PdfViewerProps, 'renderPageOverlay'> {
13
14
  file: Blob;
14
15
  documentId: string;
@@ -1,9 +1,18 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useCallback, useEffect, useState } from "react";
3
+ import {
4
+ useCallback,
5
+ useEffect,
6
+ useMemo,
7
+ useState
8
+ } from "react";
9
+ import { useParsedDocument } from "@arbidocs/react";
4
10
  import { createMarkupStore, useDocumentTools } from "@arbidocs/react/document-tools";
11
+ import { useProcessedChunks } from "@arbidocs/react/viewers";
5
12
  import { ClipCaptureOverlay } from "../../presentation/ClipCaptureOverlay.js";
6
- import { usePresentation } from "../../presentation/store.js";
13
+ import { passageClipRect } from "../../presentation/passage-clip.js";
14
+ import { useSpotlight } from "../../presentation/spotlight.js";
15
+ import { placedPassagesByPage } from "../viewer/pdf/passageHighlights.js";
7
16
  const NO_MASKS = { status: "ready", masks: /* @__PURE__ */ new Map() };
8
17
  function useRedactionMasks(documentId, version, hasMarkup) {
9
18
  const { client } = useDocumentTools();
@@ -30,6 +39,20 @@ function useRedactionMasks(documentId, version, hasMarkup) {
30
39
  }, [client, documentId, version, hasMarkup]);
31
40
  return state;
32
41
  }
42
+ const NO_FOOTNOTES = {};
43
+ const NO_PASSAGES = /* @__PURE__ */ new Map();
44
+ function usePassageAreas(documentId, current) {
45
+ const { data: parsed } = useParsedDocument(documentId, "final", { enabled: current });
46
+ const { processedChunks } = useProcessedChunks(parsed?.chunks, NO_FOOTNOTES);
47
+ return useMemo(() => {
48
+ if (!current || !processedChunks.length) return NO_PASSAGES;
49
+ const areas = /* @__PURE__ */ new Map();
50
+ for (const [page, boxes] of placedPassagesByPage(processedChunks)) {
51
+ areas.set(page, boxes.map(passageClipRect));
52
+ }
53
+ return areas;
54
+ }, [current, processedChunks]);
55
+ }
33
56
  function Notice({ children }) {
34
57
  return /* @__PURE__ */ jsx("div", { className: "border-b border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground", children });
35
58
  }
@@ -42,11 +65,12 @@ function ClippingPdfViewer({
42
65
  ...viewerProps
43
66
  }) {
44
67
  const masks = useRedactionMasks(documentId, version, hasMarkup);
68
+ const passages = usePassageAreas(documentId, version === void 0);
45
69
  const file = viewerProps.file;
46
70
  const capture = useCallback(
47
71
  ({ page, rect, aspect }) => {
48
72
  if (masks.status !== "ready") return;
49
- usePresentation.getState().addClip({
73
+ useSpotlight.getState().gather({
50
74
  kind: "pdf",
51
75
  documentId,
52
76
  version,
@@ -61,13 +85,28 @@ function ClippingPdfViewer({
61
85
  [masks, documentId, version, fileName, file]
62
86
  );
63
87
  const renderPageOverlay = useCallback(
64
- ({ pageNumber }) => masks.status === "ready" ? /* @__PURE__ */ jsx(ClipCaptureOverlay, { page: pageNumber, onCapture: capture }) : null,
65
- [masks.status, capture]
88
+ ({ pageNumber }) => masks.status === "ready" ? /* @__PURE__ */ jsx(
89
+ ClipCaptureOverlay,
90
+ {
91
+ page: pageNumber,
92
+ passages: passages.get(pageNumber),
93
+ onCapture: capture
94
+ }
95
+ ) : null,
96
+ [masks.status, capture, passages]
97
+ );
98
+ return /* @__PURE__ */ jsxs(
99
+ "div",
100
+ {
101
+ className: "flex h-full min-h-0 flex-col",
102
+ "data-clip-document": documentId,
103
+ "data-testid": "clipping-pdf-viewer",
104
+ children: [
105
+ /* @__PURE__ */ jsx(Notice, { children: masks.status === "loading" ? "Reading the redactions before clipping\u2026" : masks.status === "error" ? "Couldn't read this document's redactions, so it can't be clipped." : passages.size ? "Click a passage to clip it, or drag over any area." : "Drag over the part of a page to clip it." }),
106
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(Viewer, { ...viewerProps, renderPageOverlay }) })
107
+ ]
108
+ }
66
109
  );
67
- return /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-0 flex-col", "data-testid": "clipping-pdf-viewer", children: [
68
- /* @__PURE__ */ jsx(Notice, { children: masks.status === "loading" ? "Reading the redactions before clipping\u2026" : masks.status === "error" ? "Couldn't read this document's redactions, so it can't be clipped." : "Drag over the part of a page to show it in the presentation." }),
69
- /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(Viewer, { ...viewerProps, renderPageOverlay }) })
70
- ] });
71
110
  }
72
111
  export {
73
112
  ClippingPdfViewer
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/connection/presentation/ClippingPdfViewer.tsx"],
4
- "sourcesContent": ["/**\n * The PDF while clipping for a presentation: drag over a page and the area becomes a clip in the\n * presentation (and goes on the current slide while that has fewer than two).\n *\n * Redactions are honoured: when the version has markup, its redaction marks (all but rejected\n * ones) are read first and every clip carries those over its area as black masks, so a redacted\n * passage never reaches a shared screen. Clipping waits for them, and stays off if they cannot be\n * read.\n */\n\nimport { useCallback, useEffect, useState, type ComponentType, type ReactNode } from 'react'\nimport { createMarkupStore, useDocumentTools } from '@arbidocs/react/document-tools'\nimport type { PdfViewerProps } from '@arbidocs/react/viewers'\nimport { ClipCaptureOverlay } from '../../presentation/ClipCaptureOverlay'\nimport type { Rect } from '../../presentation/model'\nimport { usePresentation } from '../../presentation/store'\n\ntype MaskState =\n | { status: 'loading' }\n | { status: 'error' }\n | { status: 'ready'; masks: ReadonlyMap<number, Rect[]> }\n\nconst NO_MASKS: MaskState = { status: 'ready', masks: new Map() }\n\n/** The version's redaction rectangles by page; none to read when it has no markup. */\nfunction useRedactionMasks(documentId: string, version: number | undefined, hasMarkup: boolean) {\n const { client } = useDocumentTools()\n const [state, setState] = useState<MaskState>(hasMarkup ? { status: 'loading' } : NO_MASKS)\n useEffect(() => {\n if (!hasMarkup) {\n setState(NO_MASKS)\n return\n }\n let cancelled = false\n setState({ status: 'loading' })\n createMarkupStore({ version, client })\n .load(documentId)\n .then((layer) => {\n if (cancelled) return\n const masks = new Map<number, Rect[]>()\n for (const mark of layer.annotations) {\n if (mark.kind !== 'redaction' || mark.status === 'rejected') continue\n masks.set(mark.page, [...(masks.get(mark.page) ?? []), ...mark.rects])\n }\n setState({ status: 'ready', masks })\n })\n .catch(() => !cancelled && setState({ status: 'error' }))\n return () => {\n cancelled = true\n }\n }, [client, documentId, version, hasMarkup])\n return state\n}\n\nexport interface ClippingPdfViewerProps extends Omit<PdfViewerProps, 'renderPageOverlay'> {\n file: Blob\n documentId: string\n /** The version on screen when it is an older one. */\n version?: number\n fileName: string\n /** The version has markup, which may hold redactions. */\n hasMarkup: boolean\n viewer: ComponentType<PdfViewerProps>\n}\n\nfunction Notice({ children }: { children: ReactNode }) {\n return (\n <div className=\"border-b border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground\">\n {children}\n </div>\n )\n}\n\nexport function ClippingPdfViewer({\n documentId,\n version,\n fileName,\n hasMarkup,\n viewer: Viewer,\n ...viewerProps\n}: ClippingPdfViewerProps) {\n const masks = useRedactionMasks(documentId, version, hasMarkup)\n const file = viewerProps.file\n\n const capture = useCallback(\n ({ page, rect, aspect }: { page: number; rect: Rect; aspect: number }) => {\n if (masks.status !== 'ready') return\n usePresentation.getState().addClip({\n kind: 'pdf',\n documentId,\n version,\n fileName,\n page,\n rect,\n aspect,\n masks: masks.masks.get(page) ?? [],\n source: file,\n })\n // It joins the presentation's tray (the viewer's Presentation pill counts it).\n },\n [masks, documentId, version, fileName, file]\n )\n\n const renderPageOverlay = useCallback(\n ({ pageNumber }: { pageNumber: number }) =>\n masks.status === 'ready' ? (\n <ClipCaptureOverlay page={pageNumber} onCapture={capture} />\n ) : null,\n [masks.status, capture]\n )\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\" data-testid=\"clipping-pdf-viewer\">\n <Notice>\n {masks.status === 'loading'\n ? 'Reading the redactions before clipping\u2026'\n : masks.status === 'error'\n ? \"Couldn't read this document's redactions, so it can't be clipped.\"\n : 'Drag over the part of a page to show it in the presentation.'}\n </Notice>\n <div className=\"min-h-0 flex-1\">\n <Viewer {...viewerProps} renderPageOverlay={renderPageOverlay} />\n </div>\n </div>\n )\n}\n"],
5
- "mappings": ";AAmEI,cA6CA,YA7CA;AAzDJ,SAAS,aAAa,WAAW,gBAAoD;AACrF,SAAS,mBAAmB,wBAAwB;AAEpD,SAAS,0BAA0B;AAEnC,SAAS,uBAAuB;AAOhC,MAAM,WAAsB,EAAE,QAAQ,SAAS,OAAO,oBAAI,IAAI,EAAE;AAGhE,SAAS,kBAAkB,YAAoB,SAA6B,WAAoB;AAC9F,QAAM,EAAE,OAAO,IAAI,iBAAiB;AACpC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAoB,YAAY,EAAE,QAAQ,UAAU,IAAI,QAAQ;AAC1F,YAAU,MAAM;AACd,QAAI,CAAC,WAAW;AACd,eAAS,QAAQ;AACjB;AAAA,IACF;AACA,QAAI,YAAY;AAChB,aAAS,EAAE,QAAQ,UAAU,CAAC;AAC9B,sBAAkB,EAAE,SAAS,OAAO,CAAC,EAClC,KAAK,UAAU,EACf,KAAK,CAAC,UAAU;AACf,UAAI,UAAW;AACf,YAAM,QAAQ,oBAAI,IAAoB;AACtC,iBAAW,QAAQ,MAAM,aAAa;AACpC,YAAI,KAAK,SAAS,eAAe,KAAK,WAAW,WAAY;AAC7D,cAAM,IAAI,KAAK,MAAM,CAAC,GAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,GAAI,GAAG,KAAK,KAAK,CAAC;AAAA,MACvE;AACA,eAAS,EAAE,QAAQ,SAAS,MAAM,CAAC;AAAA,IACrC,CAAC,EACA,MAAM,MAAM,CAAC,aAAa,SAAS,EAAE,QAAQ,QAAQ,CAAC,CAAC;AAC1D,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,QAAQ,YAAY,SAAS,SAAS,CAAC;AAC3C,SAAO;AACT;AAaA,SAAS,OAAO,EAAE,SAAS,GAA4B;AACrD,SACE,oBAAC,SAAI,WAAU,6EACZ,UACH;AAEJ;AAEO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,GAAG;AACL,GAA2B;AACzB,QAAM,QAAQ,kBAAkB,YAAY,SAAS,SAAS;AAC9D,QAAM,OAAO,YAAY;AAEzB,QAAM,UAAU;AAAA,IACd,CAAC,EAAE,MAAM,MAAM,OAAO,MAAoD;AACxE,UAAI,MAAM,WAAW,QAAS;AAC9B,sBAAgB,SAAS,EAAE,QAAQ;AAAA,QACjC,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,MAAM,MAAM,IAAI,IAAI,KAAK,CAAC;AAAA,QACjC,QAAQ;AAAA,MACV,CAAC;AAAA,IAEH;AAAA,IACA,CAAC,OAAO,YAAY,SAAS,UAAU,IAAI;AAAA,EAC7C;AAEA,QAAM,oBAAoB;AAAA,IACxB,CAAC,EAAE,WAAW,MACZ,MAAM,WAAW,UACf,oBAAC,sBAAmB,MAAM,YAAY,WAAW,SAAS,IACxD;AAAA,IACN,CAAC,MAAM,QAAQ,OAAO;AAAA,EACxB;AAEA,SACE,qBAAC,SAAI,WAAU,gCAA+B,eAAY,uBACxD;AAAA,wBAAC,UACE,gBAAM,WAAW,YACd,iDACA,MAAM,WAAW,UACf,sEACA,gEACR;AAAA,IACA,oBAAC,SAAI,WAAU,kBACb,8BAAC,UAAQ,GAAG,aAAa,mBAAsC,GACjE;AAAA,KACF;AAEJ;",
4
+ "sourcesContent": ["/**\n * The PDF while clipping: a click on a passage clips that passage (outlined under the pointer), a\n * drag over a page clips that area. Clips are gathered in the viewer's spotlight strip\n * (`SpotlightStrip`), to show over the document or keep as a slide.\n *\n * Redactions are honoured: when the version has markup, its redaction marks (all but rejected\n * ones) are read first and every clip carries those over its area as black masks, so a redacted\n * passage never reaches a shared screen. Clipping waits for them, and stays off if they cannot be\n * read.\n */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ComponentType,\n type ReactNode,\n} from 'react'\nimport { useParsedDocument } from '@arbidocs/react'\nimport { createMarkupStore, useDocumentTools } from '@arbidocs/react/document-tools'\nimport { useProcessedChunks, type PdfViewerProps } from '@arbidocs/react/viewers'\nimport { ClipCaptureOverlay } from '../../presentation/ClipCaptureOverlay'\nimport type { Rect } from '../../presentation/model'\nimport { passageClipRect } from '../../presentation/passage-clip'\nimport { useSpotlight } from '../../presentation/spotlight'\nimport { placedPassagesByPage } from '../viewer/pdf/passageHighlights'\n\ntype MaskState =\n | { status: 'loading' }\n | { status: 'error' }\n | { status: 'ready'; masks: ReadonlyMap<number, Rect[]> }\n\nconst NO_MASKS: MaskState = { status: 'ready', masks: new Map() }\n\n/** The version's redaction rectangles by page; none to read when it has no markup. */\nfunction useRedactionMasks(documentId: string, version: number | undefined, hasMarkup: boolean) {\n const { client } = useDocumentTools()\n const [state, setState] = useState<MaskState>(hasMarkup ? { status: 'loading' } : NO_MASKS)\n useEffect(() => {\n if (!hasMarkup) {\n setState(NO_MASKS)\n return\n }\n let cancelled = false\n setState({ status: 'loading' })\n createMarkupStore({ version, client })\n .load(documentId)\n .then((layer) => {\n if (cancelled) return\n const masks = new Map<number, Rect[]>()\n for (const mark of layer.annotations) {\n if (mark.kind !== 'redaction' || mark.status === 'rejected') continue\n masks.set(mark.page, [...(masks.get(mark.page) ?? []), ...mark.rects])\n }\n setState({ status: 'ready', masks })\n })\n .catch(() => !cancelled && setState({ status: 'error' }))\n return () => {\n cancelled = true\n }\n }, [client, documentId, version, hasMarkup])\n return state\n}\n\nconst NO_FOOTNOTES: Record<string, string> = {}\nconst NO_PASSAGES: ReadonlyMap<number, Rect[]> = new Map()\n\n/**\n * The areas a click clips, by page: each passage the parser placed, with its margin. Only for the\n * current version (the passages are its own); an older one is clipped by dragging.\n */\nfunction usePassageAreas(documentId: string, current: boolean): ReadonlyMap<number, Rect[]> {\n const { data: parsed } = useParsedDocument(documentId, 'final', { enabled: current })\n const { processedChunks } = useProcessedChunks(parsed?.chunks, NO_FOOTNOTES)\n return useMemo(() => {\n if (!current || !processedChunks.length) return NO_PASSAGES\n const areas = new Map<number, Rect[]>()\n for (const [page, boxes] of placedPassagesByPage(processedChunks)) {\n areas.set(page, boxes.map(passageClipRect))\n }\n return areas\n }, [current, processedChunks])\n}\n\nexport interface ClippingPdfViewerProps extends Omit<PdfViewerProps, 'renderPageOverlay'> {\n file: Blob\n documentId: string\n /** The version on screen when it is an older one. */\n version?: number\n fileName: string\n /** The version has markup, which may hold redactions. */\n hasMarkup: boolean\n viewer: ComponentType<PdfViewerProps>\n}\n\nfunction Notice({ children }: { children: ReactNode }) {\n return (\n <div className=\"border-b border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground\">\n {children}\n </div>\n )\n}\n\nexport function ClippingPdfViewer({\n documentId,\n version,\n fileName,\n hasMarkup,\n viewer: Viewer,\n ...viewerProps\n}: ClippingPdfViewerProps) {\n const masks = useRedactionMasks(documentId, version, hasMarkup)\n const passages = usePassageAreas(documentId, version === undefined)\n const file = viewerProps.file\n\n const capture = useCallback(\n ({ page, rect, aspect }: { page: number; rect: Rect; aspect: number }) => {\n if (masks.status !== 'ready') return\n useSpotlight.getState().gather({\n kind: 'pdf',\n documentId,\n version,\n fileName,\n page,\n rect,\n aspect,\n masks: masks.masks.get(page) ?? [],\n source: file,\n })\n // It joins the viewer's spotlight strip.\n },\n [masks, documentId, version, fileName, file]\n )\n\n const renderPageOverlay = useCallback(\n ({ pageNumber }: { pageNumber: number }) =>\n masks.status === 'ready' ? (\n <ClipCaptureOverlay\n page={pageNumber}\n passages={passages.get(pageNumber)}\n onCapture={capture}\n />\n ) : null,\n [masks.status, capture, passages]\n )\n\n return (\n <div\n className=\"flex h-full min-h-0 flex-col\"\n // The spotlight finds a clip's page here, to fly it from there.\n data-clip-document={documentId}\n data-testid=\"clipping-pdf-viewer\"\n >\n <Notice>\n {masks.status === 'loading'\n ? 'Reading the redactions before clipping\u2026'\n : masks.status === 'error'\n ? \"Couldn't read this document's redactions, so it can't be clipped.\"\n : passages.size\n ? 'Click a passage to clip it, or drag over any area.'\n : 'Drag over the part of a page to clip it.'}\n </Notice>\n <div className=\"min-h-0 flex-1\">\n <Viewer {...viewerProps} renderPageOverlay={renderPageOverlay} />\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }