@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.
- package/dist/{ClippingMediaViewer-IEIBT74X.cjs → ClippingMediaViewer-ZFEX5A3U.cjs} +11 -10
- package/dist/ClippingMediaViewer-ZFEX5A3U.cjs.map +1 -0
- package/dist/{ClippingPdfViewer-OGYLMVCE.cjs → ClippingPdfViewer-3LRTEPHV.cjs} +45 -11
- package/dist/ClippingPdfViewer-3LRTEPHV.cjs.map +1 -0
- package/dist/{ConnectedPresentation-AU25OW25.cjs → ConnectedPresentation-OV2KBOLK.cjs} +27 -153
- package/dist/ConnectedPresentation-OV2KBOLK.cjs.map +1 -0
- package/dist/{ConnectedSlidesTab-I75LKKN7.cjs → ConnectedSlidesTab-LUAGZ6FD.cjs} +60 -36
- package/dist/ConnectedSlidesTab-LUAGZ6FD.cjs.map +1 -0
- package/dist/{FilesViewerDialog-4352KIOG.cjs → FilesViewerDialog-JWKNJLWG.cjs} +10 -7
- package/dist/FilesViewerDialog-JWKNJLWG.cjs.map +1 -0
- package/dist/SpotlightStrip-ED22UYTM.cjs +398 -0
- package/dist/SpotlightStrip-ED22UYTM.cjs.map +1 -0
- package/dist/{chunk-LHWOKOMP.cjs → chunk-3IH55CDE.cjs} +4 -4
- package/dist/chunk-3IH55CDE.cjs.map +1 -0
- package/dist/chunk-3ZZZO4F7.cjs +145 -0
- package/dist/chunk-3ZZZO4F7.cjs.map +1 -0
- package/dist/{chunk-WFMWKPGY.cjs → chunk-ADPRIBSH.cjs} +9 -33
- package/dist/chunk-ADPRIBSH.cjs.map +1 -0
- package/dist/{chunk-UTJ223TI.cjs → chunk-BX6G2ZCI.cjs} +138 -146
- package/dist/chunk-BX6G2ZCI.cjs.map +1 -0
- package/dist/{chunk-WRLGLZIA.cjs → chunk-EMRY62HS.cjs} +2 -2
- package/dist/{chunk-WRLGLZIA.cjs.map → chunk-EMRY62HS.cjs.map} +1 -1
- package/dist/{chunk-USNTRL22.cjs → chunk-H236SNEV.cjs} +199 -1616
- package/dist/chunk-H236SNEV.cjs.map +1 -0
- package/dist/chunk-JITYC4OS.cjs +66 -0
- package/dist/chunk-JITYC4OS.cjs.map +1 -0
- package/dist/chunk-JY7UUZQG.cjs +1513 -0
- package/dist/chunk-JY7UUZQG.cjs.map +1 -0
- package/dist/chunk-MVXHTAJ4.cjs +111 -0
- package/dist/chunk-MVXHTAJ4.cjs.map +1 -0
- package/dist/{chunk-4TTX6ZNS.cjs → chunk-ORNLCBNE.cjs} +24 -2
- package/dist/chunk-ORNLCBNE.cjs.map +1 -0
- package/dist/chunk-WVZLAAIZ.cjs +31 -0
- package/dist/chunk-WVZLAAIZ.cjs.map +1 -0
- package/dist/chunk-ZZZITHGK.cjs +119 -0
- package/dist/chunk-ZZZITHGK.cjs.map +1 -0
- package/dist/connect/index.cjs +52 -52
- package/dist/connect/viewer.cjs +8 -5
- package/dist/connection/presentation/ClippingMediaViewer.js +3 -3
- package/dist/connection/presentation/ClippingMediaViewer.js.map +2 -2
- package/dist/connection/presentation/ClippingPdfViewer.d.ts +4 -3
- package/dist/connection/presentation/ClippingPdfViewer.js +48 -9
- package/dist/connection/presentation/ClippingPdfViewer.js.map +2 -2
- package/dist/connection/presentation/ConnectedSlidesTab.js +35 -13
- package/dist/connection/presentation/ConnectedSlidesTab.js.map +2 -2
- package/dist/connection/presentation/SpotlightLayer.d.ts +5 -0
- package/dist/connection/presentation/SpotlightLayer.js +19 -0
- package/dist/connection/presentation/SpotlightLayer.js.map +7 -0
- package/dist/connection/presentation/SpotlightStrip.d.ts +10 -0
- package/dist/connection/presentation/SpotlightStrip.js +237 -0
- package/dist/connection/presentation/SpotlightStrip.js.map +7 -0
- package/dist/connection/presentation/useViewerClipping.d.ts +4 -3
- package/dist/connection/presentation/useViewerClipping.js +8 -4
- package/dist/connection/presentation/useViewerClipping.js.map +2 -2
- package/dist/connection/viewer/ConnectedDocumentViewer.js +52 -61
- package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
- package/dist/connection/viewer/ViewerMoreMenu.d.ts +18 -0
- package/dist/connection/viewer/ViewerMoreMenu.js +45 -0
- package/dist/connection/viewer/ViewerMoreMenu.js.map +7 -0
- package/dist/connection/viewer/pdf/PdfPassageHighlights.js +3 -2
- package/dist/connection/viewer/pdf/PdfPassageHighlights.js.map +2 -2
- package/dist/connection/viewer/pdf/passageHighlights.d.ts +5 -0
- package/dist/connection/viewer/pdf/passageHighlights.js +14 -1
- package/dist/connection/viewer/pdf/passageHighlights.js.map +2 -2
- package/dist/connection/viewer/useCleanView.d.ts +3 -1
- package/dist/connection/viewer/useCleanView.js +6 -3
- package/dist/connection/viewer/useCleanView.js.map +2 -2
- package/dist/document-tools/DocumentToolButtons.js +3 -3
- package/dist/document-tools/DocumentToolButtons.js.map +2 -2
- package/dist/document-tools/index.cjs +13 -13
- package/dist/index.cjs +53 -53
- package/dist/presentation/BoxActionBar.d.ts +2 -2
- package/dist/presentation/BoxActionBar.js +62 -30
- package/dist/presentation/BoxActionBar.js.map +2 -2
- package/dist/presentation/ClipActionBar.js +60 -7
- package/dist/presentation/ClipActionBar.js.map +2 -2
- package/dist/presentation/ClipCaptureOverlay.d.ts +7 -3
- package/dist/presentation/ClipCaptureOverlay.js +43 -14
- package/dist/presentation/ClipCaptureOverlay.js.map +2 -2
- package/dist/presentation/ClipViewControls.d.ts +3 -3
- package/dist/presentation/ClipViewControls.js +59 -64
- package/dist/presentation/ClipViewControls.js.map +2 -2
- package/dist/presentation/PresentControls.d.ts +8 -0
- package/dist/presentation/PresentControls.js +1 -0
- package/dist/presentation/PresentControls.js.map +2 -2
- package/dist/presentation/PresentationStage.d.ts +10 -2
- package/dist/presentation/PresentationStage.js +6 -3
- package/dist/presentation/PresentationStage.js.map +2 -2
- package/dist/presentation/PresenterView.js +1 -22
- package/dist/presentation/PresenterView.js.map +2 -2
- package/dist/presentation/SlidesEditor.js +56 -42
- package/dist/presentation/SlidesEditor.js.map +2 -2
- package/dist/presentation/SpotlightView.d.ts +19 -0
- package/dist/presentation/SpotlightView.js +180 -0
- package/dist/presentation/SpotlightView.js.map +7 -0
- package/dist/presentation/StageItem.js +0 -5
- package/dist/presentation/StageItem.js.map +2 -2
- package/dist/presentation/passage-clip.d.ts +17 -0
- package/dist/presentation/passage-clip.js +25 -0
- package/dist/presentation/passage-clip.js.map +7 -0
- package/dist/presentation/spotlight.d.ts +58 -0
- package/dist/presentation/spotlight.js +110 -0
- package/dist/presentation/spotlight.js.map +7 -0
- package/dist/presentation/store.d.ts +5 -0
- package/dist/presentation/store.js +19 -0
- package/dist/presentation/store.js.map +2 -2
- package/dist/presentation/usePointerActive.d.ts +2 -0
- package/dist/presentation/usePointerActive.js +28 -0
- package/dist/presentation/usePointerActive.js.map +7 -0
- package/dist/styles.css +1 -1
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +5 -5
- package/dist/ClippingMediaViewer-IEIBT74X.cjs.map +0 -1
- package/dist/ClippingPdfViewer-OGYLMVCE.cjs.map +0 -1
- package/dist/ConnectedPresentation-AU25OW25.cjs.map +0 -1
- package/dist/ConnectedSlidesTab-I75LKKN7.cjs.map +0 -1
- package/dist/FilesViewerDialog-4352KIOG.cjs.map +0 -1
- package/dist/chunk-4TTX6ZNS.cjs.map +0 -1
- package/dist/chunk-LHWOKOMP.cjs.map +0 -1
- package/dist/chunk-USNTRL22.cjs.map +0 -1
- package/dist/chunk-UTJ223TI.cjs.map +0 -1
- package/dist/chunk-WFMWKPGY.cjs.map +0 -1
- package/dist/chunk-XK4TVJKD.cjs +0 -73
- package/dist/chunk-XK4TVJKD.cjs.map +0 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var chunkZZZITHGK_cjs = require('./chunk-ZZZITHGK.cjs');
|
|
4
5
|
var chunkWOOOMTTA_cjs = require('./chunk-WOOOMTTA.cjs');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
6
|
+
var chunkMVXHTAJ4_cjs = require('./chunk-MVXHTAJ4.cjs');
|
|
7
|
+
var chunkORNLCBNE_cjs = require('./chunk-ORNLCBNE.cjs');
|
|
7
8
|
require('./chunk-GFUOCGY6.cjs');
|
|
8
9
|
var react = require('react');
|
|
9
10
|
var lucideReact = require('lucide-react');
|
|
@@ -41,7 +42,7 @@ function ClippingMediaViewer({
|
|
|
41
42
|
const capture = react.useCallback(
|
|
42
43
|
({ rect, aspect }) => {
|
|
43
44
|
const start = kind === "video" ? videoRef.current?.currentTime ?? 0 : void 0;
|
|
44
|
-
|
|
45
|
+
chunkMVXHTAJ4_cjs.useSpotlight.getState().gather({
|
|
45
46
|
kind,
|
|
46
47
|
documentId,
|
|
47
48
|
fileName,
|
|
@@ -51,13 +52,13 @@ function ClippingMediaViewer({
|
|
|
51
52
|
masks: [],
|
|
52
53
|
source: file,
|
|
53
54
|
start,
|
|
54
|
-
caption:
|
|
55
|
+
caption: chunkORNLCBNE_cjs.mediaCaption(fileName, start)
|
|
55
56
|
});
|
|
56
57
|
},
|
|
57
58
|
[kind, documentId, fileName, file]
|
|
58
59
|
);
|
|
59
60
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full min-h-0 flex-col", "data-testid": "clipping-media-viewer", children: [
|
|
60
|
-
/* @__PURE__ */ jsxRuntime.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
|
|
61
|
+
/* @__PURE__ */ jsxRuntime.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." }),
|
|
61
62
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative min-h-0 flex-1 bg-black", style: { containerType: "size" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
62
63
|
"div",
|
|
63
64
|
{
|
|
@@ -89,7 +90,7 @@ function ClippingMediaViewer({
|
|
|
89
90
|
className: "block h-full w-full select-none"
|
|
90
91
|
}
|
|
91
92
|
),
|
|
92
|
-
natural && /* @__PURE__ */ jsxRuntime.jsx(
|
|
93
|
+
natural && /* @__PURE__ */ jsxRuntime.jsx(chunkZZZITHGK_cjs.ClipCaptureOverlay, { page: 1, onCapture: capture })
|
|
93
94
|
]
|
|
94
95
|
}
|
|
95
96
|
) }),
|
|
@@ -128,9 +129,9 @@ function ClippingMediaViewer({
|
|
|
128
129
|
}
|
|
129
130
|
),
|
|
130
131
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs tabular-nums text-muted-foreground", children: [
|
|
131
|
-
|
|
132
|
+
chunkORNLCBNE_cjs.formatTime(time),
|
|
132
133
|
" / ",
|
|
133
|
-
|
|
134
|
+
chunkORNLCBNE_cjs.formatTime(duration)
|
|
134
135
|
] }),
|
|
135
136
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
136
137
|
ui.Button,
|
|
@@ -152,5 +153,5 @@ function ClippingMediaViewer({
|
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
exports.ClippingMediaViewer = ClippingMediaViewer;
|
|
155
|
-
//# sourceMappingURL=ClippingMediaViewer-
|
|
156
|
-
//# sourceMappingURL=ClippingMediaViewer-
|
|
156
|
+
//# sourceMappingURL=ClippingMediaViewer-ZFEX5A3U.cjs.map
|
|
157
|
+
//# sourceMappingURL=ClippingMediaViewer-ZFEX5A3U.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connection/presentation/ClippingMediaViewer.tsx"],"names":["useObjectUrl","useRef","useState","useEffect","useCallback","useSpotlight","mediaCaption","jsxs","jsx","ClipCaptureOverlay","Button","Pause","Play","formatTime","Plus"],"mappings":"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","file":"ClippingMediaViewer-ZFEX5A3U.cjs","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"]}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var chunkZZZITHGK_cjs = require('./chunk-ZZZITHGK.cjs');
|
|
5
|
+
var chunkJITYC4OS_cjs = require('./chunk-JITYC4OS.cjs');
|
|
6
|
+
var chunkMVXHTAJ4_cjs = require('./chunk-MVXHTAJ4.cjs');
|
|
7
|
+
require('./chunk-ORNLCBNE.cjs');
|
|
6
8
|
require('./chunk-GFUOCGY6.cjs');
|
|
7
9
|
var react = require('react');
|
|
10
|
+
var react$1 = require('@arbidocs/react');
|
|
8
11
|
var documentTools = require('@arbidocs/react/document-tools');
|
|
12
|
+
var viewers = require('@arbidocs/react/viewers');
|
|
9
13
|
var jsxRuntime = require('react/jsx-runtime');
|
|
10
14
|
|
|
11
15
|
var NO_MASKS = { status: "ready", masks: /* @__PURE__ */ new Map() };
|
|
@@ -34,6 +38,20 @@ function useRedactionMasks(documentId, version, hasMarkup) {
|
|
|
34
38
|
}, [client, documentId, version, hasMarkup]);
|
|
35
39
|
return state;
|
|
36
40
|
}
|
|
41
|
+
var NO_FOOTNOTES = {};
|
|
42
|
+
var NO_PASSAGES = /* @__PURE__ */ new Map();
|
|
43
|
+
function usePassageAreas(documentId, current) {
|
|
44
|
+
const { data: parsed } = react$1.useParsedDocument(documentId, "final", { enabled: current });
|
|
45
|
+
const { processedChunks } = viewers.useProcessedChunks(parsed?.chunks, NO_FOOTNOTES);
|
|
46
|
+
return react.useMemo(() => {
|
|
47
|
+
if (!current || !processedChunks.length) return NO_PASSAGES;
|
|
48
|
+
const areas = /* @__PURE__ */ new Map();
|
|
49
|
+
for (const [page, boxes] of chunkJITYC4OS_cjs.placedPassagesByPage(processedChunks)) {
|
|
50
|
+
areas.set(page, boxes.map(chunkZZZITHGK_cjs.passageClipRect));
|
|
51
|
+
}
|
|
52
|
+
return areas;
|
|
53
|
+
}, [current, processedChunks]);
|
|
54
|
+
}
|
|
37
55
|
function Notice({ children }) {
|
|
38
56
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground", children });
|
|
39
57
|
}
|
|
@@ -46,11 +64,12 @@ function ClippingPdfViewer({
|
|
|
46
64
|
...viewerProps
|
|
47
65
|
}) {
|
|
48
66
|
const masks = useRedactionMasks(documentId, version, hasMarkup);
|
|
67
|
+
const passages = usePassageAreas(documentId, version === void 0);
|
|
49
68
|
const file = viewerProps.file;
|
|
50
69
|
const capture = react.useCallback(
|
|
51
70
|
({ page, rect, aspect }) => {
|
|
52
71
|
if (masks.status !== "ready") return;
|
|
53
|
-
|
|
72
|
+
chunkMVXHTAJ4_cjs.useSpotlight.getState().gather({
|
|
54
73
|
kind: "pdf",
|
|
55
74
|
documentId,
|
|
56
75
|
version,
|
|
@@ -65,15 +84,30 @@ function ClippingPdfViewer({
|
|
|
65
84
|
[masks, documentId, version, fileName, file]
|
|
66
85
|
);
|
|
67
86
|
const renderPageOverlay = react.useCallback(
|
|
68
|
-
({ pageNumber }) => masks.status === "ready" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
69
|
-
|
|
87
|
+
({ pageNumber }) => masks.status === "ready" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
88
|
+
chunkZZZITHGK_cjs.ClipCaptureOverlay,
|
|
89
|
+
{
|
|
90
|
+
page: pageNumber,
|
|
91
|
+
passages: passages.get(pageNumber),
|
|
92
|
+
onCapture: capture
|
|
93
|
+
}
|
|
94
|
+
) : null,
|
|
95
|
+
[masks.status, capture, passages]
|
|
96
|
+
);
|
|
97
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
98
|
+
"div",
|
|
99
|
+
{
|
|
100
|
+
className: "flex h-full min-h-0 flex-col",
|
|
101
|
+
"data-clip-document": documentId,
|
|
102
|
+
"data-testid": "clipping-pdf-viewer",
|
|
103
|
+
children: [
|
|
104
|
+
/* @__PURE__ */ jsxRuntime.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." }),
|
|
105
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(Viewer, { ...viewerProps, renderPageOverlay }) })
|
|
106
|
+
]
|
|
107
|
+
}
|
|
70
108
|
);
|
|
71
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full min-h-0 flex-col", "data-testid": "clipping-pdf-viewer", children: [
|
|
72
|
-
/* @__PURE__ */ jsxRuntime.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." }),
|
|
73
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(Viewer, { ...viewerProps, renderPageOverlay }) })
|
|
74
|
-
] });
|
|
75
109
|
}
|
|
76
110
|
|
|
77
111
|
exports.ClippingPdfViewer = ClippingPdfViewer;
|
|
78
|
-
//# sourceMappingURL=ClippingPdfViewer-
|
|
79
|
-
//# sourceMappingURL=ClippingPdfViewer-
|
|
112
|
+
//# sourceMappingURL=ClippingPdfViewer-3LRTEPHV.cjs.map
|
|
113
|
+
//# sourceMappingURL=ClippingPdfViewer-3LRTEPHV.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connection/presentation/ClippingPdfViewer.tsx"],"names":["useDocumentTools","useState","useEffect","createMarkupStore","useParsedDocument","useProcessedChunks","useMemo","placedPassagesByPage","passageClipRect","jsx","useCallback","useSpotlight","ClipCaptureOverlay","jsxs"],"mappings":"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","file":"ClippingPdfViewer-3LRTEPHV.cjs","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…'\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"]}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkH236SNEV_cjs = require('./chunk-H236SNEV.cjs');
|
|
5
|
+
var chunk3ZZZO4F7_cjs = require('./chunk-3ZZZO4F7.cjs');
|
|
6
|
+
var chunkJY7UUZQG_cjs = require('./chunk-JY7UUZQG.cjs');
|
|
5
7
|
require('./chunk-WOOOMTTA.cjs');
|
|
6
8
|
var chunk6OK7ESTL_cjs = require('./chunk-6OK7ESTL.cjs');
|
|
7
9
|
require('./chunk-5GCCUXMT.cjs');
|
|
8
10
|
require('./chunk-2F57IO7S.cjs');
|
|
9
11
|
require('./chunk-UFT22LAB.cjs');
|
|
10
|
-
|
|
11
|
-
var
|
|
12
|
+
require('./chunk-WVZLAAIZ.cjs');
|
|
13
|
+
var chunkADPRIBSH_cjs = require('./chunk-ADPRIBSH.cjs');
|
|
14
|
+
var chunkORNLCBNE_cjs = require('./chunk-ORNLCBNE.cjs');
|
|
12
15
|
var chunkPL7HUTM3_cjs = require('./chunk-PL7HUTM3.cjs');
|
|
13
16
|
var chunkGFUOCGY6_cjs = require('./chunk-GFUOCGY6.cjs');
|
|
14
17
|
require('./chunk-HYUKPHCT.cjs');
|
|
@@ -43,113 +46,6 @@ var react = require('@arbidocs/react');
|
|
|
43
46
|
var ui = require('@arbidocs/react/ui');
|
|
44
47
|
var jsxRuntime = require('react/jsx-runtime');
|
|
45
48
|
|
|
46
|
-
var CONTROL = "inline-flex size-8 items-center justify-center rounded-full text-white/85 hover:bg-white/15 hover:text-white disabled:opacity-30 disabled:hover:bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/60 pointer-coarse:size-11";
|
|
47
|
-
function Control({
|
|
48
|
-
label,
|
|
49
|
-
onClick,
|
|
50
|
-
disabled,
|
|
51
|
-
children,
|
|
52
|
-
testId
|
|
53
|
-
}) {
|
|
54
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
55
|
-
"button",
|
|
56
|
-
{
|
|
57
|
-
type: "button",
|
|
58
|
-
className: CONTROL,
|
|
59
|
-
title: label,
|
|
60
|
-
"aria-label": label,
|
|
61
|
-
disabled,
|
|
62
|
-
onClick: (event) => {
|
|
63
|
-
event.stopPropagation();
|
|
64
|
-
onClick();
|
|
65
|
-
},
|
|
66
|
-
"data-testid": testId,
|
|
67
|
-
children
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
function PresentControls({ view, shown }) {
|
|
72
|
-
const current = chunk4TTX6ZNS_cjs.usePresentation((s) => s.current);
|
|
73
|
-
const count = chunk4TTX6ZNS_cjs.usePresentation((s) => s.slides.length);
|
|
74
|
-
const blank = chunk4TTX6ZNS_cjs.usePresentation((s) => s.blank);
|
|
75
|
-
const actions = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
76
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
77
|
-
"div",
|
|
78
|
-
{
|
|
79
|
-
className: ui.cn(
|
|
80
|
-
"absolute bottom-4 left-4 z-30 flex items-center gap-0.5 rounded-full bg-black/60 p-1 text-white shadow-lg backdrop-blur transition-opacity duration-300",
|
|
81
|
-
shown ? "opacity-100" : "pointer-events-none opacity-0"
|
|
82
|
-
),
|
|
83
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
84
|
-
onDoubleClick: (event) => event.stopPropagation(),
|
|
85
|
-
role: "toolbar",
|
|
86
|
-
"aria-label": "Slideshow",
|
|
87
|
-
"data-testid": "present-controls",
|
|
88
|
-
children: [
|
|
89
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
90
|
-
Control,
|
|
91
|
-
{
|
|
92
|
-
label: "Previous slide (\u2190)",
|
|
93
|
-
onClick: () => actions.goTo(current - 1),
|
|
94
|
-
disabled: current === 0,
|
|
95
|
-
testId: "present-previous",
|
|
96
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "size-4" })
|
|
97
|
-
}
|
|
98
|
-
),
|
|
99
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
100
|
-
"span",
|
|
101
|
-
{
|
|
102
|
-
className: "min-w-12 text-center text-xs tabular-nums text-white/85",
|
|
103
|
-
"data-testid": "present-position",
|
|
104
|
-
children: [
|
|
105
|
-
current + 1,
|
|
106
|
-
" / ",
|
|
107
|
-
count
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
),
|
|
111
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
112
|
-
Control,
|
|
113
|
-
{
|
|
114
|
-
label: "Next slide (\u2192, or click the slide)",
|
|
115
|
-
onClick: () => actions.goTo(current + 1),
|
|
116
|
-
disabled: current >= count - 1,
|
|
117
|
-
testId: "present-next",
|
|
118
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4" })
|
|
119
|
-
}
|
|
120
|
-
),
|
|
121
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-1 h-4 w-px bg-white/25" }),
|
|
122
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
123
|
-
Control,
|
|
124
|
-
{
|
|
125
|
-
label: blank ? "Show the slide (B)" : "Blank the screen (B)",
|
|
126
|
-
onClick: () => actions.setBlank(!blank),
|
|
127
|
-
testId: "present-blank",
|
|
128
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: ui.cn("size-4", blank && "text-amber-300") })
|
|
129
|
-
}
|
|
130
|
-
),
|
|
131
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
132
|
-
Control,
|
|
133
|
-
{
|
|
134
|
-
label: "Full screen (F)",
|
|
135
|
-
onClick: () => view && chunkWFMWKPGY_cjs.toggleFullscreen(view),
|
|
136
|
-
testId: "present-fullscreen",
|
|
137
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize, { className: "size-4" })
|
|
138
|
-
}
|
|
139
|
-
),
|
|
140
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
141
|
-
Control,
|
|
142
|
-
{
|
|
143
|
-
label: "Stop presenting (Esc)",
|
|
144
|
-
onClick: () => actions.setPresenting(false),
|
|
145
|
-
testId: "present-stop",
|
|
146
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { className: "size-3.5 fill-current" })
|
|
147
|
-
}
|
|
148
|
-
)
|
|
149
|
-
]
|
|
150
|
-
}
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
49
|
var PRESENT_WIDTH = 1280;
|
|
154
50
|
function useStageShapedWindow(view, presenting) {
|
|
155
51
|
react$1.useEffect(() => {
|
|
@@ -162,11 +58,11 @@ function useStageShapedWindow(view, presenting) {
|
|
|
162
58
|
Math.min(PRESENT_WIDTH, Math.round((view.screen.availWidth - chromeWidth) * 0.6))
|
|
163
59
|
);
|
|
164
60
|
const height = Math.min(
|
|
165
|
-
Math.round(width /
|
|
61
|
+
Math.round(width / chunkORNLCBNE_cjs.STAGE_ASPECT),
|
|
166
62
|
view.screen.availHeight - chromeHeight
|
|
167
63
|
);
|
|
168
64
|
try {
|
|
169
|
-
view.resizeTo(Math.round(height *
|
|
65
|
+
view.resizeTo(Math.round(height * chunkORNLCBNE_cjs.STAGE_ASPECT) + chromeWidth, height + chromeHeight);
|
|
170
66
|
} catch {
|
|
171
67
|
return;
|
|
172
68
|
}
|
|
@@ -178,37 +74,15 @@ function useStageShapedWindow(view, presenting) {
|
|
|
178
74
|
};
|
|
179
75
|
}, [view, presenting]);
|
|
180
76
|
}
|
|
181
|
-
var IDLE_MS = 2200;
|
|
182
|
-
function usePointerActive(view) {
|
|
183
|
-
const [active, setActive] = react$1.useState(true);
|
|
184
|
-
react$1.useEffect(() => {
|
|
185
|
-
if (!view) return;
|
|
186
|
-
setActive(true);
|
|
187
|
-
let timer = view.setTimeout(() => setActive(false), IDLE_MS);
|
|
188
|
-
const wake = () => {
|
|
189
|
-
setActive(true);
|
|
190
|
-
view.clearTimeout(timer);
|
|
191
|
-
timer = view.setTimeout(() => setActive(false), IDLE_MS);
|
|
192
|
-
};
|
|
193
|
-
view.addEventListener("pointermove", wake);
|
|
194
|
-
view.addEventListener("keydown", wake);
|
|
195
|
-
return () => {
|
|
196
|
-
view.clearTimeout(timer);
|
|
197
|
-
view.removeEventListener("pointermove", wake);
|
|
198
|
-
view.removeEventListener("keydown", wake);
|
|
199
|
-
};
|
|
200
|
-
}, [view]);
|
|
201
|
-
return active;
|
|
202
|
-
}
|
|
203
77
|
function PresenterView({ onPresent, ...editor }) {
|
|
204
|
-
const presenting =
|
|
78
|
+
const presenting = chunkORNLCBNE_cjs.usePresentation((s) => s.presenting);
|
|
205
79
|
const [view, setView] = react$1.useState(null);
|
|
206
80
|
const rootRef = react$1.useCallback((node) => {
|
|
207
81
|
if (node) setView(node.ownerDocument.defaultView);
|
|
208
82
|
}, []);
|
|
209
|
-
|
|
83
|
+
chunkADPRIBSH_cjs.usePresenterKeys(presenting ? view : null, true);
|
|
210
84
|
useStageShapedWindow(view, presenting);
|
|
211
|
-
const active = usePointerActive(presenting ? view : null);
|
|
85
|
+
const active = chunk3ZZZO4F7_cjs.usePointerActive(presenting ? view : null);
|
|
212
86
|
if (presenting) {
|
|
213
87
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
214
88
|
"div",
|
|
@@ -217,23 +91,23 @@ function PresenterView({ onPresent, ...editor }) {
|
|
|
217
91
|
className: "relative h-full w-full select-none bg-black",
|
|
218
92
|
style: { cursor: active ? "default" : "none" },
|
|
219
93
|
onClick: () => {
|
|
220
|
-
const state =
|
|
94
|
+
const state = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
221
95
|
state.goTo(state.current + 1);
|
|
222
96
|
},
|
|
223
|
-
onDoubleClick: () => view &&
|
|
97
|
+
onDoubleClick: () => view && chunkADPRIBSH_cjs.toggleFullscreen(view),
|
|
224
98
|
"data-testid": "presentation-present",
|
|
225
99
|
children: [
|
|
226
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
227
|
-
/* @__PURE__ */ jsxRuntime.jsx(PresentControls, { view, shown: active })
|
|
100
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkJY7UUZQG_cjs.PresentationStage, {}),
|
|
101
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk3ZZZO4F7_cjs.PresentControls, { view, shown: active })
|
|
228
102
|
]
|
|
229
103
|
}
|
|
230
104
|
);
|
|
231
105
|
}
|
|
232
106
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: rootRef, className: "h-full min-h-0", "data-testid": "presenter-view", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
233
|
-
|
|
107
|
+
chunkH236SNEV_cjs.SlidesEditor,
|
|
234
108
|
{
|
|
235
109
|
...editor,
|
|
236
|
-
onPresent: onPresent ?? (() =>
|
|
110
|
+
onPresent: onPresent ?? (() => chunkORNLCBNE_cjs.usePresentation.getState().setPresenting(true))
|
|
237
111
|
}
|
|
238
112
|
) });
|
|
239
113
|
}
|
|
@@ -242,31 +116,31 @@ function ConnectedPresentation() {
|
|
|
242
116
|
}
|
|
243
117
|
function PresentationWindow() {
|
|
244
118
|
const session = react.useArbiSessionStore();
|
|
245
|
-
const notify =
|
|
246
|
-
const presenting =
|
|
119
|
+
const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
|
|
120
|
+
const presenting = chunkORNLCBNE_cjs.usePresentation((s) => s.presenting);
|
|
247
121
|
const isOpen = react.useArbiSessionState((state) => react.isPanelOpen(state, chunkGFUOCGY6_cjs.PRESENTATION_PANEL));
|
|
248
122
|
const { user } = react.useArbiSession();
|
|
249
123
|
const userId = user?.external_id ?? null;
|
|
250
124
|
const shownFor = react$1.useRef(userId);
|
|
251
|
-
const { downloadFile } =
|
|
252
|
-
const logoId =
|
|
253
|
-
const controller =
|
|
125
|
+
const { downloadFile } = chunkH236SNEV_cjs.usePresentationFiles();
|
|
126
|
+
const logoId = chunkORNLCBNE_cjs.usePresentation((s) => s.theme.logo?.documentId ?? null);
|
|
127
|
+
const controller = chunkH236SNEV_cjs.usePresentationController(isOpen && !presenting);
|
|
254
128
|
react$1.useEffect(() => {
|
|
255
129
|
if (shownFor.current === userId) return;
|
|
256
130
|
shownFor.current = userId;
|
|
257
|
-
|
|
131
|
+
chunkORNLCBNE_cjs.usePresentation.getState().reset();
|
|
258
132
|
session.closePanel(chunkGFUOCGY6_cjs.PRESENTATION_PANEL);
|
|
259
133
|
}, [userId, session]);
|
|
260
134
|
react$1.useEffect(() => {
|
|
261
135
|
if (!logoId) return;
|
|
262
136
|
let current = true;
|
|
263
|
-
downloadFile(logoId).then((image) => current &&
|
|
137
|
+
downloadFile(logoId).then((image) => current && chunkORNLCBNE_cjs.usePresentation.getState().setLogoImage(image)).catch(() => current && notify("The logo could not be read", "error"));
|
|
264
138
|
return () => {
|
|
265
139
|
current = false;
|
|
266
140
|
};
|
|
267
141
|
}, [logoId, downloadFile, notify]);
|
|
268
142
|
react$1.useEffect(() => {
|
|
269
|
-
if (!isOpen)
|
|
143
|
+
if (!isOpen) chunkORNLCBNE_cjs.usePresentation.getState().setPresenting(false);
|
|
270
144
|
}, [isOpen]);
|
|
271
145
|
const wasPresenting = react$1.useRef(presenting);
|
|
272
146
|
react$1.useEffect(() => {
|
|
@@ -317,5 +191,5 @@ function PresentationWindow() {
|
|
|
317
191
|
}
|
|
318
192
|
|
|
319
193
|
exports.ConnectedPresentation = ConnectedPresentation;
|
|
320
|
-
//# sourceMappingURL=ConnectedPresentation-
|
|
321
|
-
//# sourceMappingURL=ConnectedPresentation-
|
|
194
|
+
//# sourceMappingURL=ConnectedPresentation-OV2KBOLK.cjs.map
|
|
195
|
+
//# sourceMappingURL=ConnectedPresentation-OV2KBOLK.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/presentation/PresenterView.tsx","../src/connection/presentation/ConnectedPresentation.tsx"],"names":["useEffect","STAGE_ASPECT","usePresentation","useState","useCallback","usePresenterKeys","usePointerActive","jsxs","toggleFullscreen","jsx","PresentationStage","PresentControls","SlidesEditor","ConnectedDocumentToolsProvider","useArbiSessionStore","useArbiSessionState","isPanelOpen","PRESENTATION_PANEL","useArbiSession","useRef","usePresentationFiles","usePresentationController","presentationWindowOnlyPresents","ConnectedPanelHost","Fragment","Button","PanelLeftClose"],"mappings":"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","file":"ConnectedPresentation-OV2KBOLK.cjs","sourcesContent":["/**\n * The presentation in a window of its own, in one of two modes.\n *\n * Present: nothing but the stage on black, no controls and no pointer: what is shared in a call or\n * shown on a projector. Keys drive it (arrows / Page Up / Page Down change slide, B blanks, F or\n * double-click toggles full screen, Space plays videos, Escape stops presenting).\n *\n * Edit: the slides editor (`SlidesEditor`), the same as in the viewer's tab, when the presentation\n * is edited in its own window (beside the document its clips come from).\n */\n\nimport { useCallback, useEffect, useState } from 'react'\nimport { PresentationStage } from './PresentationStage'\nimport { SlidesEditor, type SlidesEditorProps } from './SlidesEditor'\nimport { STAGE_ASPECT } from './model'\nimport { usePresentation } from './store'\nimport { toggleFullscreen, usePresenterKeys } from './usePresenterKeys'\nimport { PresentControls } from './PresentControls'\nimport { usePointerActive } from './usePointerActive'\n\n/** The presenting window's page width, at most (smaller on a small screen). */\nconst PRESENT_WIDTH = 1280\n\n/**\n * While presenting in a pop-out, its page is made 16:9 and wide enough to share sharply, so a\n * shared window is all stage with no bars; editing again gives the window back its size. Only a\n * pop-out (a window this app opened) can be resized; the app's own window is left alone.\n */\nfunction useStageShapedWindow(view: Window | null, presenting: boolean) {\n useEffect(() => {\n if (!view || !presenting || !view.opener) return\n const before = { width: view.outerWidth, height: view.outerHeight }\n const chromeWidth = view.outerWidth - view.innerWidth\n const chromeHeight = view.outerHeight - view.innerHeight\n // Wide enough for a sharp share (a call receives about what the window shows), and 16:9.\n const width = Math.max(\n view.innerWidth,\n Math.min(PRESENT_WIDTH, Math.round((view.screen.availWidth - chromeWidth) * 0.6))\n )\n const height = Math.min(\n Math.round(width / STAGE_ASPECT),\n view.screen.availHeight - chromeHeight\n )\n try {\n view.resizeTo(Math.round(height * STAGE_ASPECT) + chromeWidth, height + chromeHeight)\n } catch {\n return // not resizable: the stage letterboxes in black\n }\n return () => {\n try {\n if (!view.closed) view.resizeTo(before.width, before.height)\n } catch {\n // gone or not resizable\n }\n }\n }, [view, presenting])\n}\n\nexport type PresenterViewProps = Omit<SlidesEditorProps, 'onPresent'> & {\n /** Present (default: here, in this window). */\n onPresent?: () => void\n}\n\nexport function PresenterView({ onPresent, ...editor }: PresenterViewProps) {\n const presenting = usePresentation((s) => s.presenting)\n const [view, setView] = useState<Window | null>(null)\n // The keys work in whichever window the presenter is in.\n const rootRef = useCallback((node: HTMLDivElement | null) => {\n if (node) setView(node.ownerDocument.defaultView)\n }, [])\n usePresenterKeys(presenting ? view : null, true)\n useStageShapedWindow(view, presenting)\n\n const active = usePointerActive(presenting ? view : null)\n\n if (presenting) {\n return (\n <div\n ref={rootRef}\n className=\"relative h-full w-full select-none bg-black\"\n // The pointer shows while it moves, with the controls; idle, nothing but the slide.\n style={{ cursor: active ? 'default' : 'none' }}\n // A click on the slide goes to the next one, as in a slideshow.\n onClick={() => {\n const state = usePresentation.getState()\n state.goTo(state.current + 1)\n }}\n onDoubleClick={() => view && toggleFullscreen(view)}\n data-testid=\"presentation-present\"\n >\n <PresentationStage />\n <PresentControls view={view} shown={active} />\n </div>\n )\n }\n return (\n <div ref={rootRef} className=\"h-full min-h-0\" data-testid=\"presenter-view\">\n <SlidesEditor\n {...editor}\n onPresent={onPresent ?? (() => usePresentation.getState().setPresenting(true))}\n />\n </div>\n )\n}\n","/**\n * The presentation's own window, mounted once by the app shell (the session's `PRESENTATION_PANEL`,\n * a pop-out). It presents: the slides alone, what is shared in a call or put full screen; or, when\n * the editor is popped out of the viewer's slides tab, it edits there, beside the documents its\n * clips come from. A window opened only to present closes when presenting ends.\n *\n * It also keeps what the presentation needs wherever it is edited: the theme's logo image, read\n * when the logo changes; and a clean slate when the session signs out or another user signs in\n * (the presentation holds decrypted files in memory).\n */\n\nimport { useCallback, useEffect, useRef } from 'react'\nimport { PanelLeftClose } from 'lucide-react'\nimport {\n isPanelOpen,\n useArbiSession,\n useArbiSessionState,\n useArbiSessionStore,\n} from '@arbidocs/react'\nimport { Button } from '@arbidocs/react/ui'\nimport { ConnectedPanelHost } from '../panels/ConnectedPanelHost'\nimport { ConnectedDocumentToolsProvider } from '../viewer/ConnectedDocumentToolsProvider'\nimport { PRESENTATION_PANEL, presentationWindowOnlyPresents } from '../../presentation/panel-id'\nimport { PresenterView } from '../../presentation/PresenterView'\nimport { usePresentation } from '../../presentation/store'\nimport { usePresentationController } from './usePresentationController'\nimport { usePresentationFiles } from './usePresentationFiles'\n\n/** The presentation's window, with the document tools it needs (sources, redactions). */\nexport function ConnectedPresentation() {\n return (\n <ConnectedDocumentToolsProvider>\n <PresentationWindow />\n </ConnectedDocumentToolsProvider>\n )\n}\n\nfunction PresentationWindow() {\n const session = useArbiSessionStore()\n const notify = usePresentation((s) => s.notify)\n const presenting = usePresentation((s) => s.presenting)\n const isOpen = useArbiSessionState((state) => isPanelOpen(state, PRESENTATION_PANEL))\n const { user } = useArbiSession()\n const userId = user?.external_id ?? null\n const shownFor = useRef(userId)\n const { downloadFile } = usePresentationFiles()\n const logoId = usePresentation((s) => s.theme.logo?.documentId ?? null)\n const controller = usePresentationController(isOpen && !presenting)\n\n useEffect(() => {\n if (shownFor.current === userId) return\n shownFor.current = userId\n usePresentation.getState().reset()\n session.closePanel(PRESENTATION_PANEL)\n }, [userId, session])\n\n // The theme's logo image, fetched whenever the logo changes (the theme keeps a reference only).\n useEffect(() => {\n if (!logoId) return\n let current = true\n downloadFile(logoId)\n .then((image) => current && usePresentation.getState().setLogoImage(image))\n .catch(() => current && notify('The logo could not be read', 'error'))\n return () => {\n current = false\n }\n }, [logoId, downloadFile, notify])\n\n // A closed window is not presenting.\n useEffect(() => {\n if (!isOpen) usePresentation.getState().setPresenting(false)\n }, [isOpen])\n\n // Opened only to present: closed when presenting ends (Escape).\n const wasPresenting = useRef(presenting)\n useEffect(() => {\n if (wasPresenting.current && !presenting && isOpen && presentationWindowOnlyPresents()) {\n session.closePanel(PRESENTATION_PANEL)\n }\n wasPresenting.current = presenting\n }, [presenting, isOpen, session])\n\n const onClose = useCallback(() => session.closePanel(PRESENTATION_PANEL), [session])\n\n return (\n <ConnectedPanelHost\n panelId={PRESENTATION_PANEL}\n isOpen={isOpen}\n onClose={onClose}\n title=\"Presentation\"\n defaultMode=\"popout\"\n defaultWidth={960}\n closeTestId=\"presentation-panel-close\"\n >\n {/* Inside the panel, so its dialogs open in its window. */}\n {() => (\n <>\n {!presenting && controller.dialogs}\n <PresenterView\n {...controller.editor}\n actions={\n <>\n {controller.editor.actions}\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n className=\"size-8 text-muted-foreground hover:text-foreground pointer-coarse:size-11\"\n title=\"Back into the app's viewer\"\n aria-label=\"Back to the viewer\"\n onClick={onClose}\n data-testid=\"presentation-pop-in\"\n >\n <PanelLeftClose className=\"size-4\" />\n </Button>\n </>\n }\n />\n </>\n )}\n </ConnectedPanelHost>\n )\n}\n"]}
|