pptx-react-viewer 1.0.11 → 1.1.1
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/{PowerPointViewer-gSKLhZDo.d.mts → PowerPointViewer-DtLlYf0r.d.mts} +12 -1
- package/dist/{PowerPointViewer-gSKLhZDo.d.ts → PowerPointViewer-DtLlYf0r.d.ts} +12 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1032 -426
- package/dist/index.mjs +1033 -427
- package/dist/pptx-viewer.css +1 -1
- package/dist/viewer/index.d.mts +5 -3
- package/dist/viewer/index.d.ts +5 -3
- package/dist/viewer/index.js +1525 -990
- package/dist/viewer/index.mjs +1526 -991
- package/node_modules/emf-converter/package.json +1 -1
- package/node_modules/mtx-decompressor/package.json +1 -1
- package/node_modules/pptx-viewer-core/package.json +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
4
4
|
import * as ReactDOM from 'react-dom/client';
|
|
5
5
|
import { clsx } from 'clsx';
|
|
6
6
|
import { twMerge } from 'tailwind-merge';
|
|
7
|
-
import { LuMessageSquare, LuEyeOff, LuSettings, LuX, LuShieldCheck, LuPlus, LuPanelLeftClose, LuStickyNote, LuMonitor, LuColumns2, LuPresentation, LuMinus, LuClock, LuDownload, LuTrash2, LuCheck, LuLock, LuEye, LuFileText, LuType, LuLoader, LuShieldAlert, LuSignature, LuInfo, LuTriangleAlert, LuPrinter, LuPenTool, LuWifi, LuWifiOff, LuUsers, LuCopy, LuMonitorOff, LuChevronLeft, LuChevronRight, LuPlay, LuPause, LuPanelLeft, LuUndo, LuRedo, LuSearch, LuShare2, LuPanelRight, LuFolderOpen, LuVideo, LuImage, LuClipboardPaste, LuScissors, LuPaintbrush, LuChevronDown, LuSquare, LuDatabase, LuLayers, LuAArrowUp, LuAArrowDown, LuRemoveFormatting, LuHighlighter, LuList, LuListOrdered, LuIndentDecrease, LuIndentIncrease, LuChevronUp, LuPalette, LuPencil, LuPaintBucket, LuSparkles,
|
|
7
|
+
import { LuMessageSquare, LuEyeOff, LuSettings, LuX, LuCast, LuShieldCheck, LuPlus, LuPanelLeftClose, LuStickyNote, LuMonitor, LuColumns2, LuPresentation, LuMinus, LuClock, LuDownload, LuTrash2, LuCheck, LuLock, LuEye, LuFileText, LuType, LuLoader, LuShieldAlert, LuSignature, LuInfo, LuTriangleAlert, LuPrinter, LuPenTool, LuWifi, LuWifiOff, LuUsers, LuCopy, LuMonitorOff, LuChevronLeft, LuChevronRight, LuPlay, LuPause, LuPanelLeft, LuUndo, LuRedo, LuSearch, LuShare2, LuPanelRight, LuFolderOpen, LuVideo, LuImage, LuClipboardPaste, LuScissors, LuPaintbrush, LuChevronDown, LuSquare, LuDatabase, LuLayers, LuAArrowUp, LuAArrowDown, LuRemoveFormatting, LuHighlighter, LuList, LuListOrdered, LuIndentDecrease, LuIndentIncrease, LuChevronUp, LuPalette, LuPencil, LuPaintBucket, LuSparkles, LuCaptions, LuSpellCheck, LuGitCompare, LuPipette, LuCaseSensitive, LuReplace, LuTimer, LuMousePointer2, LuEraser, LuGripVertical, LuUpload, LuBold, LuItalic, LuUnderline, LuStrikethrough, LuLink, LuGrid2X2, LuCopyPlus, LuEllipsis, LuCircle, LuMoveRight, LuTriangle, LuDiamond, LuAlignLeft, LuAlignCenter, LuAlignRight, LuAlignJustify, LuSpline, LuSettings2, LuMove, LuRadio, LuArrowDown, LuArrowUp, LuArrowRight, LuArrowLeft, LuReply, LuRotateCw, LuBookmark } from 'react-icons/lu';
|
|
8
8
|
import { hasShapeProperties, hasTextProperties, SWITCHABLE_LAYOUT_TYPES, isCalloutShape, getCalloutLeaderLineGeometry, buildCalloutLeaderLineSvgPath, getCalloutViewBoxBounds, isInkElement, getLinkedTextBoxSegments, isImageLikeElement, getSubstituteFontFamily, PptxHandler, EncryptedFileError, guidePxToEmu, guideEmuToPx, THEME_COLOR_SCHEME_KEYS, hslToRgb, PRESET_COLOR_MAP, elementActionToPptxAction, mergeShapes, SvgExporter, applyDrawingColorTransforms as applyDrawingColorTransforms$1, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, EMU_PER_PX as EMU_PER_PX$1, chartDataChangeType, chartDataUpdatePoint, chartDataAddCategory, chartDataRemoveCategory, chartDataAddSeries, chartDataRemoveSeries, getOleObjectTypeLabel, pptxActionToElementAction, hasNonTrivialOverride, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, addSmartArtNodeAsChild, updateSmartArtNodeText, removeSmartArtNode, switchSmartArtLayout } from 'pptx-viewer-core';
|
|
9
9
|
import { useTranslation } from 'react-i18next';
|
|
10
10
|
import html2canvasPro from 'html2canvas-pro';
|
|
@@ -43302,7 +43302,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43302
43302
|
return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
|
|
43303
43303
|
}
|
|
43304
43304
|
function useSyncExternalStore$2(subscribe3, getSnapshot2) {
|
|
43305
|
-
didWarnOld18Alpha || void 0 ===
|
|
43305
|
+
didWarnOld18Alpha || void 0 === React96.startTransition || (didWarnOld18Alpha = true, console.error(
|
|
43306
43306
|
"You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
|
|
43307
43307
|
));
|
|
43308
43308
|
var value = getSnapshot2();
|
|
@@ -43312,7 +43312,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43312
43312
|
"The result of getSnapshot should be cached to avoid an infinite loop"
|
|
43313
43313
|
), didWarnUncachedGetSnapshot = true);
|
|
43314
43314
|
}
|
|
43315
|
-
cachedValue =
|
|
43315
|
+
cachedValue = useState85({
|
|
43316
43316
|
inst: { value, getSnapshot: getSnapshot2 }
|
|
43317
43317
|
});
|
|
43318
43318
|
var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
|
|
@@ -43324,7 +43324,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43324
43324
|
},
|
|
43325
43325
|
[subscribe3, value, getSnapshot2]
|
|
43326
43326
|
);
|
|
43327
|
-
|
|
43327
|
+
useEffect71(
|
|
43328
43328
|
function() {
|
|
43329
43329
|
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
|
|
43330
43330
|
return subscribe3(function() {
|
|
@@ -43350,8 +43350,8 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43350
43350
|
return getSnapshot2();
|
|
43351
43351
|
}
|
|
43352
43352
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
43353
|
-
var
|
|
43354
|
-
exports$1.useSyncExternalStore = void 0 !==
|
|
43353
|
+
var React96 = __require("react"), objectIs = "function" === typeof Object.is ? Object.is : is2, useState85 = React96.useState, useEffect71 = React96.useEffect, useLayoutEffect7 = React96.useLayoutEffect, useDebugValue = React96.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
|
|
43354
|
+
exports$1.useSyncExternalStore = void 0 !== React96.useSyncExternalStore ? React96.useSyncExternalStore : shim;
|
|
43355
43355
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
|
|
43356
43356
|
})();
|
|
43357
43357
|
}
|
|
@@ -43374,9 +43374,9 @@ var require_with_selector_development = __commonJS({
|
|
|
43374
43374
|
return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
|
|
43375
43375
|
}
|
|
43376
43376
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
43377
|
-
var
|
|
43377
|
+
var React96 = __require("react"), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is2, useSyncExternalStore3 = shim.useSyncExternalStore, useRef72 = React96.useRef, useEffect71 = React96.useEffect, useMemo41 = React96.useMemo, useDebugValue = React96.useDebugValue;
|
|
43378
43378
|
exports$1.useSyncExternalStoreWithSelector = function(subscribe3, getSnapshot2, getServerSnapshot2, selector, isEqual) {
|
|
43379
|
-
var instRef =
|
|
43379
|
+
var instRef = useRef72(null);
|
|
43380
43380
|
if (null === instRef.current) {
|
|
43381
43381
|
var inst = { hasValue: false, value: null };
|
|
43382
43382
|
instRef.current = inst;
|
|
@@ -43417,7 +43417,7 @@ var require_with_selector_development = __commonJS({
|
|
|
43417
43417
|
[getSnapshot2, getServerSnapshot2, selector, isEqual]
|
|
43418
43418
|
);
|
|
43419
43419
|
var value = useSyncExternalStore3(subscribe3, instRef[0], instRef[1]);
|
|
43420
|
-
|
|
43420
|
+
useEffect71(
|
|
43421
43421
|
function() {
|
|
43422
43422
|
inst.hasValue = true;
|
|
43423
43423
|
inst.value = value;
|
|
@@ -91102,6 +91102,542 @@ function useVirtualizedSlides({
|
|
|
91102
91102
|
scrollToIndex
|
|
91103
91103
|
};
|
|
91104
91104
|
}
|
|
91105
|
+
|
|
91106
|
+
// src/viewer/hooks/collaboration/sanitize.ts
|
|
91107
|
+
var ROOM_ID_REGEX = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
91108
|
+
function validateRoomId(roomId) {
|
|
91109
|
+
if (!ROOM_ID_REGEX.test(roomId)) {
|
|
91110
|
+
throw new Error(
|
|
91111
|
+
`Invalid collaboration room ID: "${roomId}". Must be 1-128 alphanumeric characters, hyphens, or underscores.`
|
|
91112
|
+
);
|
|
91113
|
+
}
|
|
91114
|
+
return roomId;
|
|
91115
|
+
}
|
|
91116
|
+
function sanitizeUserName(name) {
|
|
91117
|
+
if (typeof name !== "string") {
|
|
91118
|
+
return "Anonymous";
|
|
91119
|
+
}
|
|
91120
|
+
const stripped = name.replace(/<[^>]*>/g, "");
|
|
91121
|
+
const trimmed = stripped.trim().slice(0, 64);
|
|
91122
|
+
return trimmed || "Anonymous";
|
|
91123
|
+
}
|
|
91124
|
+
function clampCursorPosition(value, min2, max2) {
|
|
91125
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
91126
|
+
return 0;
|
|
91127
|
+
}
|
|
91128
|
+
const margin = 20;
|
|
91129
|
+
return Math.max(min2 - margin, Math.min(max2 + margin, value));
|
|
91130
|
+
}
|
|
91131
|
+
var HEX_COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
|
|
91132
|
+
function sanitizeColor(color, fallback = "#6366f1") {
|
|
91133
|
+
if (typeof color !== "string") {
|
|
91134
|
+
return fallback;
|
|
91135
|
+
}
|
|
91136
|
+
return HEX_COLOR_REGEX.test(color) ? color : fallback;
|
|
91137
|
+
}
|
|
91138
|
+
function sanitizeAvatarUrl(url) {
|
|
91139
|
+
if (typeof url !== "string") {
|
|
91140
|
+
return void 0;
|
|
91141
|
+
}
|
|
91142
|
+
try {
|
|
91143
|
+
const parsed = new URL(url);
|
|
91144
|
+
if (parsed.protocol === "https:" || parsed.protocol === "http:" || parsed.protocol === "data:") {
|
|
91145
|
+
return url;
|
|
91146
|
+
}
|
|
91147
|
+
} catch {
|
|
91148
|
+
}
|
|
91149
|
+
return void 0;
|
|
91150
|
+
}
|
|
91151
|
+
function sanitizeSlideIndex(value) {
|
|
91152
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
91153
|
+
return 0;
|
|
91154
|
+
}
|
|
91155
|
+
return Math.max(0, Math.floor(value));
|
|
91156
|
+
}
|
|
91157
|
+
function sanitizePresence(raw, canvasWidth, canvasHeight) {
|
|
91158
|
+
if (typeof raw.clientId !== "number") {
|
|
91159
|
+
return null;
|
|
91160
|
+
}
|
|
91161
|
+
return {
|
|
91162
|
+
clientId: raw.clientId,
|
|
91163
|
+
userName: sanitizeUserName(raw.userName),
|
|
91164
|
+
userAvatar: sanitizeAvatarUrl(raw.userAvatar),
|
|
91165
|
+
userColor: sanitizeColor(raw.userColor),
|
|
91166
|
+
activeSlideIndex: sanitizeSlideIndex(raw.activeSlideIndex),
|
|
91167
|
+
cursorX: clampCursorPosition(raw.cursorX, 0, canvasWidth),
|
|
91168
|
+
cursorY: clampCursorPosition(raw.cursorY, 0, canvasHeight),
|
|
91169
|
+
lastUpdated: typeof raw.lastUpdated === "string" ? raw.lastUpdated : (/* @__PURE__ */ new Date()).toISOString(),
|
|
91170
|
+
selectedElementId: typeof raw.selectedElementId === "string" ? raw.selectedElementId.slice(0, 128) : void 0,
|
|
91171
|
+
role: raw.role === "broadcaster" || raw.role === "viewer" || raw.role === "collaborator" ? raw.role : void 0
|
|
91172
|
+
};
|
|
91173
|
+
}
|
|
91174
|
+
var BROADCAST_THROTTLE_MS = 50;
|
|
91175
|
+
var STALE_PRESENCE_MS = 3e4;
|
|
91176
|
+
function usePresenceTracking({
|
|
91177
|
+
awareness,
|
|
91178
|
+
localClientId,
|
|
91179
|
+
userName,
|
|
91180
|
+
userColor,
|
|
91181
|
+
userAvatar,
|
|
91182
|
+
role,
|
|
91183
|
+
canvasWidth,
|
|
91184
|
+
canvasHeight
|
|
91185
|
+
}) {
|
|
91186
|
+
const [remoteUsers, setRemoteUsers] = useState([]);
|
|
91187
|
+
const lastBroadcastRef = useRef(0);
|
|
91188
|
+
const pendingBroadcastRef = useRef(null);
|
|
91189
|
+
const latestLocalState = useRef({});
|
|
91190
|
+
const broadcastPresence = useCallback(
|
|
91191
|
+
(update2) => {
|
|
91192
|
+
if (!awareness) {
|
|
91193
|
+
return;
|
|
91194
|
+
}
|
|
91195
|
+
Object.assign(latestLocalState.current, update2);
|
|
91196
|
+
const now = Date.now();
|
|
91197
|
+
const elapsed = now - lastBroadcastRef.current;
|
|
91198
|
+
const flush = () => {
|
|
91199
|
+
const state2 = {
|
|
91200
|
+
...latestLocalState.current,
|
|
91201
|
+
userName,
|
|
91202
|
+
userColor,
|
|
91203
|
+
userAvatar,
|
|
91204
|
+
role,
|
|
91205
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
91206
|
+
};
|
|
91207
|
+
awareness.setLocalStateField("presence", state2);
|
|
91208
|
+
lastBroadcastRef.current = Date.now();
|
|
91209
|
+
};
|
|
91210
|
+
if (elapsed >= BROADCAST_THROTTLE_MS) {
|
|
91211
|
+
if (pendingBroadcastRef.current) {
|
|
91212
|
+
clearTimeout(pendingBroadcastRef.current);
|
|
91213
|
+
pendingBroadcastRef.current = null;
|
|
91214
|
+
}
|
|
91215
|
+
flush();
|
|
91216
|
+
} else if (!pendingBroadcastRef.current) {
|
|
91217
|
+
pendingBroadcastRef.current = setTimeout(() => {
|
|
91218
|
+
pendingBroadcastRef.current = null;
|
|
91219
|
+
flush();
|
|
91220
|
+
}, BROADCAST_THROTTLE_MS - elapsed);
|
|
91221
|
+
}
|
|
91222
|
+
},
|
|
91223
|
+
[awareness, userName, userColor, userAvatar, role]
|
|
91224
|
+
);
|
|
91225
|
+
useEffect(() => {
|
|
91226
|
+
if (!awareness) {
|
|
91227
|
+
return;
|
|
91228
|
+
}
|
|
91229
|
+
awareness.setLocalStateField("presence", {
|
|
91230
|
+
userName,
|
|
91231
|
+
userColor,
|
|
91232
|
+
userAvatar,
|
|
91233
|
+
role,
|
|
91234
|
+
activeSlideIndex: 0,
|
|
91235
|
+
cursorX: 0,
|
|
91236
|
+
cursorY: 0,
|
|
91237
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
91238
|
+
});
|
|
91239
|
+
}, [awareness, userName, userColor, userAvatar, role]);
|
|
91240
|
+
useEffect(() => {
|
|
91241
|
+
if (!awareness || localClientId === null) {
|
|
91242
|
+
return;
|
|
91243
|
+
}
|
|
91244
|
+
const handleChange = () => {
|
|
91245
|
+
const now = Date.now();
|
|
91246
|
+
const states = awareness.getStates();
|
|
91247
|
+
const users = [];
|
|
91248
|
+
states.forEach((state2, cid) => {
|
|
91249
|
+
if (cid === localClientId) {
|
|
91250
|
+
return;
|
|
91251
|
+
}
|
|
91252
|
+
const raw = state2?.presence;
|
|
91253
|
+
if (!raw || typeof raw !== "object") {
|
|
91254
|
+
return;
|
|
91255
|
+
}
|
|
91256
|
+
const sanitized = sanitizePresence({ ...raw, clientId: cid }, canvasWidth, canvasHeight);
|
|
91257
|
+
if (!sanitized) {
|
|
91258
|
+
return;
|
|
91259
|
+
}
|
|
91260
|
+
const updatedAt = new Date(sanitized.lastUpdated).getTime();
|
|
91261
|
+
if (Number.isNaN(updatedAt) || now - updatedAt > STALE_PRESENCE_MS) {
|
|
91262
|
+
return;
|
|
91263
|
+
}
|
|
91264
|
+
users.push(sanitized);
|
|
91265
|
+
});
|
|
91266
|
+
setRemoteUsers(users);
|
|
91267
|
+
};
|
|
91268
|
+
awareness.on("change", handleChange);
|
|
91269
|
+
awareness.on("update", handleChange);
|
|
91270
|
+
handleChange();
|
|
91271
|
+
return () => {
|
|
91272
|
+
awareness.off("change", handleChange);
|
|
91273
|
+
awareness.off("update", handleChange);
|
|
91274
|
+
};
|
|
91275
|
+
}, [awareness, localClientId, canvasWidth, canvasHeight]);
|
|
91276
|
+
useEffect(() => {
|
|
91277
|
+
if (!awareness) {
|
|
91278
|
+
return;
|
|
91279
|
+
}
|
|
91280
|
+
const interval = setInterval(() => {
|
|
91281
|
+
awareness.setLocalStateField("presence", {
|
|
91282
|
+
...latestLocalState.current,
|
|
91283
|
+
userName,
|
|
91284
|
+
userColor,
|
|
91285
|
+
userAvatar,
|
|
91286
|
+
role,
|
|
91287
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
91288
|
+
});
|
|
91289
|
+
}, 1e4);
|
|
91290
|
+
return () => clearInterval(interval);
|
|
91291
|
+
}, [awareness, userName, userColor, userAvatar, role]);
|
|
91292
|
+
useEffect(() => {
|
|
91293
|
+
return () => {
|
|
91294
|
+
if (pendingBroadcastRef.current) {
|
|
91295
|
+
clearTimeout(pendingBroadcastRef.current);
|
|
91296
|
+
}
|
|
91297
|
+
};
|
|
91298
|
+
}, []);
|
|
91299
|
+
return { remoteUsers, broadcastPresence };
|
|
91300
|
+
}
|
|
91301
|
+
function useYjsProvider({ config }) {
|
|
91302
|
+
const [status, setStatus] = useState("disconnected");
|
|
91303
|
+
const [awareness, setAwareness] = useState(null);
|
|
91304
|
+
const [doc2, setDoc] = useState(null);
|
|
91305
|
+
const [clientId, setClientId] = useState(null);
|
|
91306
|
+
const cleanupRef = useRef(null);
|
|
91307
|
+
const init = useCallback(async () => {
|
|
91308
|
+
const roomId = validateRoomId(config.roomId);
|
|
91309
|
+
setStatus("connecting");
|
|
91310
|
+
try {
|
|
91311
|
+
const [Y, { WebsocketProvider: WebsocketProvider2 }] = await Promise.all([Promise.resolve().then(() => (init_yjs(), yjs_exports)), Promise.resolve().then(() => (init_y_websocket(), y_websocket_exports))]);
|
|
91312
|
+
const yDoc = new Y.Doc();
|
|
91313
|
+
const provider = new WebsocketProvider2(
|
|
91314
|
+
config.serverUrl,
|
|
91315
|
+
roomId,
|
|
91316
|
+
yDoc,
|
|
91317
|
+
// eslint-disable-line @typescript-eslint/no-explicit-any
|
|
91318
|
+
{
|
|
91319
|
+
params: config.authToken ? { token: config.authToken } : void 0
|
|
91320
|
+
}
|
|
91321
|
+
);
|
|
91322
|
+
const handleStatus = (event) => {
|
|
91323
|
+
if (event.status === "connected") {
|
|
91324
|
+
setStatus("connected");
|
|
91325
|
+
} else if (event.status === "disconnected") {
|
|
91326
|
+
setStatus("disconnected");
|
|
91327
|
+
}
|
|
91328
|
+
};
|
|
91329
|
+
provider.on("status", handleStatus);
|
|
91330
|
+
if (provider.wsconnected) {
|
|
91331
|
+
setStatus("connected");
|
|
91332
|
+
}
|
|
91333
|
+
setDoc(yDoc);
|
|
91334
|
+
setAwareness(provider.awareness);
|
|
91335
|
+
setClientId(provider.awareness.clientID);
|
|
91336
|
+
cleanupRef.current = () => {
|
|
91337
|
+
provider.off("status", handleStatus);
|
|
91338
|
+
provider.destroy();
|
|
91339
|
+
yDoc.destroy();
|
|
91340
|
+
setDoc(null);
|
|
91341
|
+
setAwareness(null);
|
|
91342
|
+
setClientId(null);
|
|
91343
|
+
setStatus("disconnected");
|
|
91344
|
+
};
|
|
91345
|
+
} catch (err) {
|
|
91346
|
+
console.warn(
|
|
91347
|
+
"[pptx-viewer] Collaboration packages not available:",
|
|
91348
|
+
err instanceof Error ? err.message : err
|
|
91349
|
+
);
|
|
91350
|
+
setStatus("error");
|
|
91351
|
+
}
|
|
91352
|
+
}, [config.roomId, config.serverUrl, config.authToken]);
|
|
91353
|
+
useEffect(() => {
|
|
91354
|
+
init();
|
|
91355
|
+
return () => {
|
|
91356
|
+
cleanupRef.current?.();
|
|
91357
|
+
cleanupRef.current = null;
|
|
91358
|
+
};
|
|
91359
|
+
}, [init]);
|
|
91360
|
+
return { status, awareness, doc: doc2, clientId };
|
|
91361
|
+
}
|
|
91362
|
+
|
|
91363
|
+
// src/viewer/hooks/collaboration/useCollaborativeState.ts
|
|
91364
|
+
function useCollaborativeState({
|
|
91365
|
+
config,
|
|
91366
|
+
canvasWidth,
|
|
91367
|
+
canvasHeight
|
|
91368
|
+
}) {
|
|
91369
|
+
const userColor = sanitizeColor(config.userColor, "#6366f1");
|
|
91370
|
+
const { status, awareness, doc: doc2, clientId } = useYjsProvider({ config });
|
|
91371
|
+
const { remoteUsers, broadcastPresence } = usePresenceTracking({
|
|
91372
|
+
awareness,
|
|
91373
|
+
localClientId: clientId,
|
|
91374
|
+
userName: config.userName,
|
|
91375
|
+
userColor,
|
|
91376
|
+
userAvatar: config.userAvatar,
|
|
91377
|
+
role: config.role,
|
|
91378
|
+
canvasWidth,
|
|
91379
|
+
canvasHeight
|
|
91380
|
+
});
|
|
91381
|
+
const connectedCount = status === "connected" ? remoteUsers.length + 1 : remoteUsers.length;
|
|
91382
|
+
return {
|
|
91383
|
+
status,
|
|
91384
|
+
remoteUsers,
|
|
91385
|
+
broadcastPresence,
|
|
91386
|
+
connectedCount,
|
|
91387
|
+
config,
|
|
91388
|
+
doc: doc2
|
|
91389
|
+
};
|
|
91390
|
+
}
|
|
91391
|
+
var CollaborationContext = createContext(null);
|
|
91392
|
+
function useCollaboration() {
|
|
91393
|
+
return useContext(CollaborationContext);
|
|
91394
|
+
}
|
|
91395
|
+
function CollaborationProvider({
|
|
91396
|
+
config,
|
|
91397
|
+
canvasWidth,
|
|
91398
|
+
canvasHeight,
|
|
91399
|
+
children
|
|
91400
|
+
}) {
|
|
91401
|
+
const value = useCollaborativeState({
|
|
91402
|
+
config,
|
|
91403
|
+
canvasWidth,
|
|
91404
|
+
canvasHeight
|
|
91405
|
+
});
|
|
91406
|
+
return /* @__PURE__ */ jsx(CollaborationContext.Provider, { value, children });
|
|
91407
|
+
}
|
|
91408
|
+
function RemoteUserCursors({
|
|
91409
|
+
remoteUsers,
|
|
91410
|
+
activeSlideIndex,
|
|
91411
|
+
canvasWidth,
|
|
91412
|
+
canvasHeight
|
|
91413
|
+
}) {
|
|
91414
|
+
const visibleUsers = remoteUsers.filter((u2) => u2.activeSlideIndex === activeSlideIndex);
|
|
91415
|
+
if (visibleUsers.length === 0) {
|
|
91416
|
+
return null;
|
|
91417
|
+
}
|
|
91418
|
+
return /* @__PURE__ */ jsx(
|
|
91419
|
+
"svg",
|
|
91420
|
+
{
|
|
91421
|
+
"data-testid": "remote-user-cursors",
|
|
91422
|
+
"data-export-ignore": "true",
|
|
91423
|
+
className: "absolute inset-0 pointer-events-none",
|
|
91424
|
+
style: { zIndex: 9999 },
|
|
91425
|
+
width: canvasWidth,
|
|
91426
|
+
height: canvasHeight,
|
|
91427
|
+
viewBox: `0 0 ${canvasWidth} ${canvasHeight}`,
|
|
91428
|
+
"aria-hidden": "true",
|
|
91429
|
+
children: visibleUsers.map((user) => /* @__PURE__ */ jsxs(
|
|
91430
|
+
"g",
|
|
91431
|
+
{
|
|
91432
|
+
transform: `translate(${user.cursorX}, ${user.cursorY})`,
|
|
91433
|
+
"data-testid": `remote-cursor-${user.clientId}`,
|
|
91434
|
+
children: [
|
|
91435
|
+
/* @__PURE__ */ jsx(
|
|
91436
|
+
"path",
|
|
91437
|
+
{
|
|
91438
|
+
d: "M0 0 L0 16 L4.5 12.5 L8 20 L10.5 19 L7 11.5 L12 11 Z",
|
|
91439
|
+
fill: user.userColor,
|
|
91440
|
+
stroke: "#fff",
|
|
91441
|
+
strokeWidth: 1,
|
|
91442
|
+
opacity: 0.9
|
|
91443
|
+
}
|
|
91444
|
+
),
|
|
91445
|
+
/* @__PURE__ */ jsxs("g", { transform: "translate(14, 18)", children: [
|
|
91446
|
+
/* @__PURE__ */ jsx(
|
|
91447
|
+
"rect",
|
|
91448
|
+
{
|
|
91449
|
+
rx: 3,
|
|
91450
|
+
ry: 3,
|
|
91451
|
+
x: -2,
|
|
91452
|
+
y: -10,
|
|
91453
|
+
width: Math.min(user.userName.length * 7 + 8, 150),
|
|
91454
|
+
height: 16,
|
|
91455
|
+
fill: user.userColor,
|
|
91456
|
+
opacity: 0.85
|
|
91457
|
+
}
|
|
91458
|
+
),
|
|
91459
|
+
/* @__PURE__ */ jsx(
|
|
91460
|
+
"text",
|
|
91461
|
+
{
|
|
91462
|
+
fill: "#fff",
|
|
91463
|
+
fontSize: 10,
|
|
91464
|
+
fontFamily: "system-ui, sans-serif",
|
|
91465
|
+
fontWeight: 500,
|
|
91466
|
+
dominantBaseline: "central",
|
|
91467
|
+
y: -2,
|
|
91468
|
+
x: 2,
|
|
91469
|
+
children: user.userName.length > 20 ? `${user.userName.slice(0, 18)}...` : user.userName
|
|
91470
|
+
}
|
|
91471
|
+
)
|
|
91472
|
+
] })
|
|
91473
|
+
]
|
|
91474
|
+
},
|
|
91475
|
+
user.clientId
|
|
91476
|
+
))
|
|
91477
|
+
}
|
|
91478
|
+
);
|
|
91479
|
+
}
|
|
91480
|
+
var STATUS_STYLES = {
|
|
91481
|
+
connected: {
|
|
91482
|
+
dot: "bg-green-400",
|
|
91483
|
+
text: "text-green-400",
|
|
91484
|
+
label: "Connected"
|
|
91485
|
+
},
|
|
91486
|
+
connecting: {
|
|
91487
|
+
dot: "bg-yellow-400 animate-pulse",
|
|
91488
|
+
text: "text-yellow-400",
|
|
91489
|
+
label: "Connecting..."
|
|
91490
|
+
},
|
|
91491
|
+
disconnected: {
|
|
91492
|
+
dot: "bg-gray-500",
|
|
91493
|
+
text: "text-gray-500",
|
|
91494
|
+
label: "Disconnected"
|
|
91495
|
+
},
|
|
91496
|
+
error: {
|
|
91497
|
+
dot: "bg-red-400",
|
|
91498
|
+
text: "text-red-400",
|
|
91499
|
+
label: "Connection error"
|
|
91500
|
+
}
|
|
91501
|
+
};
|
|
91502
|
+
function CollaborationStatusIndicator({
|
|
91503
|
+
status,
|
|
91504
|
+
connectedCount
|
|
91505
|
+
}) {
|
|
91506
|
+
const { t: t2 } = useTranslation();
|
|
91507
|
+
const style = STATUS_STYLES[status];
|
|
91508
|
+
return /* @__PURE__ */ jsxs(
|
|
91509
|
+
"div",
|
|
91510
|
+
{
|
|
91511
|
+
"data-testid": "collaboration-status",
|
|
91512
|
+
className: "flex items-center gap-1.5",
|
|
91513
|
+
"aria-label": t2("pptx.collaboration.statusAriaLabel", {
|
|
91514
|
+
status: t2(`pptx.collaboration.status.${status}`),
|
|
91515
|
+
count: connectedCount
|
|
91516
|
+
}),
|
|
91517
|
+
children: [
|
|
91518
|
+
/* @__PURE__ */ jsx("span", { className: `inline-block w-2 h-2 rounded-full ${style.dot}`, "aria-hidden": "true" }),
|
|
91519
|
+
/* @__PURE__ */ jsx("span", { className: `text-[10px] ${style.text}`, children: status === "connected" ? t2("pptx.collaboration.userCount", { count: connectedCount }) : t2(`pptx.collaboration.status.${status}`) })
|
|
91520
|
+
]
|
|
91521
|
+
}
|
|
91522
|
+
);
|
|
91523
|
+
}
|
|
91524
|
+
function CollaborationCursorOverlay({
|
|
91525
|
+
activeSlideIndex,
|
|
91526
|
+
canvasWidth,
|
|
91527
|
+
canvasHeight,
|
|
91528
|
+
selectedElementId
|
|
91529
|
+
}) {
|
|
91530
|
+
const collab = useCollaboration();
|
|
91531
|
+
const containerRef = useRef(null);
|
|
91532
|
+
const prevSelectionRef = useRef(selectedElementId);
|
|
91533
|
+
useEffect(() => {
|
|
91534
|
+
if (!collab || selectedElementId === prevSelectionRef.current) {
|
|
91535
|
+
return;
|
|
91536
|
+
}
|
|
91537
|
+
prevSelectionRef.current = selectedElementId;
|
|
91538
|
+
collab.broadcastPresence({
|
|
91539
|
+
selectedElementId: selectedElementId ?? void 0,
|
|
91540
|
+
activeSlideIndex
|
|
91541
|
+
});
|
|
91542
|
+
}, [collab, selectedElementId, activeSlideIndex]);
|
|
91543
|
+
useEffect(() => {
|
|
91544
|
+
if (!collab) {
|
|
91545
|
+
return;
|
|
91546
|
+
}
|
|
91547
|
+
const parent = containerRef.current?.parentElement;
|
|
91548
|
+
if (!parent) {
|
|
91549
|
+
return;
|
|
91550
|
+
}
|
|
91551
|
+
const handler = (e2) => {
|
|
91552
|
+
const rect = parent.getBoundingClientRect();
|
|
91553
|
+
const x2 = (e2.clientX - rect.left) / rect.width * canvasWidth;
|
|
91554
|
+
const y = (e2.clientY - rect.top) / rect.height * canvasHeight;
|
|
91555
|
+
collab.broadcastPresence({
|
|
91556
|
+
cursorX: x2,
|
|
91557
|
+
cursorY: y,
|
|
91558
|
+
activeSlideIndex
|
|
91559
|
+
});
|
|
91560
|
+
};
|
|
91561
|
+
parent.addEventListener("pointermove", handler);
|
|
91562
|
+
return () => parent.removeEventListener("pointermove", handler);
|
|
91563
|
+
}, [collab, canvasWidth, canvasHeight, activeSlideIndex]);
|
|
91564
|
+
if (!collab) {
|
|
91565
|
+
return null;
|
|
91566
|
+
}
|
|
91567
|
+
return /* @__PURE__ */ jsx(
|
|
91568
|
+
"div",
|
|
91569
|
+
{
|
|
91570
|
+
ref: containerRef,
|
|
91571
|
+
"data-testid": "collab-pointer-tracker",
|
|
91572
|
+
"data-export-ignore": "true",
|
|
91573
|
+
style: { display: "contents" },
|
|
91574
|
+
children: /* @__PURE__ */ jsx(
|
|
91575
|
+
RemoteUserCursors,
|
|
91576
|
+
{
|
|
91577
|
+
remoteUsers: collab.remoteUsers,
|
|
91578
|
+
activeSlideIndex,
|
|
91579
|
+
canvasWidth,
|
|
91580
|
+
canvasHeight
|
|
91581
|
+
}
|
|
91582
|
+
)
|
|
91583
|
+
}
|
|
91584
|
+
);
|
|
91585
|
+
}
|
|
91586
|
+
function RemoteSelectionOverlay({
|
|
91587
|
+
elements,
|
|
91588
|
+
activeSlideIndex
|
|
91589
|
+
}) {
|
|
91590
|
+
const collab = useCollaboration();
|
|
91591
|
+
if (!collab) {
|
|
91592
|
+
return null;
|
|
91593
|
+
}
|
|
91594
|
+
const elementMap = /* @__PURE__ */ new Map();
|
|
91595
|
+
for (const el of elements) {
|
|
91596
|
+
elementMap.set(el.id, el);
|
|
91597
|
+
}
|
|
91598
|
+
const selections = [];
|
|
91599
|
+
for (const user of collab.remoteUsers) {
|
|
91600
|
+
if (user.activeSlideIndex === activeSlideIndex && user.selectedElementId) {
|
|
91601
|
+
const el = elementMap.get(user.selectedElementId);
|
|
91602
|
+
if (el) {
|
|
91603
|
+
selections.push({
|
|
91604
|
+
userName: user.userName,
|
|
91605
|
+
userColor: user.userColor,
|
|
91606
|
+
element: el
|
|
91607
|
+
});
|
|
91608
|
+
}
|
|
91609
|
+
}
|
|
91610
|
+
}
|
|
91611
|
+
if (selections.length === 0) {
|
|
91612
|
+
return null;
|
|
91613
|
+
}
|
|
91614
|
+
return /* @__PURE__ */ jsx(Fragment, { children: selections.map((sel) => /* @__PURE__ */ jsx(
|
|
91615
|
+
"div",
|
|
91616
|
+
{
|
|
91617
|
+
"data-testid": `remote-selection-${sel.element.id}`,
|
|
91618
|
+
"data-export-ignore": "true",
|
|
91619
|
+
className: "absolute pointer-events-none",
|
|
91620
|
+
style: {
|
|
91621
|
+
left: sel.element.x,
|
|
91622
|
+
top: sel.element.y,
|
|
91623
|
+
width: sel.element.width,
|
|
91624
|
+
height: sel.element.height,
|
|
91625
|
+
zIndex: 9997,
|
|
91626
|
+
border: `2px solid ${sel.userColor}`,
|
|
91627
|
+
borderRadius: 2
|
|
91628
|
+
},
|
|
91629
|
+
children: /* @__PURE__ */ jsx(
|
|
91630
|
+
"span",
|
|
91631
|
+
{
|
|
91632
|
+
className: "absolute -top-5 left-0 px-1 py-0.5 text-[9px] font-medium text-white rounded-sm whitespace-nowrap leading-none",
|
|
91633
|
+
style: { backgroundColor: sel.userColor },
|
|
91634
|
+
children: sel.userName
|
|
91635
|
+
}
|
|
91636
|
+
)
|
|
91637
|
+
},
|
|
91638
|
+
`remote-sel-${sel.element.id}`
|
|
91639
|
+
)) });
|
|
91640
|
+
}
|
|
91105
91641
|
function SectionContextMenu({
|
|
91106
91642
|
state: state2,
|
|
91107
91643
|
sectionGroups,
|
|
@@ -91383,6 +91919,7 @@ function SlideItemInner({
|
|
|
91383
91919
|
canvasSize,
|
|
91384
91920
|
canEdit,
|
|
91385
91921
|
rehearsalTimings,
|
|
91922
|
+
presenceUsers,
|
|
91386
91923
|
onSelectSlide,
|
|
91387
91924
|
onSlideContextMenu,
|
|
91388
91925
|
onAddSection,
|
|
@@ -91425,16 +91962,27 @@ function SlideItemInner({
|
|
|
91425
91962
|
onDragOver,
|
|
91426
91963
|
onDrop: (e2) => onDrop(e2, slideIndex),
|
|
91427
91964
|
children: [
|
|
91428
|
-
/* @__PURE__ */
|
|
91429
|
-
|
|
91430
|
-
|
|
91431
|
-
|
|
91432
|
-
|
|
91433
|
-
|
|
91434
|
-
|
|
91435
|
-
|
|
91436
|
-
|
|
91437
|
-
|
|
91965
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5 w-5 shrink-0", children: [
|
|
91966
|
+
/* @__PURE__ */ jsx(
|
|
91967
|
+
"span",
|
|
91968
|
+
{
|
|
91969
|
+
className: cn(
|
|
91970
|
+
"text-[10px] tabular-nums text-right select-none w-full",
|
|
91971
|
+
isActive ? "text-primary font-medium" : "text-muted-foreground"
|
|
91972
|
+
),
|
|
91973
|
+
children: slideIndex + 1
|
|
91974
|
+
}
|
|
91975
|
+
),
|
|
91976
|
+
presenceUsers && presenceUsers.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-center gap-px", children: presenceUsers.slice(0, 4).map((u2, i3) => /* @__PURE__ */ jsx(
|
|
91977
|
+
"span",
|
|
91978
|
+
{
|
|
91979
|
+
className: "w-[6px] h-[6px] rounded-full",
|
|
91980
|
+
style: { backgroundColor: u2.userColor },
|
|
91981
|
+
title: u2.userName
|
|
91982
|
+
},
|
|
91983
|
+
i3
|
|
91984
|
+
)) })
|
|
91985
|
+
] }),
|
|
91438
91986
|
/* @__PURE__ */ jsxs(
|
|
91439
91987
|
"div",
|
|
91440
91988
|
{
|
|
@@ -91584,8 +92132,26 @@ function SlidesPaneSidebar({
|
|
|
91584
92132
|
panelWidth
|
|
91585
92133
|
}) {
|
|
91586
92134
|
const { t: t2 } = useTranslation();
|
|
92135
|
+
const collab = useCollaboration();
|
|
91587
92136
|
const slideRefs = useRef(/* @__PURE__ */ new Map());
|
|
91588
92137
|
const renameInputRef = useRef(null);
|
|
92138
|
+
const slidePresenceMap = useMemo(() => {
|
|
92139
|
+
if (!collab || collab.remoteUsers.length === 0) {
|
|
92140
|
+
return void 0;
|
|
92141
|
+
}
|
|
92142
|
+
const map3 = /* @__PURE__ */ new Map();
|
|
92143
|
+
for (const user of collab.remoteUsers) {
|
|
92144
|
+
const idx = user.activeSlideIndex;
|
|
92145
|
+
const existing = map3.get(idx);
|
|
92146
|
+
const entry = { userName: user.userName, userColor: user.userColor };
|
|
92147
|
+
if (existing) {
|
|
92148
|
+
existing.push(entry);
|
|
92149
|
+
} else {
|
|
92150
|
+
map3.set(idx, [entry]);
|
|
92151
|
+
}
|
|
92152
|
+
}
|
|
92153
|
+
return map3;
|
|
92154
|
+
}, [collab]);
|
|
91589
92155
|
const estimatedItemHeight = useMemo(
|
|
91590
92156
|
() => estimateSlideItemHeight(canvasSize.width, canvasSize.height),
|
|
91591
92157
|
[canvasSize.width, canvasSize.height]
|
|
@@ -91707,6 +92273,7 @@ function SlidesPaneSidebar({
|
|
|
91707
92273
|
canvasSize,
|
|
91708
92274
|
canEdit,
|
|
91709
92275
|
rehearsalTimings,
|
|
92276
|
+
presenceUsers: slidePresenceMap?.get(item.slideIndex),
|
|
91710
92277
|
onSelectSlide,
|
|
91711
92278
|
onSlideContextMenu,
|
|
91712
92279
|
onAddSection,
|
|
@@ -91760,6 +92327,7 @@ function SlidesPaneSidebar({
|
|
|
91760
92327
|
canvasSize,
|
|
91761
92328
|
canEdit,
|
|
91762
92329
|
rehearsalTimings,
|
|
92330
|
+
presenceUsers: slidePresenceMap?.get(idx),
|
|
91763
92331
|
onSelectSlide,
|
|
91764
92332
|
onSlideContextMenu,
|
|
91765
92333
|
onAddSection,
|
|
@@ -96526,16 +97094,31 @@ var ALIGN_BTNS = [
|
|
|
96526
97094
|
{ k: "bottom", el: /* @__PURE__ */ jsx(LuChevronDown, { className: ic2 }) }
|
|
96527
97095
|
];
|
|
96528
97096
|
var DRAW_TOOLS = [
|
|
96529
|
-
{
|
|
96530
|
-
|
|
97097
|
+
{
|
|
97098
|
+
id: "select",
|
|
97099
|
+
icon: /* @__PURE__ */ jsx(LuMoveRight, { className: ic2 }),
|
|
97100
|
+
t: "Select",
|
|
97101
|
+
ac: "bg-primary text-primary-foreground"
|
|
97102
|
+
},
|
|
97103
|
+
{
|
|
97104
|
+
id: "pen",
|
|
97105
|
+
icon: /* @__PURE__ */ jsx(LuPencil, { className: ic2 }),
|
|
97106
|
+
t: "Pen",
|
|
97107
|
+
ac: "bg-primary text-primary-foreground"
|
|
97108
|
+
},
|
|
96531
97109
|
{
|
|
96532
97110
|
id: "highlighter",
|
|
96533
97111
|
icon: /* @__PURE__ */ jsx(LuType, { className: ic2 }),
|
|
96534
97112
|
t: "Highlighter",
|
|
96535
97113
|
ac: "bg-yellow-600 text-white"
|
|
96536
97114
|
},
|
|
96537
|
-
{ id: "eraser", icon: /* @__PURE__ */ jsx(LuMinus, { className: ic2 }), t: "Eraser" },
|
|
96538
|
-
{
|
|
97115
|
+
{ id: "eraser", icon: /* @__PURE__ */ jsx(LuMinus, { className: ic2 }), t: "Eraser", ac: "bg-red-600 text-white" },
|
|
97116
|
+
{
|
|
97117
|
+
id: "freeform",
|
|
97118
|
+
icon: /* @__PURE__ */ jsx(LuSpline, { className: ic2 }),
|
|
97119
|
+
t: "Freeform",
|
|
97120
|
+
ac: "bg-primary text-primary-foreground"
|
|
97121
|
+
}
|
|
96539
97122
|
];
|
|
96540
97123
|
var OV = [
|
|
96541
97124
|
{
|
|
@@ -96741,7 +97324,7 @@ function AnimationsSection(p3) {
|
|
|
96741
97324
|
"button",
|
|
96742
97325
|
{
|
|
96743
97326
|
type: "button",
|
|
96744
|
-
onClick: p3.onToggleInspector,
|
|
97327
|
+
onClick: p3.onOpenAnimationPanel ?? p3.onToggleInspector,
|
|
96745
97328
|
className: cn(
|
|
96746
97329
|
pill,
|
|
96747
97330
|
p3.isInspectorPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
|
|
@@ -98268,347 +98851,6 @@ function TextSection(p3) {
|
|
|
98268
98851
|
] })
|
|
98269
98852
|
] });
|
|
98270
98853
|
}
|
|
98271
|
-
|
|
98272
|
-
// src/viewer/hooks/collaboration/sanitize.ts
|
|
98273
|
-
var ROOM_ID_REGEX = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
98274
|
-
function validateRoomId(roomId) {
|
|
98275
|
-
if (!ROOM_ID_REGEX.test(roomId)) {
|
|
98276
|
-
throw new Error(
|
|
98277
|
-
`Invalid collaboration room ID: "${roomId}". Must be 1-128 alphanumeric characters, hyphens, or underscores.`
|
|
98278
|
-
);
|
|
98279
|
-
}
|
|
98280
|
-
return roomId;
|
|
98281
|
-
}
|
|
98282
|
-
function sanitizeUserName(name) {
|
|
98283
|
-
if (typeof name !== "string") {
|
|
98284
|
-
return "Anonymous";
|
|
98285
|
-
}
|
|
98286
|
-
const stripped = name.replace(/<[^>]*>/g, "");
|
|
98287
|
-
const trimmed = stripped.trim().slice(0, 64);
|
|
98288
|
-
return trimmed || "Anonymous";
|
|
98289
|
-
}
|
|
98290
|
-
function clampCursorPosition(value, min2, max2) {
|
|
98291
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
98292
|
-
return 0;
|
|
98293
|
-
}
|
|
98294
|
-
const margin = 20;
|
|
98295
|
-
return Math.max(min2 - margin, Math.min(max2 + margin, value));
|
|
98296
|
-
}
|
|
98297
|
-
var HEX_COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
|
|
98298
|
-
function sanitizeColor(color, fallback = "#6366f1") {
|
|
98299
|
-
if (typeof color !== "string") {
|
|
98300
|
-
return fallback;
|
|
98301
|
-
}
|
|
98302
|
-
return HEX_COLOR_REGEX.test(color) ? color : fallback;
|
|
98303
|
-
}
|
|
98304
|
-
function sanitizeAvatarUrl(url) {
|
|
98305
|
-
if (typeof url !== "string") {
|
|
98306
|
-
return void 0;
|
|
98307
|
-
}
|
|
98308
|
-
try {
|
|
98309
|
-
const parsed = new URL(url);
|
|
98310
|
-
if (parsed.protocol === "https:" || parsed.protocol === "http:" || parsed.protocol === "data:") {
|
|
98311
|
-
return url;
|
|
98312
|
-
}
|
|
98313
|
-
} catch {
|
|
98314
|
-
}
|
|
98315
|
-
return void 0;
|
|
98316
|
-
}
|
|
98317
|
-
function sanitizeSlideIndex(value) {
|
|
98318
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
98319
|
-
return 0;
|
|
98320
|
-
}
|
|
98321
|
-
return Math.max(0, Math.floor(value));
|
|
98322
|
-
}
|
|
98323
|
-
function sanitizePresence(raw, canvasWidth, canvasHeight) {
|
|
98324
|
-
if (typeof raw.clientId !== "number") {
|
|
98325
|
-
return null;
|
|
98326
|
-
}
|
|
98327
|
-
return {
|
|
98328
|
-
clientId: raw.clientId,
|
|
98329
|
-
userName: sanitizeUserName(raw.userName),
|
|
98330
|
-
userAvatar: sanitizeAvatarUrl(raw.userAvatar),
|
|
98331
|
-
userColor: sanitizeColor(raw.userColor),
|
|
98332
|
-
activeSlideIndex: sanitizeSlideIndex(raw.activeSlideIndex),
|
|
98333
|
-
cursorX: clampCursorPosition(raw.cursorX, 0, canvasWidth),
|
|
98334
|
-
cursorY: clampCursorPosition(raw.cursorY, 0, canvasHeight),
|
|
98335
|
-
lastUpdated: typeof raw.lastUpdated === "string" ? raw.lastUpdated : (/* @__PURE__ */ new Date()).toISOString(),
|
|
98336
|
-
selectedElementId: typeof raw.selectedElementId === "string" ? raw.selectedElementId.slice(0, 128) : void 0
|
|
98337
|
-
};
|
|
98338
|
-
}
|
|
98339
|
-
var BROADCAST_THROTTLE_MS = 50;
|
|
98340
|
-
var STALE_PRESENCE_MS = 3e4;
|
|
98341
|
-
function usePresenceTracking({
|
|
98342
|
-
awareness,
|
|
98343
|
-
localClientId,
|
|
98344
|
-
userName,
|
|
98345
|
-
userColor,
|
|
98346
|
-
userAvatar,
|
|
98347
|
-
canvasWidth,
|
|
98348
|
-
canvasHeight
|
|
98349
|
-
}) {
|
|
98350
|
-
const [remoteUsers, setRemoteUsers] = useState([]);
|
|
98351
|
-
const lastBroadcastRef = useRef(0);
|
|
98352
|
-
const pendingBroadcastRef = useRef(null);
|
|
98353
|
-
const latestLocalState = useRef({});
|
|
98354
|
-
const broadcastPresence = useCallback(
|
|
98355
|
-
(update2) => {
|
|
98356
|
-
if (!awareness) {
|
|
98357
|
-
return;
|
|
98358
|
-
}
|
|
98359
|
-
Object.assign(latestLocalState.current, update2);
|
|
98360
|
-
const now = Date.now();
|
|
98361
|
-
const elapsed = now - lastBroadcastRef.current;
|
|
98362
|
-
const flush = () => {
|
|
98363
|
-
const state2 = {
|
|
98364
|
-
...latestLocalState.current,
|
|
98365
|
-
userName,
|
|
98366
|
-
userColor,
|
|
98367
|
-
userAvatar,
|
|
98368
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
98369
|
-
};
|
|
98370
|
-
awareness.setLocalStateField("presence", state2);
|
|
98371
|
-
lastBroadcastRef.current = Date.now();
|
|
98372
|
-
};
|
|
98373
|
-
if (elapsed >= BROADCAST_THROTTLE_MS) {
|
|
98374
|
-
if (pendingBroadcastRef.current) {
|
|
98375
|
-
clearTimeout(pendingBroadcastRef.current);
|
|
98376
|
-
pendingBroadcastRef.current = null;
|
|
98377
|
-
}
|
|
98378
|
-
flush();
|
|
98379
|
-
} else if (!pendingBroadcastRef.current) {
|
|
98380
|
-
pendingBroadcastRef.current = setTimeout(() => {
|
|
98381
|
-
pendingBroadcastRef.current = null;
|
|
98382
|
-
flush();
|
|
98383
|
-
}, BROADCAST_THROTTLE_MS - elapsed);
|
|
98384
|
-
}
|
|
98385
|
-
},
|
|
98386
|
-
[awareness, userName, userColor, userAvatar]
|
|
98387
|
-
);
|
|
98388
|
-
useEffect(() => {
|
|
98389
|
-
if (!awareness) {
|
|
98390
|
-
return;
|
|
98391
|
-
}
|
|
98392
|
-
awareness.setLocalStateField("presence", {
|
|
98393
|
-
userName,
|
|
98394
|
-
userColor,
|
|
98395
|
-
userAvatar,
|
|
98396
|
-
activeSlideIndex: 0,
|
|
98397
|
-
cursorX: 0,
|
|
98398
|
-
cursorY: 0,
|
|
98399
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
98400
|
-
});
|
|
98401
|
-
}, [awareness, userName, userColor, userAvatar]);
|
|
98402
|
-
useEffect(() => {
|
|
98403
|
-
if (!awareness || localClientId === null) {
|
|
98404
|
-
return;
|
|
98405
|
-
}
|
|
98406
|
-
const handleChange = () => {
|
|
98407
|
-
const now = Date.now();
|
|
98408
|
-
const states = awareness.getStates();
|
|
98409
|
-
const users = [];
|
|
98410
|
-
states.forEach((state2, cid) => {
|
|
98411
|
-
if (cid === localClientId) {
|
|
98412
|
-
return;
|
|
98413
|
-
}
|
|
98414
|
-
const raw = state2?.presence;
|
|
98415
|
-
if (!raw || typeof raw !== "object") {
|
|
98416
|
-
return;
|
|
98417
|
-
}
|
|
98418
|
-
const sanitized = sanitizePresence({ ...raw, clientId: cid }, canvasWidth, canvasHeight);
|
|
98419
|
-
if (!sanitized) {
|
|
98420
|
-
return;
|
|
98421
|
-
}
|
|
98422
|
-
const updatedAt = new Date(sanitized.lastUpdated).getTime();
|
|
98423
|
-
if (Number.isNaN(updatedAt) || now - updatedAt > STALE_PRESENCE_MS) {
|
|
98424
|
-
return;
|
|
98425
|
-
}
|
|
98426
|
-
users.push(sanitized);
|
|
98427
|
-
});
|
|
98428
|
-
setRemoteUsers(users);
|
|
98429
|
-
};
|
|
98430
|
-
awareness.on("change", handleChange);
|
|
98431
|
-
awareness.on("update", handleChange);
|
|
98432
|
-
handleChange();
|
|
98433
|
-
return () => {
|
|
98434
|
-
awareness.off("change", handleChange);
|
|
98435
|
-
awareness.off("update", handleChange);
|
|
98436
|
-
};
|
|
98437
|
-
}, [awareness, localClientId, canvasWidth, canvasHeight]);
|
|
98438
|
-
useEffect(() => {
|
|
98439
|
-
if (!awareness) {
|
|
98440
|
-
return;
|
|
98441
|
-
}
|
|
98442
|
-
const interval = setInterval(() => {
|
|
98443
|
-
awareness.setLocalStateField("presence", {
|
|
98444
|
-
...latestLocalState.current,
|
|
98445
|
-
userName,
|
|
98446
|
-
userColor,
|
|
98447
|
-
userAvatar,
|
|
98448
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
98449
|
-
});
|
|
98450
|
-
}, 1e4);
|
|
98451
|
-
return () => clearInterval(interval);
|
|
98452
|
-
}, [awareness, userName, userColor, userAvatar]);
|
|
98453
|
-
useEffect(() => {
|
|
98454
|
-
return () => {
|
|
98455
|
-
if (pendingBroadcastRef.current) {
|
|
98456
|
-
clearTimeout(pendingBroadcastRef.current);
|
|
98457
|
-
}
|
|
98458
|
-
};
|
|
98459
|
-
}, []);
|
|
98460
|
-
return { remoteUsers, broadcastPresence };
|
|
98461
|
-
}
|
|
98462
|
-
function useYjsProvider({ config }) {
|
|
98463
|
-
const [status, setStatus] = useState("disconnected");
|
|
98464
|
-
const [awareness, setAwareness] = useState(null);
|
|
98465
|
-
const [doc2, setDoc] = useState(null);
|
|
98466
|
-
const [clientId, setClientId] = useState(null);
|
|
98467
|
-
const cleanupRef = useRef(null);
|
|
98468
|
-
const init = useCallback(async () => {
|
|
98469
|
-
const roomId = validateRoomId(config.roomId);
|
|
98470
|
-
setStatus("connecting");
|
|
98471
|
-
try {
|
|
98472
|
-
const [Y, { WebsocketProvider: WebsocketProvider2 }] = await Promise.all([Promise.resolve().then(() => (init_yjs(), yjs_exports)), Promise.resolve().then(() => (init_y_websocket(), y_websocket_exports))]);
|
|
98473
|
-
const yDoc = new Y.Doc();
|
|
98474
|
-
const provider = new WebsocketProvider2(
|
|
98475
|
-
config.serverUrl,
|
|
98476
|
-
roomId,
|
|
98477
|
-
yDoc,
|
|
98478
|
-
// eslint-disable-line @typescript-eslint/no-explicit-any
|
|
98479
|
-
{
|
|
98480
|
-
params: config.authToken ? { token: config.authToken } : void 0
|
|
98481
|
-
}
|
|
98482
|
-
);
|
|
98483
|
-
const handleStatus = (event) => {
|
|
98484
|
-
if (event.status === "connected") {
|
|
98485
|
-
setStatus("connected");
|
|
98486
|
-
} else if (event.status === "disconnected") {
|
|
98487
|
-
setStatus("disconnected");
|
|
98488
|
-
}
|
|
98489
|
-
};
|
|
98490
|
-
provider.on("status", handleStatus);
|
|
98491
|
-
if (provider.wsconnected) {
|
|
98492
|
-
setStatus("connected");
|
|
98493
|
-
}
|
|
98494
|
-
setDoc(yDoc);
|
|
98495
|
-
setAwareness(provider.awareness);
|
|
98496
|
-
setClientId(provider.awareness.clientID);
|
|
98497
|
-
cleanupRef.current = () => {
|
|
98498
|
-
provider.off("status", handleStatus);
|
|
98499
|
-
provider.destroy();
|
|
98500
|
-
yDoc.destroy();
|
|
98501
|
-
setDoc(null);
|
|
98502
|
-
setAwareness(null);
|
|
98503
|
-
setClientId(null);
|
|
98504
|
-
setStatus("disconnected");
|
|
98505
|
-
};
|
|
98506
|
-
} catch (err) {
|
|
98507
|
-
console.warn(
|
|
98508
|
-
"[pptx-viewer] Collaboration packages not available:",
|
|
98509
|
-
err instanceof Error ? err.message : err
|
|
98510
|
-
);
|
|
98511
|
-
setStatus("error");
|
|
98512
|
-
}
|
|
98513
|
-
}, [config.roomId, config.serverUrl, config.authToken]);
|
|
98514
|
-
useEffect(() => {
|
|
98515
|
-
init();
|
|
98516
|
-
return () => {
|
|
98517
|
-
cleanupRef.current?.();
|
|
98518
|
-
cleanupRef.current = null;
|
|
98519
|
-
};
|
|
98520
|
-
}, [init]);
|
|
98521
|
-
return { status, awareness, doc: doc2, clientId };
|
|
98522
|
-
}
|
|
98523
|
-
|
|
98524
|
-
// src/viewer/hooks/collaboration/useCollaborativeState.ts
|
|
98525
|
-
function useCollaborativeState({
|
|
98526
|
-
config,
|
|
98527
|
-
canvasWidth,
|
|
98528
|
-
canvasHeight
|
|
98529
|
-
}) {
|
|
98530
|
-
const userColor = sanitizeColor(config.userColor, "#6366f1");
|
|
98531
|
-
const { status, awareness, doc: doc2, clientId } = useYjsProvider({ config });
|
|
98532
|
-
const { remoteUsers, broadcastPresence } = usePresenceTracking({
|
|
98533
|
-
awareness,
|
|
98534
|
-
localClientId: clientId,
|
|
98535
|
-
userName: config.userName,
|
|
98536
|
-
userColor,
|
|
98537
|
-
userAvatar: config.userAvatar,
|
|
98538
|
-
canvasWidth,
|
|
98539
|
-
canvasHeight
|
|
98540
|
-
});
|
|
98541
|
-
const connectedCount = status === "connected" ? remoteUsers.length + 1 : remoteUsers.length;
|
|
98542
|
-
return {
|
|
98543
|
-
status,
|
|
98544
|
-
remoteUsers,
|
|
98545
|
-
broadcastPresence,
|
|
98546
|
-
connectedCount,
|
|
98547
|
-
config,
|
|
98548
|
-
doc: doc2
|
|
98549
|
-
};
|
|
98550
|
-
}
|
|
98551
|
-
var CollaborationContext = createContext(null);
|
|
98552
|
-
function useCollaboration() {
|
|
98553
|
-
return useContext(CollaborationContext);
|
|
98554
|
-
}
|
|
98555
|
-
function CollaborationProvider({
|
|
98556
|
-
config,
|
|
98557
|
-
canvasWidth,
|
|
98558
|
-
canvasHeight,
|
|
98559
|
-
children
|
|
98560
|
-
}) {
|
|
98561
|
-
const value = useCollaborativeState({
|
|
98562
|
-
config,
|
|
98563
|
-
canvasWidth,
|
|
98564
|
-
canvasHeight
|
|
98565
|
-
});
|
|
98566
|
-
return /* @__PURE__ */ jsx(CollaborationContext.Provider, { value, children });
|
|
98567
|
-
}
|
|
98568
|
-
var STATUS_STYLES = {
|
|
98569
|
-
connected: {
|
|
98570
|
-
dot: "bg-green-400",
|
|
98571
|
-
text: "text-green-400",
|
|
98572
|
-
label: "Connected"
|
|
98573
|
-
},
|
|
98574
|
-
connecting: {
|
|
98575
|
-
dot: "bg-yellow-400 animate-pulse",
|
|
98576
|
-
text: "text-yellow-400",
|
|
98577
|
-
label: "Connecting..."
|
|
98578
|
-
},
|
|
98579
|
-
disconnected: {
|
|
98580
|
-
dot: "bg-gray-500",
|
|
98581
|
-
text: "text-gray-500",
|
|
98582
|
-
label: "Disconnected"
|
|
98583
|
-
},
|
|
98584
|
-
error: {
|
|
98585
|
-
dot: "bg-red-400",
|
|
98586
|
-
text: "text-red-400",
|
|
98587
|
-
label: "Connection error"
|
|
98588
|
-
}
|
|
98589
|
-
};
|
|
98590
|
-
function CollaborationStatusIndicator({
|
|
98591
|
-
status,
|
|
98592
|
-
connectedCount
|
|
98593
|
-
}) {
|
|
98594
|
-
const { t: t2 } = useTranslation();
|
|
98595
|
-
const style = STATUS_STYLES[status];
|
|
98596
|
-
return /* @__PURE__ */ jsxs(
|
|
98597
|
-
"div",
|
|
98598
|
-
{
|
|
98599
|
-
"data-testid": "collaboration-status",
|
|
98600
|
-
className: "flex items-center gap-1.5",
|
|
98601
|
-
"aria-label": t2("pptx.collaboration.statusAriaLabel", {
|
|
98602
|
-
status: t2(`pptx.collaboration.status.${status}`),
|
|
98603
|
-
count: connectedCount
|
|
98604
|
-
}),
|
|
98605
|
-
children: [
|
|
98606
|
-
/* @__PURE__ */ jsx("span", { className: `inline-block w-2 h-2 rounded-full ${style.dot}`, "aria-hidden": "true" }),
|
|
98607
|
-
/* @__PURE__ */ jsx("span", { className: `text-[10px] ${style.text}`, children: status === "connected" ? t2("pptx.collaboration.userCount", { count: connectedCount }) : t2(`pptx.collaboration.status.${status}`) })
|
|
98608
|
-
]
|
|
98609
|
-
}
|
|
98610
|
-
);
|
|
98611
|
-
}
|
|
98612
98854
|
function CustomShowsControls({
|
|
98613
98855
|
customShows,
|
|
98614
98856
|
activeCustomShowId,
|
|
@@ -99047,29 +99289,38 @@ function ToolbarPrimaryRow(p3) {
|
|
|
99047
99289
|
]
|
|
99048
99290
|
}
|
|
99049
99291
|
),
|
|
99050
|
-
collab && (collab.status === "connected" || collab.status === "connecting") && collab.remoteUsers.length > 0 && /* @__PURE__ */ jsxs(
|
|
99051
|
-
|
|
99052
|
-
|
|
99053
|
-
|
|
99054
|
-
|
|
99055
|
-
|
|
99056
|
-
|
|
99057
|
-
|
|
99058
|
-
|
|
99292
|
+
collab && (collab.status === "connected" || collab.status === "connecting") && collab.remoteUsers.length > 0 && /* @__PURE__ */ jsxs(
|
|
99293
|
+
"button",
|
|
99294
|
+
{
|
|
99295
|
+
type: "button",
|
|
99296
|
+
onClick: p3.onOpenShareDialog,
|
|
99297
|
+
className: "flex items-center -space-x-1.5 mx-1 rounded-sm px-1 py-0.5 hover:bg-accent/60 transition-colors cursor-pointer",
|
|
99298
|
+
title: t2("pptx.toolbar.sharingUsers", { count: collab.connectedCount }),
|
|
99299
|
+
children: [
|
|
99300
|
+
collab.remoteUsers.slice(0, 4).map((user) => /* @__PURE__ */ jsx(
|
|
99301
|
+
"div",
|
|
99059
99302
|
{
|
|
99060
|
-
|
|
99061
|
-
|
|
99062
|
-
|
|
99063
|
-
|
|
99064
|
-
|
|
99065
|
-
|
|
99066
|
-
|
|
99067
|
-
|
|
99068
|
-
|
|
99069
|
-
|
|
99070
|
-
|
|
99071
|
-
|
|
99072
|
-
|
|
99303
|
+
className: "w-6 h-6 rounded-full border-2 border-background flex items-center justify-center text-[8px] font-semibold text-white shrink-0",
|
|
99304
|
+
style: { backgroundColor: user.userColor },
|
|
99305
|
+
title: user.userName,
|
|
99306
|
+
children: user.userAvatar ? /* @__PURE__ */ jsx(
|
|
99307
|
+
"img",
|
|
99308
|
+
{
|
|
99309
|
+
src: user.userAvatar,
|
|
99310
|
+
alt: user.userName,
|
|
99311
|
+
className: "w-full h-full rounded-full object-cover"
|
|
99312
|
+
}
|
|
99313
|
+
) : user.userName.slice(0, 2).toUpperCase()
|
|
99314
|
+
},
|
|
99315
|
+
user.clientId
|
|
99316
|
+
)),
|
|
99317
|
+
collab.remoteUsers.length > 4 && /* @__PURE__ */ jsxs("div", { className: "w-6 h-6 rounded-full border-2 border-background bg-muted flex items-center justify-center text-[8px] text-muted-foreground shrink-0", children: [
|
|
99318
|
+
"+",
|
|
99319
|
+
collab.remoteUsers.length - 4
|
|
99320
|
+
] })
|
|
99321
|
+
]
|
|
99322
|
+
}
|
|
99323
|
+
),
|
|
99073
99324
|
/* @__PURE__ */ jsx(
|
|
99074
99325
|
ModeSwitcher,
|
|
99075
99326
|
{
|
|
@@ -99446,7 +99697,8 @@ function Toolbar(p3) {
|
|
|
99446
99697
|
canEdit: p3.canEdit,
|
|
99447
99698
|
selectedElement: p3.selectedElement,
|
|
99448
99699
|
isInspectorPaneOpen: p3.isInspectorPaneOpen,
|
|
99449
|
-
onToggleInspector: p3.onToggleInspector
|
|
99700
|
+
onToggleInspector: p3.onToggleInspector,
|
|
99701
|
+
onOpenAnimationPanel: p3.onOpenAnimationPanel
|
|
99450
99702
|
}
|
|
99451
99703
|
),
|
|
99452
99704
|
sSlw && /* @__PURE__ */ jsx(
|
|
@@ -106891,9 +107143,75 @@ function SetUpSlideShowDialog({
|
|
|
106891
107143
|
}
|
|
106892
107144
|
function BroadcastDialog({
|
|
106893
107145
|
open,
|
|
106894
|
-
onClose
|
|
107146
|
+
onClose,
|
|
107147
|
+
onStartBroadcast,
|
|
107148
|
+
onStopBroadcast,
|
|
107149
|
+
onStartPresenting,
|
|
107150
|
+
defaultRoomId,
|
|
107151
|
+
defaultUserName,
|
|
107152
|
+
defaultServerUrl
|
|
106895
107153
|
}) {
|
|
106896
107154
|
const { t: t2 } = useTranslation();
|
|
107155
|
+
const collab = useCollaboration();
|
|
107156
|
+
const isBroadcasting = collab !== null && collab.status !== "disconnected" && collab.status !== "error" && collab.config.role === "broadcaster";
|
|
107157
|
+
const [roomId, setRoomId] = useState("");
|
|
107158
|
+
const [userName, setUserName] = useState("");
|
|
107159
|
+
const [serverUrl, setServerUrl] = useState("");
|
|
107160
|
+
const [copied, setCopied] = useState(false);
|
|
107161
|
+
const dialogRef = useRef(null);
|
|
107162
|
+
useEffect(() => {
|
|
107163
|
+
if (open && !isBroadcasting) {
|
|
107164
|
+
const broadcastRoom = defaultRoomId ? `broadcast-${defaultRoomId}` : `broadcast-${Math.random().toString(36).slice(2, 10)}`;
|
|
107165
|
+
setRoomId(broadcastRoom);
|
|
107166
|
+
setUserName(defaultUserName ?? "");
|
|
107167
|
+
setServerUrl(defaultServerUrl ?? "ws://localhost:1234");
|
|
107168
|
+
}
|
|
107169
|
+
}, [open, isBroadcasting, defaultRoomId, defaultUserName, defaultServerUrl]);
|
|
107170
|
+
useEffect(() => {
|
|
107171
|
+
if (!open) {
|
|
107172
|
+
return;
|
|
107173
|
+
}
|
|
107174
|
+
function handleKeyDown(e2) {
|
|
107175
|
+
if (e2.key === "Escape") {
|
|
107176
|
+
onClose();
|
|
107177
|
+
}
|
|
107178
|
+
}
|
|
107179
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
107180
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
107181
|
+
}, [open, onClose]);
|
|
107182
|
+
useEffect(() => {
|
|
107183
|
+
if (open && dialogRef.current) {
|
|
107184
|
+
dialogRef.current.focus();
|
|
107185
|
+
}
|
|
107186
|
+
}, [open]);
|
|
107187
|
+
const broadcastUrl = typeof window !== "undefined" ? `${window.location.origin}${window.location.pathname}?broadcast=${encodeURIComponent(isBroadcasting ? collab.config.roomId : roomId)}&server=${encodeURIComponent(isBroadcasting ? collab.config.serverUrl : serverUrl)}` : roomId;
|
|
107188
|
+
const handleCopyUrl = useCallback(() => {
|
|
107189
|
+
void navigator.clipboard.writeText(broadcastUrl).then(() => {
|
|
107190
|
+
setCopied(true);
|
|
107191
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
107192
|
+
return void 0;
|
|
107193
|
+
});
|
|
107194
|
+
}, [broadcastUrl]);
|
|
107195
|
+
const handleStartBroadcast = useCallback(() => {
|
|
107196
|
+
if (!roomId.trim() || !userName.trim()) {
|
|
107197
|
+
return;
|
|
107198
|
+
}
|
|
107199
|
+
onStartBroadcast?.({
|
|
107200
|
+
roomId: roomId.trim(),
|
|
107201
|
+
serverUrl: serverUrl.trim(),
|
|
107202
|
+
userName: userName.trim(),
|
|
107203
|
+
role: "broadcaster"
|
|
107204
|
+
});
|
|
107205
|
+
setTimeout(() => {
|
|
107206
|
+
onStartPresenting?.();
|
|
107207
|
+
}, 100);
|
|
107208
|
+
onClose();
|
|
107209
|
+
}, [roomId, userName, serverUrl, onStartBroadcast, onStartPresenting, onClose]);
|
|
107210
|
+
const handleStopBroadcast = useCallback(() => {
|
|
107211
|
+
onStopBroadcast?.();
|
|
107212
|
+
onClose();
|
|
107213
|
+
}, [onStopBroadcast, onClose]);
|
|
107214
|
+
const canStart = roomId.trim().length > 0 && userName.trim().length > 0 && serverUrl.trim().length > 0;
|
|
106897
107215
|
if (!open) {
|
|
106898
107216
|
return null;
|
|
106899
107217
|
}
|
|
@@ -106907,42 +107225,225 @@ function BroadcastDialog({
|
|
|
106907
107225
|
onClick: onClose
|
|
106908
107226
|
}
|
|
106909
107227
|
),
|
|
106910
|
-
/* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-[201] flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs(
|
|
106911
|
-
|
|
106912
|
-
|
|
107228
|
+
/* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-[201] flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs(
|
|
107229
|
+
"div",
|
|
107230
|
+
{
|
|
107231
|
+
ref: dialogRef,
|
|
107232
|
+
role: "dialog",
|
|
107233
|
+
"aria-modal": "true",
|
|
107234
|
+
"aria-label": t2("pptx.broadcast.title"),
|
|
107235
|
+
tabIndex: -1,
|
|
107236
|
+
className: "pointer-events-auto w-full max-w-md rounded-xl border border-border bg-popover text-foreground shadow-2xl outline-none",
|
|
107237
|
+
children: [
|
|
107238
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-5 py-3 border-b border-border", children: [
|
|
107239
|
+
/* @__PURE__ */ jsxs("h2", { className: "text-sm font-semibold text-foreground flex items-center gap-2", children: [
|
|
107240
|
+
/* @__PURE__ */ jsx(LuCast, { className: "w-4 h-4" }),
|
|
107241
|
+
isBroadcasting ? t2("pptx.broadcast.broadcasting") : t2("pptx.broadcast.title")
|
|
107242
|
+
] }),
|
|
107243
|
+
/* @__PURE__ */ jsx(
|
|
107244
|
+
"button",
|
|
107245
|
+
{
|
|
107246
|
+
type: "button",
|
|
107247
|
+
onClick: onClose,
|
|
107248
|
+
className: "text-muted-foreground hover:text-foreground text-lg leading-none",
|
|
107249
|
+
"aria-label": "Close",
|
|
107250
|
+
children: "\xD7"
|
|
107251
|
+
}
|
|
107252
|
+
)
|
|
107253
|
+
] }),
|
|
107254
|
+
/* @__PURE__ */ jsx("div", { className: "px-5 py-4", children: isBroadcasting ? /* @__PURE__ */ jsx(
|
|
107255
|
+
ActiveBroadcastView,
|
|
107256
|
+
{
|
|
107257
|
+
collab,
|
|
107258
|
+
broadcastUrl,
|
|
107259
|
+
copied,
|
|
107260
|
+
onCopyUrl: handleCopyUrl,
|
|
107261
|
+
onStopBroadcast: handleStopBroadcast
|
|
107262
|
+
}
|
|
107263
|
+
) : /* @__PURE__ */ jsx(
|
|
107264
|
+
StartBroadcastForm,
|
|
107265
|
+
{
|
|
107266
|
+
roomId,
|
|
107267
|
+
userName,
|
|
107268
|
+
serverUrl,
|
|
107269
|
+
onRoomIdChange: setRoomId,
|
|
107270
|
+
onUserNameChange: setUserName,
|
|
107271
|
+
onServerUrlChange: setServerUrl
|
|
107272
|
+
}
|
|
107273
|
+
) }),
|
|
107274
|
+
!isBroadcasting && /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 px-5 py-3 border-t border-border", children: [
|
|
107275
|
+
/* @__PURE__ */ jsx(
|
|
107276
|
+
"button",
|
|
107277
|
+
{
|
|
107278
|
+
type: "button",
|
|
107279
|
+
onClick: onClose,
|
|
107280
|
+
className: "px-3 py-1.5 rounded bg-muted hover:bg-accent text-[12px] text-foreground transition-colors",
|
|
107281
|
+
children: t2("common.close")
|
|
107282
|
+
}
|
|
107283
|
+
),
|
|
107284
|
+
/* @__PURE__ */ jsx(
|
|
107285
|
+
"button",
|
|
107286
|
+
{
|
|
107287
|
+
type: "button",
|
|
107288
|
+
disabled: !canStart,
|
|
107289
|
+
onClick: handleStartBroadcast,
|
|
107290
|
+
className: "px-3 py-1.5 rounded bg-primary hover:bg-primary/90 text-[12px] text-primary-foreground transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
|
|
107291
|
+
children: t2("pptx.broadcast.startBroadcast")
|
|
107292
|
+
}
|
|
107293
|
+
)
|
|
107294
|
+
] })
|
|
107295
|
+
]
|
|
107296
|
+
}
|
|
107297
|
+
) })
|
|
107298
|
+
] });
|
|
107299
|
+
}
|
|
107300
|
+
function StartBroadcastForm({
|
|
107301
|
+
roomId,
|
|
107302
|
+
userName,
|
|
107303
|
+
serverUrl,
|
|
107304
|
+
onRoomIdChange,
|
|
107305
|
+
onUserNameChange,
|
|
107306
|
+
onServerUrlChange
|
|
107307
|
+
}) {
|
|
107308
|
+
const { t: t2 } = useTranslation();
|
|
107309
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
107310
|
+
/* @__PURE__ */ jsx("p", { className: "text-[13px] text-muted-foreground leading-relaxed", children: t2("pptx.broadcast.description") }),
|
|
107311
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
107312
|
+
/* @__PURE__ */ jsx(
|
|
107313
|
+
"label",
|
|
107314
|
+
{
|
|
107315
|
+
htmlFor: "broadcast-room-id",
|
|
107316
|
+
className: "block text-[12px] font-medium text-foreground",
|
|
107317
|
+
children: t2("pptx.broadcast.sessionName")
|
|
107318
|
+
}
|
|
107319
|
+
),
|
|
107320
|
+
/* @__PURE__ */ jsx(
|
|
107321
|
+
"input",
|
|
107322
|
+
{
|
|
107323
|
+
id: "broadcast-room-id",
|
|
107324
|
+
type: "text",
|
|
107325
|
+
value: roomId,
|
|
107326
|
+
onChange: (e2) => onRoomIdChange(e2.target.value),
|
|
107327
|
+
placeholder: "broadcast-abc123",
|
|
107328
|
+
className: "w-full px-3 py-1.5 rounded border border-border bg-background text-foreground text-[13px] placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary"
|
|
107329
|
+
}
|
|
107330
|
+
)
|
|
107331
|
+
] }),
|
|
107332
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
107333
|
+
/* @__PURE__ */ jsx(
|
|
107334
|
+
"label",
|
|
107335
|
+
{
|
|
107336
|
+
htmlFor: "broadcast-user-name",
|
|
107337
|
+
className: "block text-[12px] font-medium text-foreground",
|
|
107338
|
+
children: t2("pptx.broadcast.displayName")
|
|
107339
|
+
}
|
|
107340
|
+
),
|
|
107341
|
+
/* @__PURE__ */ jsx(
|
|
107342
|
+
"input",
|
|
107343
|
+
{
|
|
107344
|
+
id: "broadcast-user-name",
|
|
107345
|
+
type: "text",
|
|
107346
|
+
value: userName,
|
|
107347
|
+
onChange: (e2) => onUserNameChange(e2.target.value),
|
|
107348
|
+
placeholder: "Presenter",
|
|
107349
|
+
className: "w-full px-3 py-1.5 rounded border border-border bg-background text-foreground text-[13px] placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary"
|
|
107350
|
+
}
|
|
107351
|
+
)
|
|
107352
|
+
] }),
|
|
107353
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
107354
|
+
/* @__PURE__ */ jsx(
|
|
107355
|
+
"label",
|
|
107356
|
+
{
|
|
107357
|
+
htmlFor: "broadcast-server-url",
|
|
107358
|
+
className: "block text-[12px] font-medium text-foreground",
|
|
107359
|
+
children: t2("pptx.broadcast.serverLabel")
|
|
107360
|
+
}
|
|
107361
|
+
),
|
|
107362
|
+
/* @__PURE__ */ jsx(
|
|
107363
|
+
"input",
|
|
107364
|
+
{
|
|
107365
|
+
id: "broadcast-server-url",
|
|
107366
|
+
type: "text",
|
|
107367
|
+
value: serverUrl,
|
|
107368
|
+
onChange: (e2) => onServerUrlChange(e2.target.value),
|
|
107369
|
+
placeholder: "ws://localhost:1234",
|
|
107370
|
+
className: "w-full px-3 py-1.5 rounded border border-border bg-background text-foreground text-[13px] placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary"
|
|
107371
|
+
}
|
|
107372
|
+
)
|
|
107373
|
+
] }),
|
|
107374
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground/70 leading-relaxed", children: t2("pptx.broadcast.hint") })
|
|
107375
|
+
] });
|
|
107376
|
+
}
|
|
107377
|
+
function ActiveBroadcastView({
|
|
107378
|
+
collab,
|
|
107379
|
+
broadcastUrl,
|
|
107380
|
+
copied,
|
|
107381
|
+
onCopyUrl,
|
|
107382
|
+
onStopBroadcast
|
|
107383
|
+
}) {
|
|
107384
|
+
const { t: t2 } = useTranslation();
|
|
107385
|
+
const statusColor = collab.status === "connected" ? "text-green-400" : collab.status === "connecting" ? "text-yellow-400" : "text-red-400";
|
|
107386
|
+
const statusIcon = collab.status === "connected" || collab.status === "connecting" ? /* @__PURE__ */ jsx(LuWifi, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx(LuWifiOff, { className: "w-4 h-4" });
|
|
107387
|
+
const viewerCount = collab.remoteUsers.filter((u2) => u2.role === "viewer").length;
|
|
107388
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
107389
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
107390
|
+
/* @__PURE__ */ jsx("span", { className: statusColor, children: statusIcon }),
|
|
107391
|
+
/* @__PURE__ */ jsx("span", { className: "text-[13px] font-medium text-foreground capitalize", children: collab.status }),
|
|
107392
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[12px] text-muted-foreground ml-auto flex items-center gap-1", children: [
|
|
107393
|
+
/* @__PURE__ */ jsx(LuUsers, { className: "w-3.5 h-3.5" }),
|
|
107394
|
+
t2("pptx.broadcast.viewerCount", { count: viewerCount })
|
|
107395
|
+
] })
|
|
107396
|
+
] }),
|
|
107397
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
107398
|
+
/* @__PURE__ */ jsx("label", { className: "block text-[12px] font-medium text-foreground", children: t2("pptx.broadcast.viewerLink") }),
|
|
107399
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
107400
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 px-3 py-1.5 rounded border border-border bg-background text-[11px] text-foreground select-all font-mono truncate", children: broadcastUrl }),
|
|
106913
107401
|
/* @__PURE__ */ jsx(
|
|
106914
107402
|
"button",
|
|
106915
107403
|
{
|
|
106916
107404
|
type: "button",
|
|
106917
|
-
onClick:
|
|
106918
|
-
className: "
|
|
106919
|
-
|
|
106920
|
-
children:
|
|
107405
|
+
onClick: onCopyUrl,
|
|
107406
|
+
className: "flex items-center gap-1 px-2.5 py-1.5 rounded border border-border bg-muted hover:bg-accent text-[12px] text-foreground transition-colors shrink-0",
|
|
107407
|
+
title: t2("pptx.broadcast.copyLink"),
|
|
107408
|
+
children: copied ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
107409
|
+
/* @__PURE__ */ jsx(LuCheck, { className: "w-3.5 h-3.5 text-green-400" }),
|
|
107410
|
+
/* @__PURE__ */ jsx("span", { children: t2("pptx.share.copied") })
|
|
107411
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
107412
|
+
/* @__PURE__ */ jsx(LuCopy, { className: "w-3.5 h-3.5" }),
|
|
107413
|
+
/* @__PURE__ */ jsx("span", { children: t2("pptx.share.copyUrl") })
|
|
107414
|
+
] })
|
|
106921
107415
|
}
|
|
106922
107416
|
)
|
|
106923
107417
|
] }),
|
|
106924
|
-
/* @__PURE__ */ jsx("
|
|
106925
|
-
|
|
107418
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: t2("pptx.broadcast.shareHint") })
|
|
107419
|
+
] }),
|
|
107420
|
+
collab.remoteUsers.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
107421
|
+
/* @__PURE__ */ jsx("label", { className: "block text-[12px] font-medium text-foreground", children: t2("pptx.broadcast.viewers") }),
|
|
107422
|
+
/* @__PURE__ */ jsx("div", { className: "rounded border border-border bg-background divide-y divide-border max-h-[120px] overflow-y-auto", children: collab.remoteUsers.map((user) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2", children: [
|
|
106926
107423
|
/* @__PURE__ */ jsx(
|
|
106927
|
-
"
|
|
107424
|
+
"div",
|
|
106928
107425
|
{
|
|
106929
|
-
|
|
106930
|
-
|
|
106931
|
-
|
|
106932
|
-
children: t2("common.close")
|
|
107426
|
+
className: "w-5 h-5 rounded-full flex items-center justify-center text-[8px] font-semibold text-white shrink-0",
|
|
107427
|
+
style: { backgroundColor: user.userColor },
|
|
107428
|
+
children: user.userName.slice(0, 2).toUpperCase()
|
|
106933
107429
|
}
|
|
106934
107430
|
),
|
|
106935
|
-
/* @__PURE__ */ jsx(
|
|
106936
|
-
|
|
106937
|
-
|
|
106938
|
-
|
|
106939
|
-
|
|
106940
|
-
|
|
106941
|
-
|
|
106942
|
-
|
|
106943
|
-
|
|
106944
|
-
|
|
106945
|
-
|
|
107431
|
+
/* @__PURE__ */ jsx("span", { className: "text-[12px] text-foreground truncate", children: user.userName }),
|
|
107432
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground ml-auto", children: [
|
|
107433
|
+
"Slide ",
|
|
107434
|
+
user.activeSlideIndex + 1
|
|
107435
|
+
] })
|
|
107436
|
+
] }, user.clientId)) })
|
|
107437
|
+
] }),
|
|
107438
|
+
/* @__PURE__ */ jsx(
|
|
107439
|
+
"button",
|
|
107440
|
+
{
|
|
107441
|
+
type: "button",
|
|
107442
|
+
onClick: onStopBroadcast,
|
|
107443
|
+
className: "w-full px-3 py-2 rounded border border-red-500/30 bg-red-500/10 hover:bg-red-500/20 text-[12px] text-red-400 font-medium transition-colors",
|
|
107444
|
+
children: t2("pptx.broadcast.stopBroadcast")
|
|
107445
|
+
}
|
|
107446
|
+
)
|
|
106946
107447
|
] });
|
|
106947
107448
|
}
|
|
106948
107449
|
function getInitials(name) {
|
|
@@ -108526,7 +109027,8 @@ function useDrawingOverlay({
|
|
|
108526
109027
|
drawingWidth,
|
|
108527
109028
|
isDrawingRef,
|
|
108528
109029
|
onAddInkElement,
|
|
108529
|
-
onAddFreeformShape
|
|
109030
|
+
onAddFreeformShape,
|
|
109031
|
+
onEraseInkElement
|
|
108530
109032
|
}) {
|
|
108531
109033
|
const isDrawing = activeTool !== "select";
|
|
108532
109034
|
const [currentStrokePoints, setCurrentStrokePoints] = useState(
|
|
@@ -108575,6 +109077,7 @@ function useDrawingOverlay({
|
|
|
108575
109077
|
continue;
|
|
108576
109078
|
}
|
|
108577
109079
|
if (pt2.x >= el.x - HIT_RADIUS && pt2.x <= el.x + el.width + HIT_RADIUS && pt2.y >= el.y - HIT_RADIUS && pt2.y <= el.y + el.height + HIT_RADIUS) {
|
|
109080
|
+
onEraseInkElement?.(el.id);
|
|
108578
109081
|
break;
|
|
108579
109082
|
}
|
|
108580
109083
|
}
|
|
@@ -108593,7 +109096,7 @@ function useDrawingOverlay({
|
|
|
108593
109096
|
isDrawingRef.current = true;
|
|
108594
109097
|
}
|
|
108595
109098
|
},
|
|
108596
|
-
[activeTool, activeSlide, pointerToCanvasCoords, isDrawingRef]
|
|
109099
|
+
[activeTool, activeSlide, pointerToCanvasCoords, isDrawingRef, onEraseInkElement]
|
|
108597
109100
|
);
|
|
108598
109101
|
const handleDrawPointerMove = useCallback(
|
|
108599
109102
|
(e2) => {
|
|
@@ -108663,6 +109166,9 @@ function useDrawingOverlay({
|
|
|
108663
109166
|
i3 === 0 ? { type: "moveTo", pt: scaledPt } : { type: "lineTo", pt: scaledPt }
|
|
108664
109167
|
);
|
|
108665
109168
|
}
|
|
109169
|
+
if (segments.length > 2) {
|
|
109170
|
+
segments.push({ type: "close" });
|
|
109171
|
+
}
|
|
108666
109172
|
const freeformShape = {
|
|
108667
109173
|
id: `shape-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
108668
109174
|
type: "shape",
|
|
@@ -108672,7 +109178,7 @@ function useDrawingOverlay({
|
|
|
108672
109178
|
height: h2,
|
|
108673
109179
|
shapeType: "custom",
|
|
108674
109180
|
shapeStyle: {
|
|
108675
|
-
fillColor:
|
|
109181
|
+
fillColor: "transparent",
|
|
108676
109182
|
strokeColor: drawingColor,
|
|
108677
109183
|
strokeWidth: drawingWidth
|
|
108678
109184
|
},
|
|
@@ -108822,6 +109328,7 @@ function SlideCanvas({
|
|
|
108822
109328
|
isDrawingRef,
|
|
108823
109329
|
onAddInkElement,
|
|
108824
109330
|
onAddFreeformShape,
|
|
109331
|
+
onEraseInkElement,
|
|
108825
109332
|
onActionClick,
|
|
108826
109333
|
onHyperlinkClick,
|
|
108827
109334
|
comments,
|
|
@@ -108907,7 +109414,8 @@ function SlideCanvas({
|
|
|
108907
109414
|
drawingWidth,
|
|
108908
109415
|
isDrawingRef,
|
|
108909
109416
|
onAddInkElement,
|
|
108910
|
-
onAddFreeformShape
|
|
109417
|
+
onAddFreeformShape,
|
|
109418
|
+
onEraseInkElement
|
|
108911
109419
|
});
|
|
108912
109420
|
const rulerOffset = showRulers ? RULER_THICKNESS : 0;
|
|
108913
109421
|
return /* @__PURE__ */ jsx(
|
|
@@ -109403,6 +109911,10 @@ function ViewerToolbarSection(props) {
|
|
|
109403
109911
|
onSetMode,
|
|
109404
109912
|
onToggleSidebar: () => s.setIsSlidesPaneOpen((p3) => !p3),
|
|
109405
109913
|
onToggleInspector: () => s.setIsInspectorPaneOpen((p3) => !p3),
|
|
109914
|
+
onOpenAnimationPanel: () => {
|
|
109915
|
+
s.setIsInspectorPaneOpen(true);
|
|
109916
|
+
s.setSidebarPanelMode("properties");
|
|
109917
|
+
},
|
|
109406
109918
|
onToggleCompactToolbar: () => s.setIsCompactToolbarOpen((p3) => !p3),
|
|
109407
109919
|
onSetToolbarSection: s.setToolbarSection,
|
|
109408
109920
|
onZoomIn: zoom.handleZoomIn,
|
|
@@ -111074,13 +111586,6 @@ function ViewerDialogGroup(props) {
|
|
|
111074
111586
|
slideCount: slides.length
|
|
111075
111587
|
}
|
|
111076
111588
|
),
|
|
111077
|
-
/* @__PURE__ */ jsx(
|
|
111078
|
-
BroadcastDialog,
|
|
111079
|
-
{
|
|
111080
|
-
open: dialogs.isBroadcastDialogOpen,
|
|
111081
|
-
onClose: () => dialogs.setIsBroadcastDialogOpen(false)
|
|
111082
|
-
}
|
|
111083
|
-
),
|
|
111084
111589
|
/* @__PURE__ */ jsx(
|
|
111085
111590
|
PrintDialog,
|
|
111086
111591
|
{
|
|
@@ -111323,6 +111828,7 @@ function ViewerCanvasArea(props) {
|
|
|
111323
111828
|
isDrawingRef: s.isDrawingRef,
|
|
111324
111829
|
onAddInkElement: insertHandlers.handleAddInkElement,
|
|
111325
111830
|
onAddFreeformShape: insertHandlers.handleAddFreeformShape,
|
|
111831
|
+
onEraseInkElement: insertHandlers.handleEraseInkElement,
|
|
111326
111832
|
onActionClick: handleActionClick,
|
|
111327
111833
|
onHyperlinkClick: handleHyperlinkClick,
|
|
111328
111834
|
allSlides: mode === "present" ? slides : void 0,
|
|
@@ -111330,6 +111836,24 @@ function ViewerCanvasArea(props) {
|
|
|
111330
111836
|
sourceSlideIndex: mode === "present" ? activeSlideIndex : void 0,
|
|
111331
111837
|
fieldContext,
|
|
111332
111838
|
tableStyleContext,
|
|
111839
|
+
collaborationOverlay: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
111840
|
+
/* @__PURE__ */ jsx(
|
|
111841
|
+
RemoteSelectionOverlay,
|
|
111842
|
+
{
|
|
111843
|
+
elements: effectiveSlide?.elements ?? [],
|
|
111844
|
+
activeSlideIndex
|
|
111845
|
+
}
|
|
111846
|
+
),
|
|
111847
|
+
/* @__PURE__ */ jsx(
|
|
111848
|
+
CollaborationCursorOverlay,
|
|
111849
|
+
{
|
|
111850
|
+
activeSlideIndex,
|
|
111851
|
+
canvasWidth: canvasSize.width,
|
|
111852
|
+
canvasHeight: canvasSize.height,
|
|
111853
|
+
selectedElementId: s.selectedElementId
|
|
111854
|
+
}
|
|
111855
|
+
)
|
|
111856
|
+
] }),
|
|
111333
111857
|
comments: activeSlide?.comments,
|
|
111334
111858
|
showCommentMarkers: s.sidebarPanelMode === "comments",
|
|
111335
111859
|
onCommentMarkerClick: () => s.setSidebarPanelMode("comments"),
|
|
@@ -112911,6 +113435,37 @@ function useYjsDocumentSync({
|
|
|
112911
113435
|
};
|
|
112912
113436
|
}, [doc2, isConnected, getDocMap, setSlides]);
|
|
112913
113437
|
}
|
|
113438
|
+
function useBroadcastFollower({
|
|
113439
|
+
collab,
|
|
113440
|
+
activeSlideIndex,
|
|
113441
|
+
setActiveSlideIndex,
|
|
113442
|
+
slideCount
|
|
113443
|
+
}) {
|
|
113444
|
+
const lastBroadcasterSlide = useRef(-1);
|
|
113445
|
+
useEffect(() => {
|
|
113446
|
+
if (!collab) {
|
|
113447
|
+
return;
|
|
113448
|
+
}
|
|
113449
|
+
if (collab.config.role !== "viewer") {
|
|
113450
|
+
return;
|
|
113451
|
+
}
|
|
113452
|
+
const broadcaster = collab.remoteUsers.find((u2) => u2.role === "broadcaster");
|
|
113453
|
+
if (!broadcaster) {
|
|
113454
|
+
return;
|
|
113455
|
+
}
|
|
113456
|
+
const targetSlide = broadcaster.activeSlideIndex;
|
|
113457
|
+
if (targetSlide < 0 || targetSlide >= slideCount) {
|
|
113458
|
+
return;
|
|
113459
|
+
}
|
|
113460
|
+
if (targetSlide === lastBroadcasterSlide.current) {
|
|
113461
|
+
return;
|
|
113462
|
+
}
|
|
113463
|
+
lastBroadcasterSlide.current = targetSlide;
|
|
113464
|
+
if (targetSlide !== activeSlideIndex) {
|
|
113465
|
+
setActiveSlideIndex(targetSlide);
|
|
113466
|
+
}
|
|
113467
|
+
}, [collab, activeSlideIndex, setActiveSlideIndex, slideCount]);
|
|
113468
|
+
}
|
|
112914
113469
|
function computeGridSpacingPx(presentationGridSpacing) {
|
|
112915
113470
|
if (presentationGridSpacing) {
|
|
112916
113471
|
const px2 = Math.round(presentationGridSpacing.cx / EMU_PER_PX);
|
|
@@ -115251,6 +115806,17 @@ function useInsertElements(input) {
|
|
|
115251
115806
|
}
|
|
115252
115807
|
addElement(shape);
|
|
115253
115808
|
};
|
|
115809
|
+
const handleEraseInkElement = (elementId) => {
|
|
115810
|
+
if (!activeSlide) {
|
|
115811
|
+
return;
|
|
115812
|
+
}
|
|
115813
|
+
ops.updateSlides(
|
|
115814
|
+
(prev) => prev.map(
|
|
115815
|
+
(s, i3) => i3 === activeSlideIndex ? { ...s, elements: s.elements.filter((el) => el.id !== elementId) } : s
|
|
115816
|
+
)
|
|
115817
|
+
);
|
|
115818
|
+
history.markDirty();
|
|
115819
|
+
};
|
|
115254
115820
|
return {
|
|
115255
115821
|
handleAddTextBox,
|
|
115256
115822
|
handleAddShape,
|
|
@@ -115258,6 +115824,7 @@ function useInsertElements(input) {
|
|
|
115258
115824
|
...structured,
|
|
115259
115825
|
handleAddInkElement,
|
|
115260
115826
|
handleAddFreeformShape,
|
|
115827
|
+
handleEraseInkElement,
|
|
115261
115828
|
...fileHandlers
|
|
115262
115829
|
};
|
|
115263
115830
|
}
|
|
@@ -116087,7 +116654,8 @@ function useEditorOperations(input) {
|
|
|
116087
116654
|
selectedElementIds,
|
|
116088
116655
|
canvasSize,
|
|
116089
116656
|
dialogs,
|
|
116090
|
-
presentation
|
|
116657
|
+
presentation,
|
|
116658
|
+
userName
|
|
116091
116659
|
} = input;
|
|
116092
116660
|
const ops = useElementOperations({
|
|
116093
116661
|
activeSlide,
|
|
@@ -116121,6 +116689,7 @@ function useEditorOperations(input) {
|
|
|
116121
116689
|
const comments = useComments({
|
|
116122
116690
|
slides,
|
|
116123
116691
|
canEdit,
|
|
116692
|
+
userName,
|
|
116124
116693
|
selectedElementId: state2.selectedElementId,
|
|
116125
116694
|
onUpdateSlides: ops.updateSlides,
|
|
116126
116695
|
onMarkDirty: history.markDirty
|
|
@@ -122867,6 +123436,7 @@ var PowerPointViewer = forwardRef(
|
|
|
122867
123436
|
onDirtyChange,
|
|
122868
123437
|
onActiveSlideChange,
|
|
122869
123438
|
theme,
|
|
123439
|
+
authorName,
|
|
122870
123440
|
collaboration,
|
|
122871
123441
|
onStartCollaboration,
|
|
122872
123442
|
onStopCollaboration,
|
|
@@ -123024,7 +123594,8 @@ var PowerPointViewer = forwardRef(
|
|
|
123024
123594
|
selectedElementIds,
|
|
123025
123595
|
canvasSize,
|
|
123026
123596
|
dialogs,
|
|
123027
|
-
presentation
|
|
123597
|
+
presentation,
|
|
123598
|
+
userName: authorName ?? collaboration?.userName
|
|
123028
123599
|
});
|
|
123029
123600
|
const {
|
|
123030
123601
|
exportHandlers,
|
|
@@ -123227,6 +123798,19 @@ var PowerPointViewer = forwardRef(
|
|
|
123227
123798
|
defaultServerUrl: shareDefaults?.serverUrl
|
|
123228
123799
|
}
|
|
123229
123800
|
),
|
|
123801
|
+
/* @__PURE__ */ jsx(
|
|
123802
|
+
BroadcastDialog,
|
|
123803
|
+
{
|
|
123804
|
+
open: dialogs.isBroadcastDialogOpen,
|
|
123805
|
+
onClose: () => dialogs.setIsBroadcastDialogOpen(false),
|
|
123806
|
+
onStartBroadcast: onStartCollaboration,
|
|
123807
|
+
onStopBroadcast: onStopCollaboration,
|
|
123808
|
+
onStartPresenting: () => handleSetMode("present"),
|
|
123809
|
+
defaultRoomId: shareDefaults?.roomId,
|
|
123810
|
+
defaultUserName: shareDefaults?.userName,
|
|
123811
|
+
defaultServerUrl: shareDefaults?.serverUrl
|
|
123812
|
+
}
|
|
123813
|
+
),
|
|
123230
123814
|
/* @__PURE__ */ jsx(
|
|
123231
123815
|
ViewerOverlays,
|
|
123232
123816
|
{
|
|
@@ -123276,6 +123860,14 @@ var PowerPointViewer = forwardRef(
|
|
|
123276
123860
|
canvasHeight: canvasSize.height,
|
|
123277
123861
|
children: [
|
|
123278
123862
|
/* @__PURE__ */ jsx(CollaborationDocumentSync, { slides, setSlides: state2.setSlides }),
|
|
123863
|
+
/* @__PURE__ */ jsx(
|
|
123864
|
+
BroadcastFollowerSync,
|
|
123865
|
+
{
|
|
123866
|
+
activeSlideIndex,
|
|
123867
|
+
setActiveSlideIndex: state2.setActiveSlideIndex,
|
|
123868
|
+
slideCount: slides.length
|
|
123869
|
+
}
|
|
123870
|
+
),
|
|
123279
123871
|
viewerContent
|
|
123280
123872
|
]
|
|
123281
123873
|
}
|
|
@@ -123303,6 +123895,20 @@ function CollaborationDocumentSync({
|
|
|
123303
123895
|
});
|
|
123304
123896
|
return null;
|
|
123305
123897
|
}
|
|
123898
|
+
function BroadcastFollowerSync({
|
|
123899
|
+
activeSlideIndex,
|
|
123900
|
+
setActiveSlideIndex,
|
|
123901
|
+
slideCount
|
|
123902
|
+
}) {
|
|
123903
|
+
const collab = useCollaboration();
|
|
123904
|
+
useBroadcastFollower({
|
|
123905
|
+
collab,
|
|
123906
|
+
activeSlideIndex,
|
|
123907
|
+
setActiveSlideIndex,
|
|
123908
|
+
slideCount
|
|
123909
|
+
});
|
|
123910
|
+
return null;
|
|
123911
|
+
}
|
|
123306
123912
|
/*! Bundled license information:
|
|
123307
123913
|
|
|
123308
123914
|
three/build/three.core.js:
|