@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
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunk3ZZZO4F7_cjs = require('./chunk-3ZZZO4F7.cjs');
|
|
5
|
+
var chunkJY7UUZQG_cjs = require('./chunk-JY7UUZQG.cjs');
|
|
6
|
+
require('./chunk-WOOOMTTA.cjs');
|
|
7
|
+
require('./chunk-5GCCUXMT.cjs');
|
|
8
|
+
var chunkMVXHTAJ4_cjs = require('./chunk-MVXHTAJ4.cjs');
|
|
9
|
+
require('./chunk-ADPRIBSH.cjs');
|
|
10
|
+
var chunkORNLCBNE_cjs = require('./chunk-ORNLCBNE.cjs');
|
|
11
|
+
require('./chunk-GFUOCGY6.cjs');
|
|
12
|
+
var chunkVZOOGA47_cjs = require('./chunk-VZOOGA47.cjs');
|
|
13
|
+
var react = require('react');
|
|
14
|
+
var lucideReact = require('lucide-react');
|
|
15
|
+
var react$1 = require('@arbidocs/react');
|
|
16
|
+
var ui = require('@arbidocs/react/ui');
|
|
17
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
18
|
+
|
|
19
|
+
var SPOTLIGHT_MS = 300;
|
|
20
|
+
var EASING = "cubic-bezier(0.2, 0, 0, 1)";
|
|
21
|
+
var prefersReducedMotion = (view) => !!view?.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
22
|
+
function SpotlightView({ fromRect }) {
|
|
23
|
+
const clips = chunkMVXHTAJ4_cjs.useSpotlight((s) => s.clips);
|
|
24
|
+
const note = chunkMVXHTAJ4_cjs.useSpotlight((s) => s.note);
|
|
25
|
+
const step = chunkMVXHTAJ4_cjs.useSpotlight((s) => s.step);
|
|
26
|
+
const captions = chunkORNLCBNE_cjs.usePresentation((s) => s.captions);
|
|
27
|
+
const theme = chunkORNLCBNE_cjs.usePresentation((s) => s.theme);
|
|
28
|
+
const steps = react.useMemo(() => chunkMVXHTAJ4_cjs.spotlightSteps(clips), [clips]);
|
|
29
|
+
const ids = steps[step] ?? [];
|
|
30
|
+
const stepKey = ids.join();
|
|
31
|
+
const slide = react.useMemo(
|
|
32
|
+
() => chunkMVXHTAJ4_cjs.spotlightSlide(clips, ids, note, { captions, theme }),
|
|
33
|
+
// `ids` is new each render; its key says when it changed.
|
|
34
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35
|
+
[clips, stepKey, note, captions, theme]
|
|
36
|
+
);
|
|
37
|
+
const show = react.useMemo(() => ({ slide, clips }), [slide, clips]);
|
|
38
|
+
const [view, setView] = react.useState(null);
|
|
39
|
+
const root = react.useRef(null);
|
|
40
|
+
const rootRef = react.useCallback((node) => {
|
|
41
|
+
root.current = node;
|
|
42
|
+
if (node) setView(node.ownerDocument.defaultView);
|
|
43
|
+
}, []);
|
|
44
|
+
const active = chunk3ZZZO4F7_cjs.usePointerActive(view);
|
|
45
|
+
const [kept, setKept] = react.useState(null);
|
|
46
|
+
const last = react.useRef(/* @__PURE__ */ new Map());
|
|
47
|
+
const fromRectRef = react.useRef(fromRect);
|
|
48
|
+
fromRectRef.current = fromRect;
|
|
49
|
+
react.useLayoutEffect(() => {
|
|
50
|
+
const node = root.current;
|
|
51
|
+
if (!node) return;
|
|
52
|
+
const reduce = prefersReducedMotion(node.ownerDocument.defaultView);
|
|
53
|
+
const next = /* @__PURE__ */ new Map();
|
|
54
|
+
for (const id of stepKey.split(",").filter(Boolean)) {
|
|
55
|
+
const element = node.querySelector(`[data-testid="stage-item-${id}"]`);
|
|
56
|
+
const clip = chunkMVXHTAJ4_cjs.useSpotlight.getState().clips.find((entry) => entry.id === id);
|
|
57
|
+
if (!element || !clip) continue;
|
|
58
|
+
const to = element.getBoundingClientRect();
|
|
59
|
+
next.set(id, to);
|
|
60
|
+
const from = last.current.get(id) ?? fromRectRef.current(clip);
|
|
61
|
+
if (reduce || !from || !to.width || !to.height || typeof element.animate !== "function") {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
element.animate(
|
|
65
|
+
[
|
|
66
|
+
{
|
|
67
|
+
transform: `translate(${from.left - to.left}px, ${from.top - to.top}px) scale(${from.width / to.width}, ${from.height / to.height})`
|
|
68
|
+
},
|
|
69
|
+
{ transform: "none" }
|
|
70
|
+
],
|
|
71
|
+
{ duration: SPOTLIGHT_MS, easing: EASING }
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
last.current = next;
|
|
75
|
+
}, [stepKey]);
|
|
76
|
+
const backdrop = react.useRef(null);
|
|
77
|
+
react.useLayoutEffect(() => {
|
|
78
|
+
const element = backdrop.current;
|
|
79
|
+
if (!element || typeof element.animate !== "function") return;
|
|
80
|
+
if (prefersReducedMotion(element.ownerDocument.defaultView)) return;
|
|
81
|
+
element.animate([{ opacity: 0 }, { opacity: 1 }], { duration: SPOTLIGHT_MS, easing: EASING });
|
|
82
|
+
}, []);
|
|
83
|
+
react.useEffect(() => {
|
|
84
|
+
if (!view) return;
|
|
85
|
+
const onKeyDown = (event) => {
|
|
86
|
+
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
87
|
+
const target = event.target;
|
|
88
|
+
if (target?.closest?.('input, textarea, select, [contenteditable="true"]')) return;
|
|
89
|
+
const state = chunkMVXHTAJ4_cjs.useSpotlight.getState();
|
|
90
|
+
if (event.key === "Escape") state.hide();
|
|
91
|
+
else if (event.key === "ArrowRight" || event.key === "PageDown") state.goTo(state.step + 1);
|
|
92
|
+
else if (event.key === "ArrowLeft" || event.key === "PageUp") state.goTo(state.step - 1);
|
|
93
|
+
else return;
|
|
94
|
+
event.preventDefault();
|
|
95
|
+
event.stopPropagation();
|
|
96
|
+
};
|
|
97
|
+
view.addEventListener("keydown", onKeyDown, true);
|
|
98
|
+
return () => view.removeEventListener("keydown", onKeyDown, true);
|
|
99
|
+
}, [view]);
|
|
100
|
+
const actions = chunkMVXHTAJ4_cjs.useSpotlight.getState();
|
|
101
|
+
const isKept = kept === `${stepKey}|${note}`;
|
|
102
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
103
|
+
"div",
|
|
104
|
+
{
|
|
105
|
+
ref: rootRef,
|
|
106
|
+
className: "absolute inset-0 z-30 select-none",
|
|
107
|
+
style: { cursor: active ? "default" : "none" },
|
|
108
|
+
role: "dialog",
|
|
109
|
+
"aria-label": "Spotlight",
|
|
110
|
+
"data-testid": "spotlight",
|
|
111
|
+
children: [
|
|
112
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: backdrop, className: "absolute inset-0 bg-black/85" }),
|
|
113
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 p-4 pb-16", children: /* @__PURE__ */ jsxRuntime.jsx(chunkJY7UUZQG_cjs.PresentationStage, { show, className: "bg-transparent" }) }),
|
|
114
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
115
|
+
"div",
|
|
116
|
+
{
|
|
117
|
+
className: ui.cn(
|
|
118
|
+
"absolute bottom-3 left-1/2 z-10 flex -translate-x-1/2 items-center gap-0.5 rounded-full bg-black/60 p-1 text-white shadow-lg backdrop-blur transition-opacity duration-300",
|
|
119
|
+
active ? "opacity-100" : "pointer-events-none opacity-0"
|
|
120
|
+
),
|
|
121
|
+
role: "toolbar",
|
|
122
|
+
"aria-label": "Spotlight",
|
|
123
|
+
"data-testid": "spotlight-controls",
|
|
124
|
+
children: [
|
|
125
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
126
|
+
chunk3ZZZO4F7_cjs.Control,
|
|
127
|
+
{
|
|
128
|
+
label: "Previous (\u2190)",
|
|
129
|
+
onClick: () => actions.goTo(step - 1),
|
|
130
|
+
disabled: step === 0,
|
|
131
|
+
testId: "spotlight-previous",
|
|
132
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "size-4" })
|
|
133
|
+
}
|
|
134
|
+
),
|
|
135
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
136
|
+
"span",
|
|
137
|
+
{
|
|
138
|
+
className: "min-w-12 text-center text-xs tabular-nums text-white/85",
|
|
139
|
+
"data-testid": "spotlight-position",
|
|
140
|
+
children: [
|
|
141
|
+
step + 1,
|
|
142
|
+
" / ",
|
|
143
|
+
steps.length
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
),
|
|
147
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
148
|
+
chunk3ZZZO4F7_cjs.Control,
|
|
149
|
+
{
|
|
150
|
+
label: "Next (\u2192)",
|
|
151
|
+
onClick: () => actions.goTo(step + 1),
|
|
152
|
+
disabled: step >= steps.length - 1,
|
|
153
|
+
testId: "spotlight-next",
|
|
154
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4" })
|
|
155
|
+
}
|
|
156
|
+
),
|
|
157
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-1 h-4 w-px bg-white/25" }),
|
|
158
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
159
|
+
"button",
|
|
160
|
+
{
|
|
161
|
+
type: "button",
|
|
162
|
+
className: "inline-flex h-8 items-center gap-1.5 whitespace-nowrap rounded-full px-3 text-xs text-white/85 hover:bg-white/15 hover:text-white disabled:opacity-60 disabled:hover:bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/60 pointer-coarse:h-11",
|
|
163
|
+
disabled: isKept,
|
|
164
|
+
onClick: () => {
|
|
165
|
+
actions.keep();
|
|
166
|
+
setKept(`${stepKey}|${note}`);
|
|
167
|
+
},
|
|
168
|
+
title: "Add this as a slide of the open presentation",
|
|
169
|
+
"data-testid": "spotlight-keep",
|
|
170
|
+
children: [
|
|
171
|
+
isKept ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Presentation, { className: "size-3.5" }),
|
|
172
|
+
isKept ? "Kept as slide" : "Keep as slide"
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
),
|
|
176
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk3ZZZO4F7_cjs.Control, { label: "Back to the document (Esc)", onClick: actions.hide, testId: "spotlight-close", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" }) })
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
)
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
var frameOf = (node) => node?.closest('[data-slot="viewer-frame"]') ?? null;
|
|
185
|
+
var isTyping = (target) => !!target?.closest?.('input, textarea, select, [contenteditable="true"]');
|
|
186
|
+
function clipOnPage(frame, clip) {
|
|
187
|
+
const clipped = Array.from(frame.querySelectorAll("[data-clip-document]")).find(
|
|
188
|
+
(element) => element.getAttribute("data-clip-document") === clip.documentId
|
|
189
|
+
);
|
|
190
|
+
const page = clipped?.querySelector(`[data-page-number="${clip.page}"]`);
|
|
191
|
+
if (!page) return null;
|
|
192
|
+
const box = page.getBoundingClientRect();
|
|
193
|
+
const view = frame.ownerDocument.defaultView;
|
|
194
|
+
const rect = {
|
|
195
|
+
left: box.left + clip.rect.x * box.width,
|
|
196
|
+
top: box.top + clip.rect.y * box.height,
|
|
197
|
+
width: clip.rect.w * box.width,
|
|
198
|
+
height: clip.rect.h * box.height
|
|
199
|
+
};
|
|
200
|
+
const visible = rect.width > 0 && rect.top + rect.height > 0 && rect.left + rect.width > 0 && (!view || rect.top < view.innerHeight && rect.left < view.innerWidth);
|
|
201
|
+
return visible ? rect : null;
|
|
202
|
+
}
|
|
203
|
+
function useDocumentSwitcher(clips) {
|
|
204
|
+
const session = react$1.useArbiSessionStore();
|
|
205
|
+
const { data: documents } = react$1.useDocuments();
|
|
206
|
+
const groups = react.useMemo(() => {
|
|
207
|
+
const all = (documents ?? []).map((doc) => ({
|
|
208
|
+
id: doc.external_id,
|
|
209
|
+
title: ui.getDocumentTitle(doc, "Untitled"),
|
|
210
|
+
fileName: doc.file_name
|
|
211
|
+
})).sort((a, b) => a.title.localeCompare(b.title));
|
|
212
|
+
const clipped = new Set(clips.map((clip) => clip.documentId));
|
|
213
|
+
const from = all.filter((doc) => clipped.has(doc.id));
|
|
214
|
+
return [
|
|
215
|
+
...from.length ? [{ id: "clipped", heading: "Clipped from", docs: from }] : [],
|
|
216
|
+
{ id: "all", heading: "Documents", docs: all }
|
|
217
|
+
];
|
|
218
|
+
}, [documents, clips]);
|
|
219
|
+
const open = (id) => session.setViewingDocument({ id, page: null });
|
|
220
|
+
return { groups, open };
|
|
221
|
+
}
|
|
222
|
+
function SpotlightStrip() {
|
|
223
|
+
const clips = chunkMVXHTAJ4_cjs.useSpotlight((s) => s.clips);
|
|
224
|
+
const note = chunkMVXHTAJ4_cjs.useSpotlight((s) => s.note);
|
|
225
|
+
const showing = chunkMVXHTAJ4_cjs.useSpotlight((s) => s.showing);
|
|
226
|
+
const actions = chunkMVXHTAJ4_cjs.useSpotlight.getState();
|
|
227
|
+
const switcher = useDocumentSwitcher(clips);
|
|
228
|
+
const [noteOpen, setNoteOpen] = react.useState(false);
|
|
229
|
+
const strip = react.useRef(null);
|
|
230
|
+
const [view, setView] = react.useState(null);
|
|
231
|
+
const stripRef = react.useCallback((node) => {
|
|
232
|
+
strip.current = node;
|
|
233
|
+
if (node) setView(node.ownerDocument.defaultView);
|
|
234
|
+
}, []);
|
|
235
|
+
react.useEffect(() => {
|
|
236
|
+
if (!view || showing) return;
|
|
237
|
+
const onKeyDown = (event) => {
|
|
238
|
+
if (event.metaKey || event.ctrlKey || event.altKey || isTyping(event.target)) return;
|
|
239
|
+
if (event.key !== "s" && event.key !== "S") return;
|
|
240
|
+
event.preventDefault();
|
|
241
|
+
chunkMVXHTAJ4_cjs.useSpotlight.getState().show();
|
|
242
|
+
};
|
|
243
|
+
view.addEventListener("keydown", onKeyDown);
|
|
244
|
+
return () => view.removeEventListener("keydown", onKeyDown);
|
|
245
|
+
}, [view, showing]);
|
|
246
|
+
const scrolled = react.useRef(null);
|
|
247
|
+
react.useEffect(() => {
|
|
248
|
+
const scroller = frameOf(strip.current)?.querySelector(
|
|
249
|
+
'[data-slot="pdf-scroller"]'
|
|
250
|
+
);
|
|
251
|
+
if (showing) {
|
|
252
|
+
scrolled.current = scroller ? { element: scroller, top: scroller.scrollTop, left: scroller.scrollLeft } : null;
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const before = scrolled.current;
|
|
256
|
+
scrolled.current = null;
|
|
257
|
+
if (before?.element.isConnected) {
|
|
258
|
+
before.element.scrollTop = before.top;
|
|
259
|
+
before.element.scrollLeft = before.left;
|
|
260
|
+
}
|
|
261
|
+
}, [showing]);
|
|
262
|
+
const fromRect = react.useCallback((clip) => {
|
|
263
|
+
const frame = frameOf(strip.current);
|
|
264
|
+
const onPage = frame ? clipOnPage(frame, clip) : null;
|
|
265
|
+
return onPage ?? strip.current?.querySelector(`[data-spotlight-clip="${clip.id}"]`)?.getBoundingClientRect() ?? null;
|
|
266
|
+
}, []);
|
|
267
|
+
const count = `${clips.length} clip${clips.length === 1 ? "" : "s"}`;
|
|
268
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
269
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
270
|
+
"div",
|
|
271
|
+
{
|
|
272
|
+
ref: stripRef,
|
|
273
|
+
className: ui.cn(
|
|
274
|
+
"absolute bottom-[4.5rem] left-1/2 z-20 flex max-w-[calc(100%-1.5rem)] -translate-x-1/2 items-center gap-1.5 rounded-full border border-border bg-background/95 p-1 pl-1.5 shadow-lg backdrop-blur",
|
|
275
|
+
showing && "invisible"
|
|
276
|
+
),
|
|
277
|
+
role: "toolbar",
|
|
278
|
+
"aria-label": "Gathered clips",
|
|
279
|
+
"data-testid": "spotlight-strip",
|
|
280
|
+
children: [
|
|
281
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex min-w-0 items-center gap-1 overflow-x-auto [scrollbar-width:none]", children: clips.map((clip, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
282
|
+
"li",
|
|
283
|
+
{
|
|
284
|
+
className: "group relative h-8 shrink-0 overflow-hidden rounded-md border border-border bg-white",
|
|
285
|
+
style: { width: `${Math.min(4.5, Math.max(1.5, 2 * clip.aspect))}rem` },
|
|
286
|
+
title: clip.caption,
|
|
287
|
+
"data-spotlight-clip": clip.id,
|
|
288
|
+
"data-testid": `spotlight-chip-${index}`,
|
|
289
|
+
children: [
|
|
290
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkJY7UUZQG_cjs.ClipImage, { clip, className: "h-full w-full" }),
|
|
291
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
292
|
+
"button",
|
|
293
|
+
{
|
|
294
|
+
type: "button",
|
|
295
|
+
className: "absolute inset-0 flex items-center justify-center bg-black/50 text-white opacity-0 transition-opacity focus-visible:opacity-100 group-hover:opacity-100",
|
|
296
|
+
onClick: () => actions.remove(clip.id),
|
|
297
|
+
"aria-label": `Remove ${clip.caption}`,
|
|
298
|
+
"data-testid": `spotlight-remove-${index}`,
|
|
299
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3.5" })
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
]
|
|
303
|
+
},
|
|
304
|
+
clip.id
|
|
305
|
+
)) }),
|
|
306
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-muted-foreground", "data-testid": "spotlight-count", children: count }),
|
|
307
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { open: noteOpen, onOpenChange: setNoteOpen, children: [
|
|
308
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
309
|
+
ui.Button,
|
|
310
|
+
{
|
|
311
|
+
type: "button",
|
|
312
|
+
variant: note ? "secondary" : "ghost",
|
|
313
|
+
size: "sm",
|
|
314
|
+
className: "h-7 max-w-40 shrink-0 gap-1 rounded-full px-2 text-xs",
|
|
315
|
+
title: note ? `Note: ${note}` : "Type a note to show as the title",
|
|
316
|
+
"data-testid": "spotlight-note",
|
|
317
|
+
children: [
|
|
318
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.StickyNote, { className: "size-3.5 shrink-0" }),
|
|
319
|
+
note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: note }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Note" })
|
|
320
|
+
]
|
|
321
|
+
}
|
|
322
|
+
) }),
|
|
323
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.PopoverContent, { side: "top", className: "w-72 p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
324
|
+
ui.Input,
|
|
325
|
+
{
|
|
326
|
+
autoFocus: true,
|
|
327
|
+
value: note,
|
|
328
|
+
placeholder: "Type a note",
|
|
329
|
+
onChange: (event) => actions.setNote(event.target.value),
|
|
330
|
+
onKeyDown: (event) => {
|
|
331
|
+
if (event.key === "Enter") setNoteOpen(false);
|
|
332
|
+
},
|
|
333
|
+
"data-testid": "spotlight-note-input"
|
|
334
|
+
}
|
|
335
|
+
) })
|
|
336
|
+
] }),
|
|
337
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-44 shrink-0 [&_[role=combobox]]:h-7 [&_[role=combobox]]:rounded-full [&_[role=combobox]]:text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
338
|
+
chunkVZOOGA47_cjs.DocumentPicker,
|
|
339
|
+
{
|
|
340
|
+
groups: switcher.groups,
|
|
341
|
+
value: "",
|
|
342
|
+
onValueChange: switcher.open,
|
|
343
|
+
labels: { placeholder: "Clip another document" }
|
|
344
|
+
}
|
|
345
|
+
) }),
|
|
346
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
347
|
+
ui.Button,
|
|
348
|
+
{
|
|
349
|
+
type: "button",
|
|
350
|
+
size: "sm",
|
|
351
|
+
className: "h-7 shrink-0 gap-1 rounded-full px-3 text-xs",
|
|
352
|
+
onClick: actions.show,
|
|
353
|
+
title: "Show the clips over the document (S)",
|
|
354
|
+
"data-testid": "spotlight-show",
|
|
355
|
+
children: [
|
|
356
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Presentation, { className: "size-3.5" }),
|
|
357
|
+
"Show"
|
|
358
|
+
]
|
|
359
|
+
}
|
|
360
|
+
),
|
|
361
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
362
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
363
|
+
ui.Button,
|
|
364
|
+
{
|
|
365
|
+
type: "button",
|
|
366
|
+
variant: "ghost",
|
|
367
|
+
size: "icon",
|
|
368
|
+
className: "size-7 shrink-0 rounded-full",
|
|
369
|
+
"aria-label": "More",
|
|
370
|
+
"data-testid": "spotlight-more",
|
|
371
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4" })
|
|
372
|
+
}
|
|
373
|
+
) }),
|
|
374
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", side: "top", children: [
|
|
375
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: actions.keep, "data-testid": "spotlight-menu-keep", children: [
|
|
376
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Presentation, { className: "mr-2 size-4" }),
|
|
377
|
+
" Keep as slide"
|
|
378
|
+
] }),
|
|
379
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: actions.addToTray, "data-testid": "spotlight-menu-tray", children: [
|
|
380
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Inbox, { className: "mr-2 size-4" }),
|
|
381
|
+
" Add to the presentation tray"
|
|
382
|
+
] }),
|
|
383
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: actions.clear, "data-testid": "spotlight-menu-clear", children: [
|
|
384
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eraser, { className: "mr-2 size-4" }),
|
|
385
|
+
" Clear the clips"
|
|
386
|
+
] })
|
|
387
|
+
] })
|
|
388
|
+
] })
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
),
|
|
392
|
+
showing && /* @__PURE__ */ jsxRuntime.jsx(SpotlightView, { fromRect })
|
|
393
|
+
] });
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
exports.SpotlightStrip = SpotlightStrip;
|
|
397
|
+
//# sourceMappingURL=SpotlightStrip-ED22UYTM.cjs.map
|
|
398
|
+
//# sourceMappingURL=SpotlightStrip-ED22UYTM.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/presentation/SpotlightView.tsx","../src/connection/presentation/SpotlightStrip.tsx"],"names":["useSpotlight","usePresentation","useMemo","spotlightSteps","spotlightSlide","useState","useRef","useCallback","usePointerActive","useLayoutEffect","useEffect","jsxs","jsx","PresentationStage","cn","Control","ChevronLeft","ChevronRight","Check","Presentation","X","useArbiSessionStore","useDocuments","getDocumentTitle","Fragment","ClipImage","Popover","PopoverTrigger","Button","StickyNote","PopoverContent","Input","DocumentPicker","DropdownMenu","DropdownMenuTrigger","MoreHorizontal","DropdownMenuContent","DropdownMenuItem","Inbox","Eraser"],"mappings":"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","file":"SpotlightStrip-ED22UYTM.cjs","sourcesContent":["/**\n * The spotlight on screen: the document dims and the gathered clips fly from where they are on\n * their pages into a slide over it, in the same window (a call sharing it goes on sharing it). It is\n * the presentation's own stage (`PresentationStage`), so it looks as a slide of the deck would.\n *\n * ← → step through the clips together and each alone, Esc goes back to the document. Each move is\n * a FLIP: a clip is drawn where it ends and animated from where it was (its page, or its place on\n * the previous step) by a transform, about 300 ms; with reduced motion it simply appears.\n */\n\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { Check, ChevronLeft, ChevronRight, Presentation, X } from 'lucide-react'\nimport { cn } from '@arbidocs/react/ui'\nimport type { Clip } from './model'\nimport { Control } from './PresentControls'\nimport { PresentationStage } from './PresentationStage'\nimport { spotlightSlide, spotlightSteps, useSpotlight } from './spotlight'\nimport { usePresentation } from './store'\nimport { usePointerActive } from './usePointerActive'\n\n/** How long a clip takes to fly into place. */\nexport const SPOTLIGHT_MS = 300\nconst EASING = 'cubic-bezier(0.2, 0, 0, 1)'\n\n/** A box on screen, in CSS pixels. */\nexport type ScreenRect = Pick<DOMRect, 'left' | 'top' | 'width' | 'height'>\n\nexport interface SpotlightViewProps {\n /** Where a clip is on screen before the spotlight (its passage on the page), if it shows. */\n fromRect: (clip: Clip) => ScreenRect | null\n}\n\nconst prefersReducedMotion = (view: Window | null) =>\n !!view?.matchMedia?.('(prefers-reduced-motion: reduce)').matches\n\nexport function SpotlightView({ fromRect }: SpotlightViewProps) {\n const clips = useSpotlight((s) => s.clips)\n const note = useSpotlight((s) => s.note)\n const step = useSpotlight((s) => s.step)\n const captions = usePresentation((s) => s.captions)\n const theme = usePresentation((s) => s.theme)\n const steps = useMemo(() => spotlightSteps(clips), [clips])\n const ids = steps[step] ?? []\n const stepKey = ids.join()\n const slide = useMemo(\n () => spotlightSlide(clips, ids, note, { captions, theme }),\n // `ids` is new each render; its key says when it changed.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [clips, stepKey, note, captions, theme]\n )\n const show = useMemo(() => ({ slide, clips }), [slide, clips])\n\n const [view, setView] = useState<Window | null>(null)\n const root = useRef<HTMLDivElement | null>(null)\n const rootRef = useCallback((node: HTMLDivElement | null) => {\n root.current = node\n if (node) setView(node.ownerDocument.defaultView)\n }, [])\n const active = usePointerActive(view)\n const [kept, setKept] = useState<string | null>(null)\n\n // FLIP: each clip from where it was (on its page, or on the step before) to where it is now.\n const last = useRef(new Map<string, ScreenRect>())\n const fromRectRef = useRef(fromRect)\n fromRectRef.current = fromRect\n useLayoutEffect(() => {\n const node = root.current\n if (!node) return\n const reduce = prefersReducedMotion(node.ownerDocument.defaultView)\n const next = new Map<string, ScreenRect>()\n for (const id of stepKey.split(',').filter(Boolean)) {\n const element = node.querySelector<HTMLElement>(`[data-testid=\"stage-item-${id}\"]`)\n const clip = useSpotlight.getState().clips.find((entry) => entry.id === id)\n if (!element || !clip) continue\n const to = element.getBoundingClientRect()\n next.set(id, to)\n const from = last.current.get(id) ?? fromRectRef.current(clip)\n if (reduce || !from || !to.width || !to.height || typeof element.animate !== 'function') {\n continue\n }\n element.animate(\n [\n {\n transform: `translate(${from.left - to.left}px, ${from.top - to.top}px) scale(${\n from.width / to.width\n }, ${from.height / to.height})`,\n },\n { transform: 'none' },\n ],\n { duration: SPOTLIGHT_MS, easing: EASING }\n )\n }\n last.current = next\n }, [stepKey])\n\n // The document dims as the clips arrive.\n const backdrop = useRef<HTMLDivElement>(null)\n useLayoutEffect(() => {\n const element = backdrop.current\n if (!element || typeof element.animate !== 'function') return\n if (prefersReducedMotion(element.ownerDocument.defaultView)) return\n element.animate([{ opacity: 0 }, { opacity: 1 }], { duration: SPOTLIGHT_MS, easing: EASING })\n }, [])\n\n // Esc back to the document, ← → through the steps; taken before the viewer's own keys.\n useEffect(() => {\n if (!view) return\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.metaKey || event.ctrlKey || event.altKey) return\n const target = event.target as HTMLElement | null\n if (target?.closest?.('input, textarea, select, [contenteditable=\"true\"]')) return\n const state = useSpotlight.getState()\n if (event.key === 'Escape') state.hide()\n else if (event.key === 'ArrowRight' || event.key === 'PageDown') state.goTo(state.step + 1)\n else if (event.key === 'ArrowLeft' || event.key === 'PageUp') state.goTo(state.step - 1)\n else return\n event.preventDefault()\n event.stopPropagation()\n }\n view.addEventListener('keydown', onKeyDown, true)\n return () => view.removeEventListener('keydown', onKeyDown, true)\n }, [view])\n\n const actions = useSpotlight.getState()\n const isKept = kept === `${stepKey}|${note}`\n return (\n <div\n ref={rootRef}\n className=\"absolute inset-0 z-30 select-none\"\n style={{ cursor: active ? 'default' : 'none' }}\n role=\"dialog\"\n aria-label=\"Spotlight\"\n data-testid=\"spotlight\"\n >\n <div ref={backdrop} className=\"absolute inset-0 bg-black/85\" />\n <div className=\"absolute inset-0 p-4 pb-16\">\n <PresentationStage show={show} className=\"bg-transparent\" />\n </div>\n <div\n className={cn(\n 'absolute bottom-3 left-1/2 z-10 flex -translate-x-1/2 items-center gap-0.5 rounded-full bg-black/60 p-1 text-white shadow-lg backdrop-blur transition-opacity duration-300',\n active ? 'opacity-100' : 'pointer-events-none opacity-0'\n )}\n role=\"toolbar\"\n aria-label=\"Spotlight\"\n data-testid=\"spotlight-controls\"\n >\n <Control\n label=\"Previous (←)\"\n onClick={() => actions.goTo(step - 1)}\n disabled={step === 0}\n testId=\"spotlight-previous\"\n >\n <ChevronLeft className=\"size-4\" />\n </Control>\n <span\n className=\"min-w-12 text-center text-xs tabular-nums text-white/85\"\n data-testid=\"spotlight-position\"\n >\n {step + 1} / {steps.length}\n </span>\n <Control\n label=\"Next (→)\"\n onClick={() => actions.goTo(step + 1)}\n disabled={step >= steps.length - 1}\n testId=\"spotlight-next\"\n >\n <ChevronRight className=\"size-4\" />\n </Control>\n <div className=\"mx-1 h-4 w-px bg-white/25\" />\n <button\n type=\"button\"\n className=\"inline-flex h-8 items-center gap-1.5 whitespace-nowrap rounded-full px-3 text-xs text-white/85 hover:bg-white/15 hover:text-white disabled:opacity-60 disabled:hover:bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/60 pointer-coarse:h-11\"\n disabled={isKept}\n onClick={() => {\n actions.keep()\n setKept(`${stepKey}|${note}`)\n }}\n title=\"Add this as a slide of the open presentation\"\n data-testid=\"spotlight-keep\"\n >\n {isKept ? <Check className=\"size-3.5\" /> : <Presentation className=\"size-3.5\" />}\n {isKept ? 'Kept as slide' : 'Keep as slide'}\n </button>\n <Control label=\"Back to the document (Esc)\" onClick={actions.hide} testId=\"spotlight-close\">\n <X className=\"size-4\" />\n </Control>\n </div>\n </div>\n )\n}\n","/**\n * The clips gathered in the viewer, in a small strip over the document: each clip (× takes it\n * out), a note to show as the spotlight's title, another document to clip from, and Show (or S),\n * which puts them in the spotlight over this same viewer. Rarer actions — keep them as a slide,\n * add them to the presentation's tray, clear them — are in its \"…\" menu.\n *\n * The strip and the spotlight stay over whichever document the viewer shows, so clips are gathered\n * from several documents in a row. Esc brings the document back where it was scrolled to.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Eraser, MoreHorizontal, Inbox, Presentation, StickyNote, X } from 'lucide-react'\nimport { useArbiSessionStore, useDocuments } from '@arbidocs/react'\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Input,\n Popover,\n PopoverContent,\n PopoverTrigger,\n cn,\n getDocumentTitle,\n} from '@arbidocs/react/ui'\nimport { ClipImage } from '../../presentation/ClipImage'\nimport type { Clip } from '../../presentation/model'\nimport { SpotlightView, type ScreenRect } from '../../presentation/SpotlightView'\nimport { useSpotlight } from '../../presentation/spotlight'\nimport { DocumentPicker, type PickerGroup } from '../../settings/DocumentPicker'\n\n/** The viewer this strip is over (its frame), found from the strip's own element. */\nconst frameOf = (node: HTMLElement | null) =>\n node?.closest<HTMLElement>('[data-slot=\"viewer-frame\"]') ?? null\n\nconst isTyping = (target: EventTarget | null) =>\n !!(target as HTMLElement | null)?.closest?.('input, textarea, select, [contenteditable=\"true\"]')\n\n/**\n * Where a clip is on screen now: its area of its page, while its document is clipped in the viewer\n * (`data-clip-document`) and that page is in view.\n */\nfunction clipOnPage(frame: HTMLElement, clip: Clip): ScreenRect | null {\n const clipped = Array.from(frame.querySelectorAll('[data-clip-document]')).find(\n (element) => element.getAttribute('data-clip-document') === clip.documentId\n )\n const page = clipped?.querySelector<HTMLElement>(`[data-page-number=\"${clip.page}\"]`)\n if (!page) return null\n const box = page.getBoundingClientRect()\n const view = frame.ownerDocument.defaultView\n const rect = {\n left: box.left + clip.rect.x * box.width,\n top: box.top + clip.rect.y * box.height,\n width: clip.rect.w * box.width,\n height: clip.rect.h * box.height,\n }\n const visible =\n rect.width > 0 &&\n rect.top + rect.height > 0 &&\n rect.left + rect.width > 0 &&\n (!view || (rect.top < view.innerHeight && rect.left < view.innerWidth))\n return visible ? rect : null\n}\n\nfunction useDocumentSwitcher(clips: readonly Clip[]) {\n const session = useArbiSessionStore()\n const { data: documents } = useDocuments()\n const groups = useMemo<PickerGroup[]>(() => {\n const all = (documents ?? [])\n .map((doc) => ({\n id: doc.external_id,\n title: getDocumentTitle(doc, 'Untitled'),\n fileName: doc.file_name,\n }))\n .sort((a, b) => a.title.localeCompare(b.title))\n const clipped = new Set(clips.map((clip) => clip.documentId))\n const from = all.filter((doc) => clipped.has(doc.id))\n return [\n ...(from.length ? [{ id: 'clipped', heading: 'Clipped from', docs: from }] : []),\n { id: 'all', heading: 'Documents', docs: all },\n ]\n }, [documents, clips])\n const open = (id: string) => session.setViewingDocument({ id, page: null })\n return { groups, open }\n}\n\nexport function SpotlightStrip() {\n const clips = useSpotlight((s) => s.clips)\n const note = useSpotlight((s) => s.note)\n const showing = useSpotlight((s) => s.showing)\n const actions = useSpotlight.getState()\n const switcher = useDocumentSwitcher(clips)\n const [noteOpen, setNoteOpen] = useState(false)\n\n const strip = useRef<HTMLDivElement | null>(null)\n const [view, setView] = useState<Window | null>(null)\n const stripRef = useCallback((node: HTMLDivElement | null) => {\n strip.current = node\n if (node) setView(node.ownerDocument.defaultView)\n }, [])\n\n // S shows the spotlight (not while typing).\n useEffect(() => {\n if (!view || showing) return\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.metaKey || event.ctrlKey || event.altKey || isTyping(event.target)) return\n if (event.key !== 's' && event.key !== 'S') return\n event.preventDefault()\n useSpotlight.getState().show()\n }\n view.addEventListener('keydown', onKeyDown)\n return () => view.removeEventListener('keydown', onKeyDown)\n }, [view, showing])\n\n // Back from the spotlight, the document is where it was scrolled to.\n const scrolled = useRef<{ element: HTMLElement; top: number; left: number } | null>(null)\n useEffect(() => {\n const scroller = frameOf(strip.current)?.querySelector<HTMLElement>(\n '[data-slot=\"pdf-scroller\"]'\n )\n if (showing) {\n scrolled.current = scroller\n ? { element: scroller, top: scroller.scrollTop, left: scroller.scrollLeft }\n : null\n return\n }\n const before = scrolled.current\n scrolled.current = null\n if (before?.element.isConnected) {\n before.element.scrollTop = before.top\n before.element.scrollLeft = before.left\n }\n }, [showing])\n\n const fromRect = useCallback((clip: Clip) => {\n const frame = frameOf(strip.current)\n const onPage = frame ? clipOnPage(frame, clip) : null\n // Not on screen (another document's clip): from its chip in the strip.\n return (\n onPage ??\n strip.current?.querySelector(`[data-spotlight-clip=\"${clip.id}\"]`)?.getBoundingClientRect() ??\n null\n )\n }, [])\n\n const count = `${clips.length} clip${clips.length === 1 ? '' : 's'}`\n return (\n <>\n <div\n ref={stripRef}\n className={cn(\n 'absolute bottom-[4.5rem] left-1/2 z-20 flex max-w-[calc(100%-1.5rem)] -translate-x-1/2 items-center gap-1.5 rounded-full border border-border bg-background/95 p-1 pl-1.5 shadow-lg backdrop-blur',\n showing && 'invisible'\n )}\n role=\"toolbar\"\n aria-label=\"Gathered clips\"\n data-testid=\"spotlight-strip\"\n >\n <ul className=\"flex min-w-0 items-center gap-1 overflow-x-auto [scrollbar-width:none]\">\n {clips.map((clip, index) => (\n <li\n key={clip.id}\n className=\"group relative h-8 shrink-0 overflow-hidden rounded-md border border-border bg-white\"\n style={{ width: `${Math.min(4.5, Math.max(1.5, 2 * clip.aspect))}rem` }}\n title={clip.caption}\n data-spotlight-clip={clip.id}\n data-testid={`spotlight-chip-${index}`}\n >\n <ClipImage clip={clip} className=\"h-full w-full\" />\n <button\n type=\"button\"\n className=\"absolute inset-0 flex items-center justify-center bg-black/50 text-white opacity-0 transition-opacity focus-visible:opacity-100 group-hover:opacity-100\"\n onClick={() => actions.remove(clip.id)}\n aria-label={`Remove ${clip.caption}`}\n data-testid={`spotlight-remove-${index}`}\n >\n <X className=\"size-3.5\" />\n </button>\n </li>\n ))}\n </ul>\n <span className=\"shrink-0 text-xs text-muted-foreground\" data-testid=\"spotlight-count\">\n {count}\n </span>\n <Popover open={noteOpen} onOpenChange={setNoteOpen}>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant={note ? 'secondary' : 'ghost'}\n size=\"sm\"\n className=\"h-7 max-w-40 shrink-0 gap-1 rounded-full px-2 text-xs\"\n title={note ? `Note: ${note}` : 'Type a note to show as the title'}\n data-testid=\"spotlight-note\"\n >\n <StickyNote className=\"size-3.5 shrink-0\" />\n {note ? <span className=\"truncate\">{note}</span> : <span>Note</span>}\n </Button>\n </PopoverTrigger>\n <PopoverContent side=\"top\" className=\"w-72 p-2\">\n <Input\n autoFocus\n value={note}\n placeholder=\"Type a note\"\n onChange={(event) => actions.setNote(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') setNoteOpen(false)\n }}\n data-testid=\"spotlight-note-input\"\n />\n </PopoverContent>\n </Popover>\n <div className=\"w-44 shrink-0 [&_[role=combobox]]:h-7 [&_[role=combobox]]:rounded-full [&_[role=combobox]]:text-xs\">\n <DocumentPicker\n groups={switcher.groups}\n value=\"\"\n onValueChange={switcher.open}\n labels={{ placeholder: 'Clip another document' }}\n />\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n className=\"h-7 shrink-0 gap-1 rounded-full px-3 text-xs\"\n onClick={actions.show}\n title=\"Show the clips over the document (S)\"\n data-testid=\"spotlight-show\"\n >\n <Presentation className=\"size-3.5\" />\n Show\n </Button>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 shrink-0 rounded-full\"\n aria-label=\"More\"\n data-testid=\"spotlight-more\"\n >\n <MoreHorizontal className=\"size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" side=\"top\">\n <DropdownMenuItem onSelect={actions.keep} data-testid=\"spotlight-menu-keep\">\n <Presentation className=\"mr-2 size-4\" /> Keep as slide\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={actions.addToTray} data-testid=\"spotlight-menu-tray\">\n <Inbox className=\"mr-2 size-4\" /> Add to the presentation tray\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={actions.clear} data-testid=\"spotlight-menu-clear\">\n <Eraser className=\"mr-2 size-4\" /> Clear the clips\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n {showing && <SpotlightView fromRect={fromRect} />}\n </>\n )\n}\n"]}
|
|
@@ -39,13 +39,13 @@ function ClipButton({ active, onClick, compact }) {
|
|
|
39
39
|
variant: active ? "default" : "outline",
|
|
40
40
|
size: compact ? "icon" : "sm",
|
|
41
41
|
"aria-pressed": active,
|
|
42
|
-
title: "Clip: drag over
|
|
42
|
+
title: "Clip: click a passage (or drag over any area) to gather it, then Show",
|
|
43
43
|
"aria-label": "Clip",
|
|
44
44
|
"data-testid": "clip-toggle",
|
|
45
45
|
className: TOUCH,
|
|
46
46
|
onClick,
|
|
47
47
|
children: [
|
|
48
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
48
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Scissors, { className: "size-4" }),
|
|
49
49
|
!compact && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: "Clip" })
|
|
50
50
|
]
|
|
51
51
|
}
|
|
@@ -557,5 +557,5 @@ exports.ShowOriginalButton = ShowOriginalButton;
|
|
|
557
557
|
exports.SignatureRequestBanner = SignatureRequestBanner;
|
|
558
558
|
exports.SignedEditNote = SignedEditNote;
|
|
559
559
|
exports.VersionSnapshotBar = VersionSnapshotBar;
|
|
560
|
-
//# sourceMappingURL=chunk-
|
|
561
|
-
//# sourceMappingURL=chunk-
|
|
560
|
+
//# sourceMappingURL=chunk-3IH55CDE.cjs.map
|
|
561
|
+
//# sourceMappingURL=chunk-3IH55CDE.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/document-tools/DocumentToolButtons.tsx","../src/document-tools/MarkupNotices.tsx","../src/document-tools/MarkupViewNote.tsx","../src/document-tools/VersionSnapshotBar.tsx","../src/document-tools/PlaceMySignatureMenuItems.tsx","../src/document-tools/SignatureRequestBanner.tsx","../src/document-tools/FileShareDialog.tsx"],"names":["jsxs","Button","jsx","PencilLine","Scissors","FileText","Download","Fragment","ViewerStatusNote","LINK","useDocumentTools","useState","fetchSavedSignature","DropdownMenuItem","AdoptSignatureDialog","storeSavedSignature","SIGNER_PROGRESS_LABELS","useDocumentSignatureRequests","useVoidSignatureRequest","useInviteSigners","useSignerCandidates","PenLine","Send","FilePenLine","ModalScaffold","createFileShare","Label","Textarea"],"mappings":"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","file":"chunk-3IH55CDE.cjs","sourcesContent":["/**\n * The viewer-header buttons of the PDF document tools: Annotate, Show original, Download with\n * markup and Sign. Separate parts so a host can place them among its own header actions. On a\n * narrow (`compact`) header each is icon-only; its accessible name stays.\n */\n\nimport type { ReactElement } from 'react'\nimport { Download, FileText, PencilLine, Scissors } from 'lucide-react'\nimport { Button } from '@arbidocs/react/ui'\n\nconst TOUCH = 'pointer-coarse:min-h-11'\n\ninterface ToggleProps {\n /** On (pressed). */\n active: boolean\n onClick: () => void\n compact?: boolean\n}\n\n/** Annotate mode: highlight, comment, stamp, redact. */\nexport function AnnotateButton({ active, onClick, compact }: ToggleProps): ReactElement {\n return (\n <Button\n type=\"button\"\n variant={active ? 'default' : 'outline'}\n size={compact ? 'icon' : 'sm'}\n aria-pressed={active}\n title=\"Annotate: highlight, comment, stamp, redact\"\n aria-label=\"Annotate\"\n data-testid=\"annotate-toggle\"\n className={TOUCH}\n onClick={onClick}\n >\n <PencilLine className=\"size-4\" />\n {!compact && <span className=\"ml-1\">Annotate</span>}\n </Button>\n )\n}\n\n/** Clip mode: drag over a page to show that part of it in the presentation. */\nexport function ClipButton({ active, onClick, compact }: ToggleProps): ReactElement {\n return (\n <Button\n type=\"button\"\n variant={active ? 'default' : 'outline'}\n size={compact ? 'icon' : 'sm'}\n aria-pressed={active}\n title=\"Clip: click a passage (or drag over any area) to gather it, then Show\"\n aria-label=\"Clip\"\n data-testid=\"clip-toggle\"\n className={TOUCH}\n onClick={onClick}\n >\n <Scissors className=\"size-4\" />\n {!compact && <span className=\"ml-1\">Clip</span>}\n </Button>\n )\n}\n\n/** The markup is the default view of a marked-up PDF; this shows the untouched file. */\nexport function ShowOriginalButton({ active, onClick, compact }: ToggleProps): ReactElement {\n return (\n <Button\n type=\"button\"\n variant={active ? 'default' : 'outline'}\n size={compact ? 'icon' : 'sm'}\n aria-pressed={active}\n title={active ? 'Show the markup again' : 'Show the original, without markup'}\n aria-label=\"Show original\"\n data-testid=\"markup-show-original\"\n className={TOUCH}\n onClick={onClick}\n >\n <FileText className=\"size-4\" />\n {!compact && <span className=\"ml-1\">Show original</span>}\n </Button>\n )\n}\n\n/**\n * \"Download with markup\": the PDF with its annotations, which Acrobat and Preview show. With a\n * `disabledReason` (a signed, locked version) it is off and says why.\n */\nexport function DownloadMarkupButton({\n onClick,\n disabledReason,\n}: {\n onClick: () => void\n disabledReason?: string\n}): ReactElement {\n const button = (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n title={\n disabledReason ??\n 'Download with markup: the PDF with its annotations (opens in Acrobat or Preview)'\n }\n aria-label=\"Download with markup\"\n aria-description={disabledReason}\n disabled={!!disabledReason}\n data-testid=\"markup-download\"\n className={TOUCH}\n onClick={onClick}\n >\n <Download className=\"size-4\" />\n </Button>\n )\n // A disabled button gets no pointer events, so the reason sits on a wrapper too.\n return disabledReason ? (\n <span title={disabledReason} className=\"inline-flex\" data-testid=\"markup-download-locked\">\n {button}\n </span>\n ) : (\n button\n )\n}\n\n/** One line where a signed version's content can be edited: an edit is a new, unsigned version. */\nexport function SignedEditNote(): ReactElement {\n return (\n <p\n className=\"border-b px-3 py-1.5 text-xs text-muted-foreground\"\n data-testid=\"signed-edit-note\"\n >\n Editing creates a new unsigned version\n </p>\n )\n}\n","/**\n * The one-line notices above the PDF about its markup: annotations found in this browser from\n * before markup was saved on the server (for a shared document: add them to the shared markup, or\n * discard), and markup that sits on an older version (open it, or copy its open comments here).\n */\n\nimport type { LegacyPrompt, OlderMarkupNote } from '@arbidocs/react/document-tools'\n\nconst BAR = 'flex flex-wrap items-center justify-between gap-2 border-b px-3 py-2 text-xs'\nconst LINK =\n 'font-medium text-primary hover:underline disabled:opacity-50 disabled:no-underline pointer-coarse:min-h-11'\n\nexport interface MarkupNoticesProps {\n legacyPrompt: LegacyPrompt | null\n olderNote: OlderMarkupNote | null\n onOpenVersion: (version: number) => void\n}\n\nexport function MarkupNotices({ legacyPrompt, olderNote, onOpenVersion }: MarkupNoticesProps) {\n return (\n <>\n {legacyPrompt && (\n <div className={BAR} role=\"status\" data-testid=\"markup-migration-prompt\">\n <span>\n {legacyPrompt.count} annotation{legacyPrompt.count === 1 ? '' : 's'} on this document\n {legacyPrompt.count === 1 ? ' is' : ' are'} saved only in this browser. Add{' '}\n {legacyPrompt.count === 1 ? 'it' : 'them'} to the shared markup, where everyone with\n access sees {legacyPrompt.count === 1 ? 'it' : 'them'}?\n </span>\n <span className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n className={LINK}\n disabled={legacyPrompt.busy}\n data-testid=\"markup-migration-add\"\n onClick={legacyPrompt.add}\n >\n {legacyPrompt.busy ? 'Adding…' : 'Add to shared markup'}\n </button>\n <button\n type=\"button\"\n className={LINK}\n disabled={legacyPrompt.busy}\n data-testid=\"markup-migration-discard\"\n onClick={legacyPrompt.discard}\n >\n Discard\n </button>\n </span>\n </div>\n )}\n {olderNote && (\n <div className={BAR} data-testid=\"markup-older-version-note\">\n <span>\n The markup is on version {olderNote.version}. This version started without it.\n {olderNote.signed && (\n <span data-testid=\"markup-older-version-signed\">\n {' '}\n It is signed: comments copied here are kept beside it, and the signed PDF does not\n change.\n </span>\n )}\n </span>\n <span className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n className={LINK}\n data-testid=\"markup-open-older-version\"\n onClick={() => onOpenVersion(olderNote.version)}\n >\n Open version {olderNote.version}\n </button>\n <button\n type=\"button\"\n className={LINK}\n disabled={olderNote.busy}\n data-testid=\"markup-copy-open-threads\"\n title=\"Copy the unresolved comment threads onto this version (redactions never carry over)\"\n onClick={olderNote.copy}\n >\n {olderNote.busy ? 'Copying…' : 'Copy open comments here'}\n </button>\n </span>\n </div>\n )}\n </>\n )\n}\n","/**\n * Which view of a marked-up PDF is on screen, spelled out beside the title, with the switch to the\n * other one. The narrow header's \"Show original\" is an unlabelled page icon, so on its own it read\n * as no control at all, and nothing said whether the page showed the markup or the original.\n */\n\nimport type { ReactElement } from 'react'\nimport { ViewerStatusNote } from '../files/ViewerLayout'\n\nexport interface MarkupViewNoteProps {\n showOriginal: boolean\n onToggle: () => void\n}\n\nexport function MarkupViewNote({ showOriginal, onToggle }: MarkupViewNoteProps): ReactElement {\n return (\n <ViewerStatusNote testId=\"markup-view-note\">\n {showOriginal ? 'Original, without markup' : 'With markup'}\n {' · '}\n <button\n type=\"button\"\n className=\"font-medium text-primary hover:underline pointer-coarse:min-h-11\"\n data-testid=\"markup-view-note-toggle\"\n onClick={onToggle}\n >\n {showOriginal ? 'Show markup' : 'Show original'}\n </button>\n </ViewerStatusNote>\n )\n}\n","/**\n * The bar above an older version opened read-only: which version it is, \"Ask about this version\"\n * (when the host has an assistant) and the way back to the current version. Put it in the viewer's\n * sticky header, not the content area: a PDF view scrolls its first page into view, which would\n * scroll a bar above it out of sight.\n */\n\nimport type { ReactElement } from 'react'\n\nconst LINK = 'font-medium text-primary hover:underline pointer-coarse:min-h-11'\n\nexport interface VersionSnapshotBarLabels {\n /** `Version 2 · read only`; `number` is undefined when the version is not known. */\n title: (number: number | undefined) => string\n ask: string\n returnToCurrent: string\n /** For documents edited live (Word, artifacts), where \"current\" is the live document. */\n returnToLive: string\n}\n\nexport const DEFAULT_VERSION_SNAPSHOT_BAR_LABELS: VersionSnapshotBarLabels = {\n title: (number) => `${number ? `Version ${number}` : 'Saved version'} · read only`,\n ask: 'Ask about this version',\n returnToCurrent: 'Return to current version',\n returnToLive: 'Return to live document',\n}\n\nexport interface VersionSnapshotBarProps {\n /** The version's number, when known. */\n versionNumber?: number\n /** The document is edited live: the way back says \"live document\". */\n live?: boolean\n /** Ask the assistant about this version. Omitted: no ask action. */\n onAsk?: () => void\n onReturn: () => void\n labels?: Partial<VersionSnapshotBarLabels>\n}\n\nexport function VersionSnapshotBar({\n versionNumber,\n live = false,\n onAsk,\n onReturn,\n labels: overrides,\n}: VersionSnapshotBarProps): ReactElement {\n const labels = { ...DEFAULT_VERSION_SNAPSHOT_BAR_LABELS, ...overrides }\n return (\n <div\n className=\"flex items-center justify-between border-b px-3 py-2 text-xs\"\n data-testid=\"version-snapshot-bar\"\n >\n <span>{labels.title(versionNumber)}</span>\n <span className=\"flex items-center gap-3\">\n {onAsk && (\n <button type=\"button\" className={LINK} data-testid=\"version-snapshot-ask\" onClick={onAsk}>\n {labels.ask}\n </button>\n )}\n <button\n type=\"button\"\n className={LINK}\n data-testid=\"version-snapshot-return\"\n onClick={onReturn}\n >\n {live ? labels.returnToLive : labels.returnToCurrent}\n </button>\n </span>\n </div>\n )\n}\n","/**\n * \"Place my signature\" / \"Place my initials\" in the viewer's signing menu: place one's own saved\n * signature or initials on the page as a picture stamp in the markup layer (then drag and resize it\n * like any stamp). Nothing saved yet: the adopt dialog opens first and saves it. Renders menu\n * items, so it goes inside a `DropdownMenuContent`. Needs a `<DocumentToolsProvider>` inside a\n * React Query `QueryClientProvider`.\n */\n\nimport { useState, type ReactElement } from 'react'\nimport {\n fetchSavedSignature,\n storeSavedSignature,\n useDocumentTools,\n type SavedSignature,\n} from '@arbidocs/react/document-tools'\nimport { DropdownMenuItem } from '@arbidocs/react/ui'\nimport { AdoptSignatureDialog } from './AdoptSignatureDialog'\n\nexport type PlacedMark = { image: string; label: string }\n\ntype Mark = 'signature' | 'initials'\n\nconst picked = (saved: SavedSignature, mark: Mark): PlacedMark =>\n mark === 'signature'\n ? { image: saved.signature_png, label: 'Signature' }\n : { image: saved.initials_png, label: 'Initials' }\n\nexport function PlaceMySignatureMenuItems({\n onPlace,\n}: {\n /** Arm the stamp tool with this picture: the next click on a page places it. */\n onPlace: (mark: PlacedMark) => void\n}): ReactElement {\n const { client, user, notify } = useDocumentTools()\n const [adoptFor, setAdoptFor] = useState<Mark | null>(null)\n\n // Read when asked for (sealed with one's own key: opened here, in the browser).\n const place = async (mark: Mark) => {\n try {\n const saved = await fetchSavedSignature(client)\n if (saved) return onPlace(picked(saved, mark))\n setAdoptFor(mark)\n } catch (err) {\n notify(err instanceof Error ? err.message : 'Your saved signature could not be read', 'error')\n }\n }\n\n return (\n <>\n <DropdownMenuItem onSelect={() => void place('signature')} data-testid=\"place-my-signature\">\n Place my signature\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={() => void place('initials')} data-testid=\"place-my-initials\">\n Place my initials\n </DropdownMenuItem>\n <AdoptSignatureDialog\n open={!!adoptFor}\n onOpenChange={(open) => !open && setAdoptFor(null)}\n mode=\"save\"\n defaultName={user?.name ?? ''}\n onSave={async (signature) => {\n await storeSavedSignature(client, signature)\n const mark = adoptFor\n setAdoptFor(null)\n if (mark) onPlace(picked(signature, mark))\n }}\n onAdopt={() => {}}\n />\n </>\n )\n}\n","/**\n * Where a document's signature requests stand, above the document: a request waiting for the\n * viewer's signature (with \"Review and sign\"), one the viewer sent and is waiting on others (who\n * has signed; void it), and the viewer's own draft (go on editing it). Nothing when there is none.\n * Needs a `<DocumentToolsProvider>` whose `user` has an `externalId`.\n */\n\nimport type { ReactElement } from 'react'\nimport { FilePenLine, PenLine, Send } from 'lucide-react'\nimport {\n SIGNER_PROGRESS_LABELS,\n useDocumentSignatureRequests,\n useDocumentTools,\n useInviteSigners,\n useSignerCandidates,\n useVoidSignatureRequest,\n type SignatureRequest,\n} from '@arbidocs/react/document-tools'\nimport { Button } from '@arbidocs/react/ui'\n\nexport interface SignatureRequestBannerProps {\n documentId: string\n /** Open the guided signing of a request waiting for the viewer. */\n onSign: (request: SignatureRequest) => void\n /** Go on editing the viewer's draft. */\n onEditDraft: (request: SignatureRequest) => void\n /** Hide it (e.g. while the editor or the guided signing is open). */\n hidden?: boolean\n}\n\n/** Who is still to sign, and how far each has got (\"Dana Day (invited)\"). */\nfunction waitingFor(request: SignatureRequest): string[] {\n return request.signers\n .filter((s) => s.status === 'pending')\n .map((s) => `${s.name || s.email || ''} (${SIGNER_PROGRESS_LABELS[s.progress].toLowerCase()})`)\n}\n\nexport function SignatureRequestBanner({\n documentId,\n onSign,\n onEditDraft,\n hidden = false,\n}: SignatureRequestBannerProps): ReactElement | null {\n const { user, notify } = useDocumentTools()\n const requests = useDocumentSignatureRequests(documentId, !hidden)\n const voidRequest = useVoidSignatureRequest()\n const invite = useInviteSigners()\n const me = user?.externalId ?? null\n const candidates = useSignerCandidates(!hidden && !!me)\n const isOwner = candidates.data?.some((c) => c.externalId === me && c.role === 'owner') ?? false\n if (hidden || !me || !requests.data) return null\n const open = requests.data.filter((r) => r.status === 'sent' || r.status === 'draft')\n const awaitingMe = open.filter(\n (r) =>\n r.status === 'sent' && r.signers.some((s) => s.user_ext_id === me && s.status === 'pending')\n )\n const sentByMe = open.filter(\n (r) => r.status === 'sent' && r.created_by === me && !awaitingMe.includes(r)\n )\n const drafts = open.filter((r) => r.status === 'draft' && r.created_by === me)\n if (awaitingMe.length + sentByMe.length + drafts.length === 0) return null\n\n const doVoid = async (request: SignatureRequest) => {\n try {\n await voidRequest.mutateAsync(request.external_id)\n notify(request.status === 'draft' ? 'Draft discarded.' : 'Signature request voided.', 'info')\n } catch (err) {\n notify(err instanceof Error ? err.message : 'Could not void it', 'error')\n }\n }\n\n return (\n <div\n className=\"space-y-1.5 border-b border-border px-3 py-2 text-sm\"\n data-testid=\"signature-request-banner\"\n >\n {awaitingMe.map((r) => {\n const count = r.fields.filter((f) => f.signer === me).length\n const author = r.signers.find((s) => s.user_ext_id === r.created_by)?.name\n return (\n <div\n key={r.external_id}\n className=\"flex flex-wrap items-center gap-2 rounded-md bg-blue-50 px-2 py-1.5 text-blue-950 dark:bg-blue-950/40 dark:text-blue-100\"\n data-testid=\"signature-request-awaiting-me\"\n >\n <PenLine className=\"size-4 shrink-0\" aria-hidden />\n <span className=\"mr-auto\">\n {author && r.created_by !== me\n ? `${author} asked you to sign`\n : 'You are asked to sign'}{' '}\n {count} field{count === 1 ? '' : 's'} in this document.\n {r.stale && ' It has changed since it was sent: ask for it again.'}\n </span>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => onSign(r)}\n disabled={r.stale}\n data-testid=\"signature-request-start\"\n >\n Review and sign\n </Button>\n </div>\n )\n })}\n {sentByMe.map((r) => {\n const pending = waitingFor(r)\n const signed = r.signers.length - pending.length\n const invited = r.signers.filter((s) => s.progress === 'invited' && s.email)\n return (\n <div\n key={r.external_id}\n className=\"flex flex-wrap items-center gap-2\"\n data-testid=\"signature-request-sent\"\n >\n <Send className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden />\n <span className=\"mr-auto\">\n Out for signature: {signed} of {r.signers.length} signed\n {pending.length > 0 && (\n <span className=\"text-muted-foreground\"> · waiting for {pending.join(', ')}</span>\n )}\n {r.stale && (\n <span className=\"text-red-text\"> · the document has changed since it was sent</span>\n )}\n </span>\n {isOwner && invited.length > 0 && (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={invite.isPending}\n onClick={async () => {\n try {\n await invite.mutateAsync({\n documentId,\n emails: invited.map((s) => s.email!),\n })\n notify(\n 'Invited again: anyone already registered is added now and asked to sign.',\n 'success'\n )\n } catch (err) {\n notify(err instanceof Error ? err.message : 'Could not invite', 'error')\n }\n }}\n data-testid=\"signature-request-reinvite\"\n >\n Invite again\n </Button>\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => doVoid(r)}\n disabled={voidRequest.isPending}\n >\n Void\n </Button>\n </div>\n )\n })}\n {drafts.map((r) => (\n <div\n key={r.external_id}\n className=\"flex flex-wrap items-center gap-2\"\n data-testid=\"signature-request-draft\"\n >\n <FilePenLine className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden />\n <span className=\"mr-auto\">\n Draft signature request: {r.fields.length} field{r.fields.length === 1 ? '' : 's'}, not\n sent yet.\n </span>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={() => onEditDraft(r)}>\n Continue\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => doVoid(r)}\n disabled={voidRequest.isPending}\n >\n Discard\n </Button>\n </div>\n ))}\n </div>\n )\n}\n","import { useState } from 'react'\nimport { createFileShare, useDocumentTools } from '@arbidocs/react/document-tools'\nimport { Button, Label, Textarea } from '@arbidocs/react/ui'\nimport { ModalScaffold } from '../settings/ModalScaffold'\n\nexport function FileShareDialog({\n open,\n onOpenChange,\n documentId,\n version,\n}: {\n open: boolean\n onOpenChange: (open: boolean) => void\n documentId: string\n version: number\n}) {\n const { client, prepareFileShare } = useDocumentTools()\n const [emails, setEmails] = useState('')\n const [message, setMessage] = useState('')\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState('')\n return (\n <ModalScaffold\n open={open}\n onOpenChange={(next) => !busy && onOpenChange(next)}\n title={`Share file · version ${version}`}\n description=\"Recipients can view and download only this version. They get no workspace access or other versions.\"\n showDescription\n testId=\"file-share-dialog\"\n >\n <form\n onSubmit={async (event) => {\n event.preventDefault()\n setBusy(true)\n setError('')\n try {\n const recipients = [\n ...new Set(\n emails\n .split(/[,;\\n]+/)\n .map((e) => e.trim().toLowerCase())\n .filter(Boolean)\n ),\n ]\n if (!recipients.length) throw new Error('Add at least one recipient email')\n await prepareFileShare(documentId)\n const share = await createFileShare(client, documentId, {\n version,\n recipients: recipients.map((email) => ({ email, permission: 'view' })),\n message,\n })\n window.location.assign(`/shared-files/${share.external_id}`)\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Could not share the file')\n } finally {\n setBusy(false)\n }\n }}\n >\n <ModalScaffold.Body>\n <Label htmlFor=\"file-share-emails\">Recipient emails</Label>\n <Textarea\n id=\"file-share-emails\"\n data-testid=\"file-share-emails\"\n value={emails}\n onChange={(e) => setEmails(e.target.value)}\n placeholder=\"One email per line, or separated by commas\"\n required\n />\n <Label htmlFor=\"file-share-message\">Message (optional)</Label>\n <Textarea\n id=\"file-share-message\"\n value={message}\n onChange={(e) => setMessage(e.target.value)}\n maxLength={2000}\n />\n <p className=\"text-sm text-muted-foreground\">\n Each recipient receives an email with an account-specific link. External users on a Box\n receive up to 24 hours of access.\n </p>\n {error && (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {error}\n </p>\n )}\n </ModalScaffold.Body>\n <ModalScaffold.Footer>\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={busy}\n onClick={() => onOpenChange(false)}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={busy} data-testid=\"file-share-send\">\n {busy ? 'Sharing…' : 'Share this version'}\n </Button>\n </ModalScaffold.Footer>\n </form>\n </ModalScaffold>\n )\n}\n"]}
|