pptx-react-viewer 1.0.11 → 1.0.12
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.js
CHANGED
|
@@ -43328,7 +43328,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43328
43328
|
return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
|
|
43329
43329
|
}
|
|
43330
43330
|
function useSyncExternalStore$2(subscribe3, getSnapshot2) {
|
|
43331
|
-
didWarnOld18Alpha || void 0 ===
|
|
43331
|
+
didWarnOld18Alpha || void 0 === React96.startTransition || (didWarnOld18Alpha = true, console.error(
|
|
43332
43332
|
"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."
|
|
43333
43333
|
));
|
|
43334
43334
|
var value = getSnapshot2();
|
|
@@ -43338,7 +43338,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43338
43338
|
"The result of getSnapshot should be cached to avoid an infinite loop"
|
|
43339
43339
|
), didWarnUncachedGetSnapshot = true);
|
|
43340
43340
|
}
|
|
43341
|
-
cachedValue =
|
|
43341
|
+
cachedValue = useState85({
|
|
43342
43342
|
inst: { value, getSnapshot: getSnapshot2 }
|
|
43343
43343
|
});
|
|
43344
43344
|
var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
|
|
@@ -43350,7 +43350,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43350
43350
|
},
|
|
43351
43351
|
[subscribe3, value, getSnapshot2]
|
|
43352
43352
|
);
|
|
43353
|
-
|
|
43353
|
+
useEffect71(
|
|
43354
43354
|
function() {
|
|
43355
43355
|
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
|
|
43356
43356
|
return subscribe3(function() {
|
|
@@ -43376,8 +43376,8 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43376
43376
|
return getSnapshot2();
|
|
43377
43377
|
}
|
|
43378
43378
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
43379
|
-
var
|
|
43380
|
-
exports$1.useSyncExternalStore = void 0 !==
|
|
43379
|
+
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;
|
|
43380
|
+
exports$1.useSyncExternalStore = void 0 !== React96.useSyncExternalStore ? React96.useSyncExternalStore : shim;
|
|
43381
43381
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
|
|
43382
43382
|
})();
|
|
43383
43383
|
}
|
|
@@ -43400,9 +43400,9 @@ var require_with_selector_development = __commonJS({
|
|
|
43400
43400
|
return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
|
|
43401
43401
|
}
|
|
43402
43402
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
43403
|
-
var
|
|
43403
|
+
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;
|
|
43404
43404
|
exports$1.useSyncExternalStoreWithSelector = function(subscribe3, getSnapshot2, getServerSnapshot2, selector, isEqual) {
|
|
43405
|
-
var instRef =
|
|
43405
|
+
var instRef = useRef72(null);
|
|
43406
43406
|
if (null === instRef.current) {
|
|
43407
43407
|
var inst = { hasValue: false, value: null };
|
|
43408
43408
|
instRef.current = inst;
|
|
@@ -43443,7 +43443,7 @@ var require_with_selector_development = __commonJS({
|
|
|
43443
43443
|
[getSnapshot2, getServerSnapshot2, selector, isEqual]
|
|
43444
43444
|
);
|
|
43445
43445
|
var value = useSyncExternalStore3(subscribe3, instRef[0], instRef[1]);
|
|
43446
|
-
|
|
43446
|
+
useEffect71(
|
|
43447
43447
|
function() {
|
|
43448
43448
|
inst.hasValue = true;
|
|
43449
43449
|
inst.value = value;
|
|
@@ -91128,6 +91128,542 @@ function useVirtualizedSlides({
|
|
|
91128
91128
|
scrollToIndex
|
|
91129
91129
|
};
|
|
91130
91130
|
}
|
|
91131
|
+
|
|
91132
|
+
// src/viewer/hooks/collaboration/sanitize.ts
|
|
91133
|
+
var ROOM_ID_REGEX = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
91134
|
+
function validateRoomId(roomId) {
|
|
91135
|
+
if (!ROOM_ID_REGEX.test(roomId)) {
|
|
91136
|
+
throw new Error(
|
|
91137
|
+
`Invalid collaboration room ID: "${roomId}". Must be 1-128 alphanumeric characters, hyphens, or underscores.`
|
|
91138
|
+
);
|
|
91139
|
+
}
|
|
91140
|
+
return roomId;
|
|
91141
|
+
}
|
|
91142
|
+
function sanitizeUserName(name) {
|
|
91143
|
+
if (typeof name !== "string") {
|
|
91144
|
+
return "Anonymous";
|
|
91145
|
+
}
|
|
91146
|
+
const stripped = name.replace(/<[^>]*>/g, "");
|
|
91147
|
+
const trimmed = stripped.trim().slice(0, 64);
|
|
91148
|
+
return trimmed || "Anonymous";
|
|
91149
|
+
}
|
|
91150
|
+
function clampCursorPosition(value, min2, max2) {
|
|
91151
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
91152
|
+
return 0;
|
|
91153
|
+
}
|
|
91154
|
+
const margin = 20;
|
|
91155
|
+
return Math.max(min2 - margin, Math.min(max2 + margin, value));
|
|
91156
|
+
}
|
|
91157
|
+
var HEX_COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
|
|
91158
|
+
function sanitizeColor(color, fallback = "#6366f1") {
|
|
91159
|
+
if (typeof color !== "string") {
|
|
91160
|
+
return fallback;
|
|
91161
|
+
}
|
|
91162
|
+
return HEX_COLOR_REGEX.test(color) ? color : fallback;
|
|
91163
|
+
}
|
|
91164
|
+
function sanitizeAvatarUrl(url) {
|
|
91165
|
+
if (typeof url !== "string") {
|
|
91166
|
+
return void 0;
|
|
91167
|
+
}
|
|
91168
|
+
try {
|
|
91169
|
+
const parsed = new URL(url);
|
|
91170
|
+
if (parsed.protocol === "https:" || parsed.protocol === "http:" || parsed.protocol === "data:") {
|
|
91171
|
+
return url;
|
|
91172
|
+
}
|
|
91173
|
+
} catch {
|
|
91174
|
+
}
|
|
91175
|
+
return void 0;
|
|
91176
|
+
}
|
|
91177
|
+
function sanitizeSlideIndex(value) {
|
|
91178
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
91179
|
+
return 0;
|
|
91180
|
+
}
|
|
91181
|
+
return Math.max(0, Math.floor(value));
|
|
91182
|
+
}
|
|
91183
|
+
function sanitizePresence(raw, canvasWidth, canvasHeight) {
|
|
91184
|
+
if (typeof raw.clientId !== "number") {
|
|
91185
|
+
return null;
|
|
91186
|
+
}
|
|
91187
|
+
return {
|
|
91188
|
+
clientId: raw.clientId,
|
|
91189
|
+
userName: sanitizeUserName(raw.userName),
|
|
91190
|
+
userAvatar: sanitizeAvatarUrl(raw.userAvatar),
|
|
91191
|
+
userColor: sanitizeColor(raw.userColor),
|
|
91192
|
+
activeSlideIndex: sanitizeSlideIndex(raw.activeSlideIndex),
|
|
91193
|
+
cursorX: clampCursorPosition(raw.cursorX, 0, canvasWidth),
|
|
91194
|
+
cursorY: clampCursorPosition(raw.cursorY, 0, canvasHeight),
|
|
91195
|
+
lastUpdated: typeof raw.lastUpdated === "string" ? raw.lastUpdated : (/* @__PURE__ */ new Date()).toISOString(),
|
|
91196
|
+
selectedElementId: typeof raw.selectedElementId === "string" ? raw.selectedElementId.slice(0, 128) : void 0,
|
|
91197
|
+
role: raw.role === "broadcaster" || raw.role === "viewer" || raw.role === "collaborator" ? raw.role : void 0
|
|
91198
|
+
};
|
|
91199
|
+
}
|
|
91200
|
+
var BROADCAST_THROTTLE_MS = 50;
|
|
91201
|
+
var STALE_PRESENCE_MS = 3e4;
|
|
91202
|
+
function usePresenceTracking({
|
|
91203
|
+
awareness,
|
|
91204
|
+
localClientId,
|
|
91205
|
+
userName,
|
|
91206
|
+
userColor,
|
|
91207
|
+
userAvatar,
|
|
91208
|
+
role,
|
|
91209
|
+
canvasWidth,
|
|
91210
|
+
canvasHeight
|
|
91211
|
+
}) {
|
|
91212
|
+
const [remoteUsers, setRemoteUsers] = React10.useState([]);
|
|
91213
|
+
const lastBroadcastRef = React10.useRef(0);
|
|
91214
|
+
const pendingBroadcastRef = React10.useRef(null);
|
|
91215
|
+
const latestLocalState = React10.useRef({});
|
|
91216
|
+
const broadcastPresence = React10.useCallback(
|
|
91217
|
+
(update2) => {
|
|
91218
|
+
if (!awareness) {
|
|
91219
|
+
return;
|
|
91220
|
+
}
|
|
91221
|
+
Object.assign(latestLocalState.current, update2);
|
|
91222
|
+
const now = Date.now();
|
|
91223
|
+
const elapsed = now - lastBroadcastRef.current;
|
|
91224
|
+
const flush = () => {
|
|
91225
|
+
const state2 = {
|
|
91226
|
+
...latestLocalState.current,
|
|
91227
|
+
userName,
|
|
91228
|
+
userColor,
|
|
91229
|
+
userAvatar,
|
|
91230
|
+
role,
|
|
91231
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
91232
|
+
};
|
|
91233
|
+
awareness.setLocalStateField("presence", state2);
|
|
91234
|
+
lastBroadcastRef.current = Date.now();
|
|
91235
|
+
};
|
|
91236
|
+
if (elapsed >= BROADCAST_THROTTLE_MS) {
|
|
91237
|
+
if (pendingBroadcastRef.current) {
|
|
91238
|
+
clearTimeout(pendingBroadcastRef.current);
|
|
91239
|
+
pendingBroadcastRef.current = null;
|
|
91240
|
+
}
|
|
91241
|
+
flush();
|
|
91242
|
+
} else if (!pendingBroadcastRef.current) {
|
|
91243
|
+
pendingBroadcastRef.current = setTimeout(() => {
|
|
91244
|
+
pendingBroadcastRef.current = null;
|
|
91245
|
+
flush();
|
|
91246
|
+
}, BROADCAST_THROTTLE_MS - elapsed);
|
|
91247
|
+
}
|
|
91248
|
+
},
|
|
91249
|
+
[awareness, userName, userColor, userAvatar, role]
|
|
91250
|
+
);
|
|
91251
|
+
React10.useEffect(() => {
|
|
91252
|
+
if (!awareness) {
|
|
91253
|
+
return;
|
|
91254
|
+
}
|
|
91255
|
+
awareness.setLocalStateField("presence", {
|
|
91256
|
+
userName,
|
|
91257
|
+
userColor,
|
|
91258
|
+
userAvatar,
|
|
91259
|
+
role,
|
|
91260
|
+
activeSlideIndex: 0,
|
|
91261
|
+
cursorX: 0,
|
|
91262
|
+
cursorY: 0,
|
|
91263
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
91264
|
+
});
|
|
91265
|
+
}, [awareness, userName, userColor, userAvatar, role]);
|
|
91266
|
+
React10.useEffect(() => {
|
|
91267
|
+
if (!awareness || localClientId === null) {
|
|
91268
|
+
return;
|
|
91269
|
+
}
|
|
91270
|
+
const handleChange = () => {
|
|
91271
|
+
const now = Date.now();
|
|
91272
|
+
const states = awareness.getStates();
|
|
91273
|
+
const users = [];
|
|
91274
|
+
states.forEach((state2, cid) => {
|
|
91275
|
+
if (cid === localClientId) {
|
|
91276
|
+
return;
|
|
91277
|
+
}
|
|
91278
|
+
const raw = state2?.presence;
|
|
91279
|
+
if (!raw || typeof raw !== "object") {
|
|
91280
|
+
return;
|
|
91281
|
+
}
|
|
91282
|
+
const sanitized = sanitizePresence({ ...raw, clientId: cid }, canvasWidth, canvasHeight);
|
|
91283
|
+
if (!sanitized) {
|
|
91284
|
+
return;
|
|
91285
|
+
}
|
|
91286
|
+
const updatedAt = new Date(sanitized.lastUpdated).getTime();
|
|
91287
|
+
if (Number.isNaN(updatedAt) || now - updatedAt > STALE_PRESENCE_MS) {
|
|
91288
|
+
return;
|
|
91289
|
+
}
|
|
91290
|
+
users.push(sanitized);
|
|
91291
|
+
});
|
|
91292
|
+
setRemoteUsers(users);
|
|
91293
|
+
};
|
|
91294
|
+
awareness.on("change", handleChange);
|
|
91295
|
+
awareness.on("update", handleChange);
|
|
91296
|
+
handleChange();
|
|
91297
|
+
return () => {
|
|
91298
|
+
awareness.off("change", handleChange);
|
|
91299
|
+
awareness.off("update", handleChange);
|
|
91300
|
+
};
|
|
91301
|
+
}, [awareness, localClientId, canvasWidth, canvasHeight]);
|
|
91302
|
+
React10.useEffect(() => {
|
|
91303
|
+
if (!awareness) {
|
|
91304
|
+
return;
|
|
91305
|
+
}
|
|
91306
|
+
const interval = setInterval(() => {
|
|
91307
|
+
awareness.setLocalStateField("presence", {
|
|
91308
|
+
...latestLocalState.current,
|
|
91309
|
+
userName,
|
|
91310
|
+
userColor,
|
|
91311
|
+
userAvatar,
|
|
91312
|
+
role,
|
|
91313
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
91314
|
+
});
|
|
91315
|
+
}, 1e4);
|
|
91316
|
+
return () => clearInterval(interval);
|
|
91317
|
+
}, [awareness, userName, userColor, userAvatar, role]);
|
|
91318
|
+
React10.useEffect(() => {
|
|
91319
|
+
return () => {
|
|
91320
|
+
if (pendingBroadcastRef.current) {
|
|
91321
|
+
clearTimeout(pendingBroadcastRef.current);
|
|
91322
|
+
}
|
|
91323
|
+
};
|
|
91324
|
+
}, []);
|
|
91325
|
+
return { remoteUsers, broadcastPresence };
|
|
91326
|
+
}
|
|
91327
|
+
function useYjsProvider({ config }) {
|
|
91328
|
+
const [status, setStatus] = React10.useState("disconnected");
|
|
91329
|
+
const [awareness, setAwareness] = React10.useState(null);
|
|
91330
|
+
const [doc2, setDoc] = React10.useState(null);
|
|
91331
|
+
const [clientId, setClientId] = React10.useState(null);
|
|
91332
|
+
const cleanupRef = React10.useRef(null);
|
|
91333
|
+
const init = React10.useCallback(async () => {
|
|
91334
|
+
const roomId = validateRoomId(config.roomId);
|
|
91335
|
+
setStatus("connecting");
|
|
91336
|
+
try {
|
|
91337
|
+
const [Y, { WebsocketProvider: WebsocketProvider2 }] = await Promise.all([Promise.resolve().then(() => (init_yjs(), yjs_exports)), Promise.resolve().then(() => (init_y_websocket(), y_websocket_exports))]);
|
|
91338
|
+
const yDoc = new Y.Doc();
|
|
91339
|
+
const provider = new WebsocketProvider2(
|
|
91340
|
+
config.serverUrl,
|
|
91341
|
+
roomId,
|
|
91342
|
+
yDoc,
|
|
91343
|
+
// eslint-disable-line @typescript-eslint/no-explicit-any
|
|
91344
|
+
{
|
|
91345
|
+
params: config.authToken ? { token: config.authToken } : void 0
|
|
91346
|
+
}
|
|
91347
|
+
);
|
|
91348
|
+
const handleStatus = (event) => {
|
|
91349
|
+
if (event.status === "connected") {
|
|
91350
|
+
setStatus("connected");
|
|
91351
|
+
} else if (event.status === "disconnected") {
|
|
91352
|
+
setStatus("disconnected");
|
|
91353
|
+
}
|
|
91354
|
+
};
|
|
91355
|
+
provider.on("status", handleStatus);
|
|
91356
|
+
if (provider.wsconnected) {
|
|
91357
|
+
setStatus("connected");
|
|
91358
|
+
}
|
|
91359
|
+
setDoc(yDoc);
|
|
91360
|
+
setAwareness(provider.awareness);
|
|
91361
|
+
setClientId(provider.awareness.clientID);
|
|
91362
|
+
cleanupRef.current = () => {
|
|
91363
|
+
provider.off("status", handleStatus);
|
|
91364
|
+
provider.destroy();
|
|
91365
|
+
yDoc.destroy();
|
|
91366
|
+
setDoc(null);
|
|
91367
|
+
setAwareness(null);
|
|
91368
|
+
setClientId(null);
|
|
91369
|
+
setStatus("disconnected");
|
|
91370
|
+
};
|
|
91371
|
+
} catch (err) {
|
|
91372
|
+
console.warn(
|
|
91373
|
+
"[pptx-viewer] Collaboration packages not available:",
|
|
91374
|
+
err instanceof Error ? err.message : err
|
|
91375
|
+
);
|
|
91376
|
+
setStatus("error");
|
|
91377
|
+
}
|
|
91378
|
+
}, [config.roomId, config.serverUrl, config.authToken]);
|
|
91379
|
+
React10.useEffect(() => {
|
|
91380
|
+
init();
|
|
91381
|
+
return () => {
|
|
91382
|
+
cleanupRef.current?.();
|
|
91383
|
+
cleanupRef.current = null;
|
|
91384
|
+
};
|
|
91385
|
+
}, [init]);
|
|
91386
|
+
return { status, awareness, doc: doc2, clientId };
|
|
91387
|
+
}
|
|
91388
|
+
|
|
91389
|
+
// src/viewer/hooks/collaboration/useCollaborativeState.ts
|
|
91390
|
+
function useCollaborativeState({
|
|
91391
|
+
config,
|
|
91392
|
+
canvasWidth,
|
|
91393
|
+
canvasHeight
|
|
91394
|
+
}) {
|
|
91395
|
+
const userColor = sanitizeColor(config.userColor, "#6366f1");
|
|
91396
|
+
const { status, awareness, doc: doc2, clientId } = useYjsProvider({ config });
|
|
91397
|
+
const { remoteUsers, broadcastPresence } = usePresenceTracking({
|
|
91398
|
+
awareness,
|
|
91399
|
+
localClientId: clientId,
|
|
91400
|
+
userName: config.userName,
|
|
91401
|
+
userColor,
|
|
91402
|
+
userAvatar: config.userAvatar,
|
|
91403
|
+
role: config.role,
|
|
91404
|
+
canvasWidth,
|
|
91405
|
+
canvasHeight
|
|
91406
|
+
});
|
|
91407
|
+
const connectedCount = status === "connected" ? remoteUsers.length + 1 : remoteUsers.length;
|
|
91408
|
+
return {
|
|
91409
|
+
status,
|
|
91410
|
+
remoteUsers,
|
|
91411
|
+
broadcastPresence,
|
|
91412
|
+
connectedCount,
|
|
91413
|
+
config,
|
|
91414
|
+
doc: doc2
|
|
91415
|
+
};
|
|
91416
|
+
}
|
|
91417
|
+
var CollaborationContext = React10.createContext(null);
|
|
91418
|
+
function useCollaboration() {
|
|
91419
|
+
return React10.useContext(CollaborationContext);
|
|
91420
|
+
}
|
|
91421
|
+
function CollaborationProvider({
|
|
91422
|
+
config,
|
|
91423
|
+
canvasWidth,
|
|
91424
|
+
canvasHeight,
|
|
91425
|
+
children
|
|
91426
|
+
}) {
|
|
91427
|
+
const value = useCollaborativeState({
|
|
91428
|
+
config,
|
|
91429
|
+
canvasWidth,
|
|
91430
|
+
canvasHeight
|
|
91431
|
+
});
|
|
91432
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CollaborationContext.Provider, { value, children });
|
|
91433
|
+
}
|
|
91434
|
+
function RemoteUserCursors({
|
|
91435
|
+
remoteUsers,
|
|
91436
|
+
activeSlideIndex,
|
|
91437
|
+
canvasWidth,
|
|
91438
|
+
canvasHeight
|
|
91439
|
+
}) {
|
|
91440
|
+
const visibleUsers = remoteUsers.filter((u2) => u2.activeSlideIndex === activeSlideIndex);
|
|
91441
|
+
if (visibleUsers.length === 0) {
|
|
91442
|
+
return null;
|
|
91443
|
+
}
|
|
91444
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
91445
|
+
"svg",
|
|
91446
|
+
{
|
|
91447
|
+
"data-testid": "remote-user-cursors",
|
|
91448
|
+
"data-export-ignore": "true",
|
|
91449
|
+
className: "absolute inset-0 pointer-events-none",
|
|
91450
|
+
style: { zIndex: 9999 },
|
|
91451
|
+
width: canvasWidth,
|
|
91452
|
+
height: canvasHeight,
|
|
91453
|
+
viewBox: `0 0 ${canvasWidth} ${canvasHeight}`,
|
|
91454
|
+
"aria-hidden": "true",
|
|
91455
|
+
children: visibleUsers.map((user) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
91456
|
+
"g",
|
|
91457
|
+
{
|
|
91458
|
+
transform: `translate(${user.cursorX}, ${user.cursorY})`,
|
|
91459
|
+
"data-testid": `remote-cursor-${user.clientId}`,
|
|
91460
|
+
children: [
|
|
91461
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
91462
|
+
"path",
|
|
91463
|
+
{
|
|
91464
|
+
d: "M0 0 L0 16 L4.5 12.5 L8 20 L10.5 19 L7 11.5 L12 11 Z",
|
|
91465
|
+
fill: user.userColor,
|
|
91466
|
+
stroke: "#fff",
|
|
91467
|
+
strokeWidth: 1,
|
|
91468
|
+
opacity: 0.9
|
|
91469
|
+
}
|
|
91470
|
+
),
|
|
91471
|
+
/* @__PURE__ */ jsxRuntime.jsxs("g", { transform: "translate(14, 18)", children: [
|
|
91472
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
91473
|
+
"rect",
|
|
91474
|
+
{
|
|
91475
|
+
rx: 3,
|
|
91476
|
+
ry: 3,
|
|
91477
|
+
x: -2,
|
|
91478
|
+
y: -10,
|
|
91479
|
+
width: Math.min(user.userName.length * 7 + 8, 150),
|
|
91480
|
+
height: 16,
|
|
91481
|
+
fill: user.userColor,
|
|
91482
|
+
opacity: 0.85
|
|
91483
|
+
}
|
|
91484
|
+
),
|
|
91485
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
91486
|
+
"text",
|
|
91487
|
+
{
|
|
91488
|
+
fill: "#fff",
|
|
91489
|
+
fontSize: 10,
|
|
91490
|
+
fontFamily: "system-ui, sans-serif",
|
|
91491
|
+
fontWeight: 500,
|
|
91492
|
+
dominantBaseline: "central",
|
|
91493
|
+
y: -2,
|
|
91494
|
+
x: 2,
|
|
91495
|
+
children: user.userName.length > 20 ? `${user.userName.slice(0, 18)}...` : user.userName
|
|
91496
|
+
}
|
|
91497
|
+
)
|
|
91498
|
+
] })
|
|
91499
|
+
]
|
|
91500
|
+
},
|
|
91501
|
+
user.clientId
|
|
91502
|
+
))
|
|
91503
|
+
}
|
|
91504
|
+
);
|
|
91505
|
+
}
|
|
91506
|
+
var STATUS_STYLES = {
|
|
91507
|
+
connected: {
|
|
91508
|
+
dot: "bg-green-400",
|
|
91509
|
+
text: "text-green-400",
|
|
91510
|
+
label: "Connected"
|
|
91511
|
+
},
|
|
91512
|
+
connecting: {
|
|
91513
|
+
dot: "bg-yellow-400 animate-pulse",
|
|
91514
|
+
text: "text-yellow-400",
|
|
91515
|
+
label: "Connecting..."
|
|
91516
|
+
},
|
|
91517
|
+
disconnected: {
|
|
91518
|
+
dot: "bg-gray-500",
|
|
91519
|
+
text: "text-gray-500",
|
|
91520
|
+
label: "Disconnected"
|
|
91521
|
+
},
|
|
91522
|
+
error: {
|
|
91523
|
+
dot: "bg-red-400",
|
|
91524
|
+
text: "text-red-400",
|
|
91525
|
+
label: "Connection error"
|
|
91526
|
+
}
|
|
91527
|
+
};
|
|
91528
|
+
function CollaborationStatusIndicator({
|
|
91529
|
+
status,
|
|
91530
|
+
connectedCount
|
|
91531
|
+
}) {
|
|
91532
|
+
const { t: t2 } = reactI18next.useTranslation();
|
|
91533
|
+
const style = STATUS_STYLES[status];
|
|
91534
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
91535
|
+
"div",
|
|
91536
|
+
{
|
|
91537
|
+
"data-testid": "collaboration-status",
|
|
91538
|
+
className: "flex items-center gap-1.5",
|
|
91539
|
+
"aria-label": t2("pptx.collaboration.statusAriaLabel", {
|
|
91540
|
+
status: t2(`pptx.collaboration.status.${status}`),
|
|
91541
|
+
count: connectedCount
|
|
91542
|
+
}),
|
|
91543
|
+
children: [
|
|
91544
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-block w-2 h-2 rounded-full ${style.dot}`, "aria-hidden": "true" }),
|
|
91545
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-[10px] ${style.text}`, children: status === "connected" ? t2("pptx.collaboration.userCount", { count: connectedCount }) : t2(`pptx.collaboration.status.${status}`) })
|
|
91546
|
+
]
|
|
91547
|
+
}
|
|
91548
|
+
);
|
|
91549
|
+
}
|
|
91550
|
+
function CollaborationCursorOverlay({
|
|
91551
|
+
activeSlideIndex,
|
|
91552
|
+
canvasWidth,
|
|
91553
|
+
canvasHeight,
|
|
91554
|
+
selectedElementId
|
|
91555
|
+
}) {
|
|
91556
|
+
const collab = useCollaboration();
|
|
91557
|
+
const containerRef = React10.useRef(null);
|
|
91558
|
+
const prevSelectionRef = React10.useRef(selectedElementId);
|
|
91559
|
+
React10.useEffect(() => {
|
|
91560
|
+
if (!collab || selectedElementId === prevSelectionRef.current) {
|
|
91561
|
+
return;
|
|
91562
|
+
}
|
|
91563
|
+
prevSelectionRef.current = selectedElementId;
|
|
91564
|
+
collab.broadcastPresence({
|
|
91565
|
+
selectedElementId: selectedElementId ?? void 0,
|
|
91566
|
+
activeSlideIndex
|
|
91567
|
+
});
|
|
91568
|
+
}, [collab, selectedElementId, activeSlideIndex]);
|
|
91569
|
+
React10.useEffect(() => {
|
|
91570
|
+
if (!collab) {
|
|
91571
|
+
return;
|
|
91572
|
+
}
|
|
91573
|
+
const parent = containerRef.current?.parentElement;
|
|
91574
|
+
if (!parent) {
|
|
91575
|
+
return;
|
|
91576
|
+
}
|
|
91577
|
+
const handler = (e2) => {
|
|
91578
|
+
const rect = parent.getBoundingClientRect();
|
|
91579
|
+
const x2 = (e2.clientX - rect.left) / rect.width * canvasWidth;
|
|
91580
|
+
const y = (e2.clientY - rect.top) / rect.height * canvasHeight;
|
|
91581
|
+
collab.broadcastPresence({
|
|
91582
|
+
cursorX: x2,
|
|
91583
|
+
cursorY: y,
|
|
91584
|
+
activeSlideIndex
|
|
91585
|
+
});
|
|
91586
|
+
};
|
|
91587
|
+
parent.addEventListener("pointermove", handler);
|
|
91588
|
+
return () => parent.removeEventListener("pointermove", handler);
|
|
91589
|
+
}, [collab, canvasWidth, canvasHeight, activeSlideIndex]);
|
|
91590
|
+
if (!collab) {
|
|
91591
|
+
return null;
|
|
91592
|
+
}
|
|
91593
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
91594
|
+
"div",
|
|
91595
|
+
{
|
|
91596
|
+
ref: containerRef,
|
|
91597
|
+
"data-testid": "collab-pointer-tracker",
|
|
91598
|
+
"data-export-ignore": "true",
|
|
91599
|
+
style: { display: "contents" },
|
|
91600
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
91601
|
+
RemoteUserCursors,
|
|
91602
|
+
{
|
|
91603
|
+
remoteUsers: collab.remoteUsers,
|
|
91604
|
+
activeSlideIndex,
|
|
91605
|
+
canvasWidth,
|
|
91606
|
+
canvasHeight
|
|
91607
|
+
}
|
|
91608
|
+
)
|
|
91609
|
+
}
|
|
91610
|
+
);
|
|
91611
|
+
}
|
|
91612
|
+
function RemoteSelectionOverlay({
|
|
91613
|
+
elements,
|
|
91614
|
+
activeSlideIndex
|
|
91615
|
+
}) {
|
|
91616
|
+
const collab = useCollaboration();
|
|
91617
|
+
if (!collab) {
|
|
91618
|
+
return null;
|
|
91619
|
+
}
|
|
91620
|
+
const elementMap = /* @__PURE__ */ new Map();
|
|
91621
|
+
for (const el of elements) {
|
|
91622
|
+
elementMap.set(el.id, el);
|
|
91623
|
+
}
|
|
91624
|
+
const selections = [];
|
|
91625
|
+
for (const user of collab.remoteUsers) {
|
|
91626
|
+
if (user.activeSlideIndex === activeSlideIndex && user.selectedElementId) {
|
|
91627
|
+
const el = elementMap.get(user.selectedElementId);
|
|
91628
|
+
if (el) {
|
|
91629
|
+
selections.push({
|
|
91630
|
+
userName: user.userName,
|
|
91631
|
+
userColor: user.userColor,
|
|
91632
|
+
element: el
|
|
91633
|
+
});
|
|
91634
|
+
}
|
|
91635
|
+
}
|
|
91636
|
+
}
|
|
91637
|
+
if (selections.length === 0) {
|
|
91638
|
+
return null;
|
|
91639
|
+
}
|
|
91640
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: selections.map((sel) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
91641
|
+
"div",
|
|
91642
|
+
{
|
|
91643
|
+
"data-testid": `remote-selection-${sel.element.id}`,
|
|
91644
|
+
"data-export-ignore": "true",
|
|
91645
|
+
className: "absolute pointer-events-none",
|
|
91646
|
+
style: {
|
|
91647
|
+
left: sel.element.x,
|
|
91648
|
+
top: sel.element.y,
|
|
91649
|
+
width: sel.element.width,
|
|
91650
|
+
height: sel.element.height,
|
|
91651
|
+
zIndex: 9997,
|
|
91652
|
+
border: `2px solid ${sel.userColor}`,
|
|
91653
|
+
borderRadius: 2
|
|
91654
|
+
},
|
|
91655
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
91656
|
+
"span",
|
|
91657
|
+
{
|
|
91658
|
+
className: "absolute -top-5 left-0 px-1 py-0.5 text-[9px] font-medium text-white rounded-sm whitespace-nowrap leading-none",
|
|
91659
|
+
style: { backgroundColor: sel.userColor },
|
|
91660
|
+
children: sel.userName
|
|
91661
|
+
}
|
|
91662
|
+
)
|
|
91663
|
+
},
|
|
91664
|
+
`remote-sel-${sel.element.id}`
|
|
91665
|
+
)) });
|
|
91666
|
+
}
|
|
91131
91667
|
function SectionContextMenu({
|
|
91132
91668
|
state: state2,
|
|
91133
91669
|
sectionGroups,
|
|
@@ -91409,6 +91945,7 @@ function SlideItemInner({
|
|
|
91409
91945
|
canvasSize,
|
|
91410
91946
|
canEdit,
|
|
91411
91947
|
rehearsalTimings,
|
|
91948
|
+
presenceUsers,
|
|
91412
91949
|
onSelectSlide,
|
|
91413
91950
|
onSlideContextMenu,
|
|
91414
91951
|
onAddSection,
|
|
@@ -91451,16 +91988,27 @@ function SlideItemInner({
|
|
|
91451
91988
|
onDragOver,
|
|
91452
91989
|
onDrop: (e2) => onDrop(e2, slideIndex),
|
|
91453
91990
|
children: [
|
|
91454
|
-
/* @__PURE__ */ jsxRuntime.
|
|
91455
|
-
|
|
91456
|
-
|
|
91457
|
-
|
|
91458
|
-
|
|
91459
|
-
|
|
91460
|
-
|
|
91461
|
-
|
|
91462
|
-
|
|
91463
|
-
|
|
91991
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-0.5 w-5 shrink-0", children: [
|
|
91992
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
91993
|
+
"span",
|
|
91994
|
+
{
|
|
91995
|
+
className: cn(
|
|
91996
|
+
"text-[10px] tabular-nums text-right select-none w-full",
|
|
91997
|
+
isActive ? "text-primary font-medium" : "text-muted-foreground"
|
|
91998
|
+
),
|
|
91999
|
+
children: slideIndex + 1
|
|
92000
|
+
}
|
|
92001
|
+
),
|
|
92002
|
+
presenceUsers && presenceUsers.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap justify-center gap-px", children: presenceUsers.slice(0, 4).map((u2, i3) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
92003
|
+
"span",
|
|
92004
|
+
{
|
|
92005
|
+
className: "w-[6px] h-[6px] rounded-full",
|
|
92006
|
+
style: { backgroundColor: u2.userColor },
|
|
92007
|
+
title: u2.userName
|
|
92008
|
+
},
|
|
92009
|
+
i3
|
|
92010
|
+
)) })
|
|
92011
|
+
] }),
|
|
91464
92012
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
91465
92013
|
"div",
|
|
91466
92014
|
{
|
|
@@ -91610,8 +92158,26 @@ function SlidesPaneSidebar({
|
|
|
91610
92158
|
panelWidth
|
|
91611
92159
|
}) {
|
|
91612
92160
|
const { t: t2 } = reactI18next.useTranslation();
|
|
92161
|
+
const collab = useCollaboration();
|
|
91613
92162
|
const slideRefs = React10.useRef(/* @__PURE__ */ new Map());
|
|
91614
92163
|
const renameInputRef = React10.useRef(null);
|
|
92164
|
+
const slidePresenceMap = React10.useMemo(() => {
|
|
92165
|
+
if (!collab || collab.remoteUsers.length === 0) {
|
|
92166
|
+
return void 0;
|
|
92167
|
+
}
|
|
92168
|
+
const map3 = /* @__PURE__ */ new Map();
|
|
92169
|
+
for (const user of collab.remoteUsers) {
|
|
92170
|
+
const idx = user.activeSlideIndex;
|
|
92171
|
+
const existing = map3.get(idx);
|
|
92172
|
+
const entry = { userName: user.userName, userColor: user.userColor };
|
|
92173
|
+
if (existing) {
|
|
92174
|
+
existing.push(entry);
|
|
92175
|
+
} else {
|
|
92176
|
+
map3.set(idx, [entry]);
|
|
92177
|
+
}
|
|
92178
|
+
}
|
|
92179
|
+
return map3;
|
|
92180
|
+
}, [collab]);
|
|
91615
92181
|
const estimatedItemHeight = React10.useMemo(
|
|
91616
92182
|
() => estimateSlideItemHeight(canvasSize.width, canvasSize.height),
|
|
91617
92183
|
[canvasSize.width, canvasSize.height]
|
|
@@ -91733,6 +92299,7 @@ function SlidesPaneSidebar({
|
|
|
91733
92299
|
canvasSize,
|
|
91734
92300
|
canEdit,
|
|
91735
92301
|
rehearsalTimings,
|
|
92302
|
+
presenceUsers: slidePresenceMap?.get(item.slideIndex),
|
|
91736
92303
|
onSelectSlide,
|
|
91737
92304
|
onSlideContextMenu,
|
|
91738
92305
|
onAddSection,
|
|
@@ -91786,6 +92353,7 @@ function SlidesPaneSidebar({
|
|
|
91786
92353
|
canvasSize,
|
|
91787
92354
|
canEdit,
|
|
91788
92355
|
rehearsalTimings,
|
|
92356
|
+
presenceUsers: slidePresenceMap?.get(idx),
|
|
91789
92357
|
onSelectSlide,
|
|
91790
92358
|
onSlideContextMenu,
|
|
91791
92359
|
onAddSection,
|
|
@@ -96552,16 +97120,31 @@ var ALIGN_BTNS = [
|
|
|
96552
97120
|
{ k: "bottom", el: /* @__PURE__ */ jsxRuntime.jsx(lu.LuChevronDown, { className: ic2 }) }
|
|
96553
97121
|
];
|
|
96554
97122
|
var DRAW_TOOLS = [
|
|
96555
|
-
{
|
|
96556
|
-
|
|
97123
|
+
{
|
|
97124
|
+
id: "select",
|
|
97125
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuMoveRight, { className: ic2 }),
|
|
97126
|
+
t: "Select",
|
|
97127
|
+
ac: "bg-primary text-primary-foreground"
|
|
97128
|
+
},
|
|
97129
|
+
{
|
|
97130
|
+
id: "pen",
|
|
97131
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuPencil, { className: ic2 }),
|
|
97132
|
+
t: "Pen",
|
|
97133
|
+
ac: "bg-primary text-primary-foreground"
|
|
97134
|
+
},
|
|
96557
97135
|
{
|
|
96558
97136
|
id: "highlighter",
|
|
96559
97137
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuType, { className: ic2 }),
|
|
96560
97138
|
t: "Highlighter",
|
|
96561
97139
|
ac: "bg-yellow-600 text-white"
|
|
96562
97140
|
},
|
|
96563
|
-
{ id: "eraser", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuMinus, { className: ic2 }), t: "Eraser" },
|
|
96564
|
-
{
|
|
97141
|
+
{ id: "eraser", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuMinus, { className: ic2 }), t: "Eraser", ac: "bg-red-600 text-white" },
|
|
97142
|
+
{
|
|
97143
|
+
id: "freeform",
|
|
97144
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuSpline, { className: ic2 }),
|
|
97145
|
+
t: "Freeform",
|
|
97146
|
+
ac: "bg-primary text-primary-foreground"
|
|
97147
|
+
}
|
|
96565
97148
|
];
|
|
96566
97149
|
var OV = [
|
|
96567
97150
|
{
|
|
@@ -96767,7 +97350,7 @@ function AnimationsSection(p3) {
|
|
|
96767
97350
|
"button",
|
|
96768
97351
|
{
|
|
96769
97352
|
type: "button",
|
|
96770
|
-
onClick: p3.onToggleInspector,
|
|
97353
|
+
onClick: p3.onOpenAnimationPanel ?? p3.onToggleInspector,
|
|
96771
97354
|
className: cn(
|
|
96772
97355
|
pill,
|
|
96773
97356
|
p3.isInspectorPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
|
|
@@ -98294,347 +98877,6 @@ function TextSection(p3) {
|
|
|
98294
98877
|
] })
|
|
98295
98878
|
] });
|
|
98296
98879
|
}
|
|
98297
|
-
|
|
98298
|
-
// src/viewer/hooks/collaboration/sanitize.ts
|
|
98299
|
-
var ROOM_ID_REGEX = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
98300
|
-
function validateRoomId(roomId) {
|
|
98301
|
-
if (!ROOM_ID_REGEX.test(roomId)) {
|
|
98302
|
-
throw new Error(
|
|
98303
|
-
`Invalid collaboration room ID: "${roomId}". Must be 1-128 alphanumeric characters, hyphens, or underscores.`
|
|
98304
|
-
);
|
|
98305
|
-
}
|
|
98306
|
-
return roomId;
|
|
98307
|
-
}
|
|
98308
|
-
function sanitizeUserName(name) {
|
|
98309
|
-
if (typeof name !== "string") {
|
|
98310
|
-
return "Anonymous";
|
|
98311
|
-
}
|
|
98312
|
-
const stripped = name.replace(/<[^>]*>/g, "");
|
|
98313
|
-
const trimmed = stripped.trim().slice(0, 64);
|
|
98314
|
-
return trimmed || "Anonymous";
|
|
98315
|
-
}
|
|
98316
|
-
function clampCursorPosition(value, min2, max2) {
|
|
98317
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
98318
|
-
return 0;
|
|
98319
|
-
}
|
|
98320
|
-
const margin = 20;
|
|
98321
|
-
return Math.max(min2 - margin, Math.min(max2 + margin, value));
|
|
98322
|
-
}
|
|
98323
|
-
var HEX_COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
|
|
98324
|
-
function sanitizeColor(color, fallback = "#6366f1") {
|
|
98325
|
-
if (typeof color !== "string") {
|
|
98326
|
-
return fallback;
|
|
98327
|
-
}
|
|
98328
|
-
return HEX_COLOR_REGEX.test(color) ? color : fallback;
|
|
98329
|
-
}
|
|
98330
|
-
function sanitizeAvatarUrl(url) {
|
|
98331
|
-
if (typeof url !== "string") {
|
|
98332
|
-
return void 0;
|
|
98333
|
-
}
|
|
98334
|
-
try {
|
|
98335
|
-
const parsed = new URL(url);
|
|
98336
|
-
if (parsed.protocol === "https:" || parsed.protocol === "http:" || parsed.protocol === "data:") {
|
|
98337
|
-
return url;
|
|
98338
|
-
}
|
|
98339
|
-
} catch {
|
|
98340
|
-
}
|
|
98341
|
-
return void 0;
|
|
98342
|
-
}
|
|
98343
|
-
function sanitizeSlideIndex(value) {
|
|
98344
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
98345
|
-
return 0;
|
|
98346
|
-
}
|
|
98347
|
-
return Math.max(0, Math.floor(value));
|
|
98348
|
-
}
|
|
98349
|
-
function sanitizePresence(raw, canvasWidth, canvasHeight) {
|
|
98350
|
-
if (typeof raw.clientId !== "number") {
|
|
98351
|
-
return null;
|
|
98352
|
-
}
|
|
98353
|
-
return {
|
|
98354
|
-
clientId: raw.clientId,
|
|
98355
|
-
userName: sanitizeUserName(raw.userName),
|
|
98356
|
-
userAvatar: sanitizeAvatarUrl(raw.userAvatar),
|
|
98357
|
-
userColor: sanitizeColor(raw.userColor),
|
|
98358
|
-
activeSlideIndex: sanitizeSlideIndex(raw.activeSlideIndex),
|
|
98359
|
-
cursorX: clampCursorPosition(raw.cursorX, 0, canvasWidth),
|
|
98360
|
-
cursorY: clampCursorPosition(raw.cursorY, 0, canvasHeight),
|
|
98361
|
-
lastUpdated: typeof raw.lastUpdated === "string" ? raw.lastUpdated : (/* @__PURE__ */ new Date()).toISOString(),
|
|
98362
|
-
selectedElementId: typeof raw.selectedElementId === "string" ? raw.selectedElementId.slice(0, 128) : void 0
|
|
98363
|
-
};
|
|
98364
|
-
}
|
|
98365
|
-
var BROADCAST_THROTTLE_MS = 50;
|
|
98366
|
-
var STALE_PRESENCE_MS = 3e4;
|
|
98367
|
-
function usePresenceTracking({
|
|
98368
|
-
awareness,
|
|
98369
|
-
localClientId,
|
|
98370
|
-
userName,
|
|
98371
|
-
userColor,
|
|
98372
|
-
userAvatar,
|
|
98373
|
-
canvasWidth,
|
|
98374
|
-
canvasHeight
|
|
98375
|
-
}) {
|
|
98376
|
-
const [remoteUsers, setRemoteUsers] = React10.useState([]);
|
|
98377
|
-
const lastBroadcastRef = React10.useRef(0);
|
|
98378
|
-
const pendingBroadcastRef = React10.useRef(null);
|
|
98379
|
-
const latestLocalState = React10.useRef({});
|
|
98380
|
-
const broadcastPresence = React10.useCallback(
|
|
98381
|
-
(update2) => {
|
|
98382
|
-
if (!awareness) {
|
|
98383
|
-
return;
|
|
98384
|
-
}
|
|
98385
|
-
Object.assign(latestLocalState.current, update2);
|
|
98386
|
-
const now = Date.now();
|
|
98387
|
-
const elapsed = now - lastBroadcastRef.current;
|
|
98388
|
-
const flush = () => {
|
|
98389
|
-
const state2 = {
|
|
98390
|
-
...latestLocalState.current,
|
|
98391
|
-
userName,
|
|
98392
|
-
userColor,
|
|
98393
|
-
userAvatar,
|
|
98394
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
98395
|
-
};
|
|
98396
|
-
awareness.setLocalStateField("presence", state2);
|
|
98397
|
-
lastBroadcastRef.current = Date.now();
|
|
98398
|
-
};
|
|
98399
|
-
if (elapsed >= BROADCAST_THROTTLE_MS) {
|
|
98400
|
-
if (pendingBroadcastRef.current) {
|
|
98401
|
-
clearTimeout(pendingBroadcastRef.current);
|
|
98402
|
-
pendingBroadcastRef.current = null;
|
|
98403
|
-
}
|
|
98404
|
-
flush();
|
|
98405
|
-
} else if (!pendingBroadcastRef.current) {
|
|
98406
|
-
pendingBroadcastRef.current = setTimeout(() => {
|
|
98407
|
-
pendingBroadcastRef.current = null;
|
|
98408
|
-
flush();
|
|
98409
|
-
}, BROADCAST_THROTTLE_MS - elapsed);
|
|
98410
|
-
}
|
|
98411
|
-
},
|
|
98412
|
-
[awareness, userName, userColor, userAvatar]
|
|
98413
|
-
);
|
|
98414
|
-
React10.useEffect(() => {
|
|
98415
|
-
if (!awareness) {
|
|
98416
|
-
return;
|
|
98417
|
-
}
|
|
98418
|
-
awareness.setLocalStateField("presence", {
|
|
98419
|
-
userName,
|
|
98420
|
-
userColor,
|
|
98421
|
-
userAvatar,
|
|
98422
|
-
activeSlideIndex: 0,
|
|
98423
|
-
cursorX: 0,
|
|
98424
|
-
cursorY: 0,
|
|
98425
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
98426
|
-
});
|
|
98427
|
-
}, [awareness, userName, userColor, userAvatar]);
|
|
98428
|
-
React10.useEffect(() => {
|
|
98429
|
-
if (!awareness || localClientId === null) {
|
|
98430
|
-
return;
|
|
98431
|
-
}
|
|
98432
|
-
const handleChange = () => {
|
|
98433
|
-
const now = Date.now();
|
|
98434
|
-
const states = awareness.getStates();
|
|
98435
|
-
const users = [];
|
|
98436
|
-
states.forEach((state2, cid) => {
|
|
98437
|
-
if (cid === localClientId) {
|
|
98438
|
-
return;
|
|
98439
|
-
}
|
|
98440
|
-
const raw = state2?.presence;
|
|
98441
|
-
if (!raw || typeof raw !== "object") {
|
|
98442
|
-
return;
|
|
98443
|
-
}
|
|
98444
|
-
const sanitized = sanitizePresence({ ...raw, clientId: cid }, canvasWidth, canvasHeight);
|
|
98445
|
-
if (!sanitized) {
|
|
98446
|
-
return;
|
|
98447
|
-
}
|
|
98448
|
-
const updatedAt = new Date(sanitized.lastUpdated).getTime();
|
|
98449
|
-
if (Number.isNaN(updatedAt) || now - updatedAt > STALE_PRESENCE_MS) {
|
|
98450
|
-
return;
|
|
98451
|
-
}
|
|
98452
|
-
users.push(sanitized);
|
|
98453
|
-
});
|
|
98454
|
-
setRemoteUsers(users);
|
|
98455
|
-
};
|
|
98456
|
-
awareness.on("change", handleChange);
|
|
98457
|
-
awareness.on("update", handleChange);
|
|
98458
|
-
handleChange();
|
|
98459
|
-
return () => {
|
|
98460
|
-
awareness.off("change", handleChange);
|
|
98461
|
-
awareness.off("update", handleChange);
|
|
98462
|
-
};
|
|
98463
|
-
}, [awareness, localClientId, canvasWidth, canvasHeight]);
|
|
98464
|
-
React10.useEffect(() => {
|
|
98465
|
-
if (!awareness) {
|
|
98466
|
-
return;
|
|
98467
|
-
}
|
|
98468
|
-
const interval = setInterval(() => {
|
|
98469
|
-
awareness.setLocalStateField("presence", {
|
|
98470
|
-
...latestLocalState.current,
|
|
98471
|
-
userName,
|
|
98472
|
-
userColor,
|
|
98473
|
-
userAvatar,
|
|
98474
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
98475
|
-
});
|
|
98476
|
-
}, 1e4);
|
|
98477
|
-
return () => clearInterval(interval);
|
|
98478
|
-
}, [awareness, userName, userColor, userAvatar]);
|
|
98479
|
-
React10.useEffect(() => {
|
|
98480
|
-
return () => {
|
|
98481
|
-
if (pendingBroadcastRef.current) {
|
|
98482
|
-
clearTimeout(pendingBroadcastRef.current);
|
|
98483
|
-
}
|
|
98484
|
-
};
|
|
98485
|
-
}, []);
|
|
98486
|
-
return { remoteUsers, broadcastPresence };
|
|
98487
|
-
}
|
|
98488
|
-
function useYjsProvider({ config }) {
|
|
98489
|
-
const [status, setStatus] = React10.useState("disconnected");
|
|
98490
|
-
const [awareness, setAwareness] = React10.useState(null);
|
|
98491
|
-
const [doc2, setDoc] = React10.useState(null);
|
|
98492
|
-
const [clientId, setClientId] = React10.useState(null);
|
|
98493
|
-
const cleanupRef = React10.useRef(null);
|
|
98494
|
-
const init = React10.useCallback(async () => {
|
|
98495
|
-
const roomId = validateRoomId(config.roomId);
|
|
98496
|
-
setStatus("connecting");
|
|
98497
|
-
try {
|
|
98498
|
-
const [Y, { WebsocketProvider: WebsocketProvider2 }] = await Promise.all([Promise.resolve().then(() => (init_yjs(), yjs_exports)), Promise.resolve().then(() => (init_y_websocket(), y_websocket_exports))]);
|
|
98499
|
-
const yDoc = new Y.Doc();
|
|
98500
|
-
const provider = new WebsocketProvider2(
|
|
98501
|
-
config.serverUrl,
|
|
98502
|
-
roomId,
|
|
98503
|
-
yDoc,
|
|
98504
|
-
// eslint-disable-line @typescript-eslint/no-explicit-any
|
|
98505
|
-
{
|
|
98506
|
-
params: config.authToken ? { token: config.authToken } : void 0
|
|
98507
|
-
}
|
|
98508
|
-
);
|
|
98509
|
-
const handleStatus = (event) => {
|
|
98510
|
-
if (event.status === "connected") {
|
|
98511
|
-
setStatus("connected");
|
|
98512
|
-
} else if (event.status === "disconnected") {
|
|
98513
|
-
setStatus("disconnected");
|
|
98514
|
-
}
|
|
98515
|
-
};
|
|
98516
|
-
provider.on("status", handleStatus);
|
|
98517
|
-
if (provider.wsconnected) {
|
|
98518
|
-
setStatus("connected");
|
|
98519
|
-
}
|
|
98520
|
-
setDoc(yDoc);
|
|
98521
|
-
setAwareness(provider.awareness);
|
|
98522
|
-
setClientId(provider.awareness.clientID);
|
|
98523
|
-
cleanupRef.current = () => {
|
|
98524
|
-
provider.off("status", handleStatus);
|
|
98525
|
-
provider.destroy();
|
|
98526
|
-
yDoc.destroy();
|
|
98527
|
-
setDoc(null);
|
|
98528
|
-
setAwareness(null);
|
|
98529
|
-
setClientId(null);
|
|
98530
|
-
setStatus("disconnected");
|
|
98531
|
-
};
|
|
98532
|
-
} catch (err) {
|
|
98533
|
-
console.warn(
|
|
98534
|
-
"[pptx-viewer] Collaboration packages not available:",
|
|
98535
|
-
err instanceof Error ? err.message : err
|
|
98536
|
-
);
|
|
98537
|
-
setStatus("error");
|
|
98538
|
-
}
|
|
98539
|
-
}, [config.roomId, config.serverUrl, config.authToken]);
|
|
98540
|
-
React10.useEffect(() => {
|
|
98541
|
-
init();
|
|
98542
|
-
return () => {
|
|
98543
|
-
cleanupRef.current?.();
|
|
98544
|
-
cleanupRef.current = null;
|
|
98545
|
-
};
|
|
98546
|
-
}, [init]);
|
|
98547
|
-
return { status, awareness, doc: doc2, clientId };
|
|
98548
|
-
}
|
|
98549
|
-
|
|
98550
|
-
// src/viewer/hooks/collaboration/useCollaborativeState.ts
|
|
98551
|
-
function useCollaborativeState({
|
|
98552
|
-
config,
|
|
98553
|
-
canvasWidth,
|
|
98554
|
-
canvasHeight
|
|
98555
|
-
}) {
|
|
98556
|
-
const userColor = sanitizeColor(config.userColor, "#6366f1");
|
|
98557
|
-
const { status, awareness, doc: doc2, clientId } = useYjsProvider({ config });
|
|
98558
|
-
const { remoteUsers, broadcastPresence } = usePresenceTracking({
|
|
98559
|
-
awareness,
|
|
98560
|
-
localClientId: clientId,
|
|
98561
|
-
userName: config.userName,
|
|
98562
|
-
userColor,
|
|
98563
|
-
userAvatar: config.userAvatar,
|
|
98564
|
-
canvasWidth,
|
|
98565
|
-
canvasHeight
|
|
98566
|
-
});
|
|
98567
|
-
const connectedCount = status === "connected" ? remoteUsers.length + 1 : remoteUsers.length;
|
|
98568
|
-
return {
|
|
98569
|
-
status,
|
|
98570
|
-
remoteUsers,
|
|
98571
|
-
broadcastPresence,
|
|
98572
|
-
connectedCount,
|
|
98573
|
-
config,
|
|
98574
|
-
doc: doc2
|
|
98575
|
-
};
|
|
98576
|
-
}
|
|
98577
|
-
var CollaborationContext = React10.createContext(null);
|
|
98578
|
-
function useCollaboration() {
|
|
98579
|
-
return React10.useContext(CollaborationContext);
|
|
98580
|
-
}
|
|
98581
|
-
function CollaborationProvider({
|
|
98582
|
-
config,
|
|
98583
|
-
canvasWidth,
|
|
98584
|
-
canvasHeight,
|
|
98585
|
-
children
|
|
98586
|
-
}) {
|
|
98587
|
-
const value = useCollaborativeState({
|
|
98588
|
-
config,
|
|
98589
|
-
canvasWidth,
|
|
98590
|
-
canvasHeight
|
|
98591
|
-
});
|
|
98592
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CollaborationContext.Provider, { value, children });
|
|
98593
|
-
}
|
|
98594
|
-
var STATUS_STYLES = {
|
|
98595
|
-
connected: {
|
|
98596
|
-
dot: "bg-green-400",
|
|
98597
|
-
text: "text-green-400",
|
|
98598
|
-
label: "Connected"
|
|
98599
|
-
},
|
|
98600
|
-
connecting: {
|
|
98601
|
-
dot: "bg-yellow-400 animate-pulse",
|
|
98602
|
-
text: "text-yellow-400",
|
|
98603
|
-
label: "Connecting..."
|
|
98604
|
-
},
|
|
98605
|
-
disconnected: {
|
|
98606
|
-
dot: "bg-gray-500",
|
|
98607
|
-
text: "text-gray-500",
|
|
98608
|
-
label: "Disconnected"
|
|
98609
|
-
},
|
|
98610
|
-
error: {
|
|
98611
|
-
dot: "bg-red-400",
|
|
98612
|
-
text: "text-red-400",
|
|
98613
|
-
label: "Connection error"
|
|
98614
|
-
}
|
|
98615
|
-
};
|
|
98616
|
-
function CollaborationStatusIndicator({
|
|
98617
|
-
status,
|
|
98618
|
-
connectedCount
|
|
98619
|
-
}) {
|
|
98620
|
-
const { t: t2 } = reactI18next.useTranslation();
|
|
98621
|
-
const style = STATUS_STYLES[status];
|
|
98622
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
98623
|
-
"div",
|
|
98624
|
-
{
|
|
98625
|
-
"data-testid": "collaboration-status",
|
|
98626
|
-
className: "flex items-center gap-1.5",
|
|
98627
|
-
"aria-label": t2("pptx.collaboration.statusAriaLabel", {
|
|
98628
|
-
status: t2(`pptx.collaboration.status.${status}`),
|
|
98629
|
-
count: connectedCount
|
|
98630
|
-
}),
|
|
98631
|
-
children: [
|
|
98632
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-block w-2 h-2 rounded-full ${style.dot}`, "aria-hidden": "true" }),
|
|
98633
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-[10px] ${style.text}`, children: status === "connected" ? t2("pptx.collaboration.userCount", { count: connectedCount }) : t2(`pptx.collaboration.status.${status}`) })
|
|
98634
|
-
]
|
|
98635
|
-
}
|
|
98636
|
-
);
|
|
98637
|
-
}
|
|
98638
98880
|
function CustomShowsControls({
|
|
98639
98881
|
customShows,
|
|
98640
98882
|
activeCustomShowId,
|
|
@@ -99073,29 +99315,38 @@ function ToolbarPrimaryRow(p3) {
|
|
|
99073
99315
|
]
|
|
99074
99316
|
}
|
|
99075
99317
|
),
|
|
99076
|
-
collab && (collab.status === "connected" || collab.status === "connecting") && collab.remoteUsers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
99077
|
-
|
|
99078
|
-
|
|
99079
|
-
|
|
99080
|
-
|
|
99081
|
-
|
|
99082
|
-
|
|
99083
|
-
|
|
99084
|
-
|
|
99318
|
+
collab && (collab.status === "connected" || collab.status === "connecting") && collab.remoteUsers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
99319
|
+
"button",
|
|
99320
|
+
{
|
|
99321
|
+
type: "button",
|
|
99322
|
+
onClick: p3.onOpenShareDialog,
|
|
99323
|
+
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",
|
|
99324
|
+
title: t2("pptx.toolbar.sharingUsers", { count: collab.connectedCount }),
|
|
99325
|
+
children: [
|
|
99326
|
+
collab.remoteUsers.slice(0, 4).map((user) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
99327
|
+
"div",
|
|
99085
99328
|
{
|
|
99086
|
-
|
|
99087
|
-
|
|
99088
|
-
|
|
99089
|
-
|
|
99090
|
-
|
|
99091
|
-
|
|
99092
|
-
|
|
99093
|
-
|
|
99094
|
-
|
|
99095
|
-
|
|
99096
|
-
|
|
99097
|
-
|
|
99098
|
-
|
|
99329
|
+
className: "w-6 h-6 rounded-full border-2 border-background flex items-center justify-center text-[8px] font-semibold text-white shrink-0",
|
|
99330
|
+
style: { backgroundColor: user.userColor },
|
|
99331
|
+
title: user.userName,
|
|
99332
|
+
children: user.userAvatar ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
99333
|
+
"img",
|
|
99334
|
+
{
|
|
99335
|
+
src: user.userAvatar,
|
|
99336
|
+
alt: user.userName,
|
|
99337
|
+
className: "w-full h-full rounded-full object-cover"
|
|
99338
|
+
}
|
|
99339
|
+
) : user.userName.slice(0, 2).toUpperCase()
|
|
99340
|
+
},
|
|
99341
|
+
user.clientId
|
|
99342
|
+
)),
|
|
99343
|
+
collab.remoteUsers.length > 4 && /* @__PURE__ */ jsxRuntime.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: [
|
|
99344
|
+
"+",
|
|
99345
|
+
collab.remoteUsers.length - 4
|
|
99346
|
+
] })
|
|
99347
|
+
]
|
|
99348
|
+
}
|
|
99349
|
+
),
|
|
99099
99350
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
99100
99351
|
ModeSwitcher,
|
|
99101
99352
|
{
|
|
@@ -99472,7 +99723,8 @@ function Toolbar(p3) {
|
|
|
99472
99723
|
canEdit: p3.canEdit,
|
|
99473
99724
|
selectedElement: p3.selectedElement,
|
|
99474
99725
|
isInspectorPaneOpen: p3.isInspectorPaneOpen,
|
|
99475
|
-
onToggleInspector: p3.onToggleInspector
|
|
99726
|
+
onToggleInspector: p3.onToggleInspector,
|
|
99727
|
+
onOpenAnimationPanel: p3.onOpenAnimationPanel
|
|
99476
99728
|
}
|
|
99477
99729
|
),
|
|
99478
99730
|
sSlw && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -106917,9 +107169,75 @@ function SetUpSlideShowDialog({
|
|
|
106917
107169
|
}
|
|
106918
107170
|
function BroadcastDialog({
|
|
106919
107171
|
open,
|
|
106920
|
-
onClose
|
|
107172
|
+
onClose,
|
|
107173
|
+
onStartBroadcast,
|
|
107174
|
+
onStopBroadcast,
|
|
107175
|
+
onStartPresenting,
|
|
107176
|
+
defaultRoomId,
|
|
107177
|
+
defaultUserName,
|
|
107178
|
+
defaultServerUrl
|
|
106921
107179
|
}) {
|
|
106922
107180
|
const { t: t2 } = reactI18next.useTranslation();
|
|
107181
|
+
const collab = useCollaboration();
|
|
107182
|
+
const isBroadcasting = collab !== null && collab.status !== "disconnected" && collab.status !== "error" && collab.config.role === "broadcaster";
|
|
107183
|
+
const [roomId, setRoomId] = React10.useState("");
|
|
107184
|
+
const [userName, setUserName] = React10.useState("");
|
|
107185
|
+
const [serverUrl, setServerUrl] = React10.useState("");
|
|
107186
|
+
const [copied, setCopied] = React10.useState(false);
|
|
107187
|
+
const dialogRef = React10.useRef(null);
|
|
107188
|
+
React10.useEffect(() => {
|
|
107189
|
+
if (open && !isBroadcasting) {
|
|
107190
|
+
const broadcastRoom = defaultRoomId ? `broadcast-${defaultRoomId}` : `broadcast-${Math.random().toString(36).slice(2, 10)}`;
|
|
107191
|
+
setRoomId(broadcastRoom);
|
|
107192
|
+
setUserName(defaultUserName ?? "");
|
|
107193
|
+
setServerUrl(defaultServerUrl ?? "ws://localhost:1234");
|
|
107194
|
+
}
|
|
107195
|
+
}, [open, isBroadcasting, defaultRoomId, defaultUserName, defaultServerUrl]);
|
|
107196
|
+
React10.useEffect(() => {
|
|
107197
|
+
if (!open) {
|
|
107198
|
+
return;
|
|
107199
|
+
}
|
|
107200
|
+
function handleKeyDown(e2) {
|
|
107201
|
+
if (e2.key === "Escape") {
|
|
107202
|
+
onClose();
|
|
107203
|
+
}
|
|
107204
|
+
}
|
|
107205
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
107206
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
107207
|
+
}, [open, onClose]);
|
|
107208
|
+
React10.useEffect(() => {
|
|
107209
|
+
if (open && dialogRef.current) {
|
|
107210
|
+
dialogRef.current.focus();
|
|
107211
|
+
}
|
|
107212
|
+
}, [open]);
|
|
107213
|
+
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;
|
|
107214
|
+
const handleCopyUrl = React10.useCallback(() => {
|
|
107215
|
+
void navigator.clipboard.writeText(broadcastUrl).then(() => {
|
|
107216
|
+
setCopied(true);
|
|
107217
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
107218
|
+
return void 0;
|
|
107219
|
+
});
|
|
107220
|
+
}, [broadcastUrl]);
|
|
107221
|
+
const handleStartBroadcast = React10.useCallback(() => {
|
|
107222
|
+
if (!roomId.trim() || !userName.trim()) {
|
|
107223
|
+
return;
|
|
107224
|
+
}
|
|
107225
|
+
onStartBroadcast?.({
|
|
107226
|
+
roomId: roomId.trim(),
|
|
107227
|
+
serverUrl: serverUrl.trim(),
|
|
107228
|
+
userName: userName.trim(),
|
|
107229
|
+
role: "broadcaster"
|
|
107230
|
+
});
|
|
107231
|
+
setTimeout(() => {
|
|
107232
|
+
onStartPresenting?.();
|
|
107233
|
+
}, 100);
|
|
107234
|
+
onClose();
|
|
107235
|
+
}, [roomId, userName, serverUrl, onStartBroadcast, onStartPresenting, onClose]);
|
|
107236
|
+
const handleStopBroadcast = React10.useCallback(() => {
|
|
107237
|
+
onStopBroadcast?.();
|
|
107238
|
+
onClose();
|
|
107239
|
+
}, [onStopBroadcast, onClose]);
|
|
107240
|
+
const canStart = roomId.trim().length > 0 && userName.trim().length > 0 && serverUrl.trim().length > 0;
|
|
106923
107241
|
if (!open) {
|
|
106924
107242
|
return null;
|
|
106925
107243
|
}
|
|
@@ -106933,42 +107251,225 @@ function BroadcastDialog({
|
|
|
106933
107251
|
onClick: onClose
|
|
106934
107252
|
}
|
|
106935
107253
|
),
|
|
106936
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-[201] flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
106937
|
-
|
|
106938
|
-
|
|
107254
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-[201] flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
107255
|
+
"div",
|
|
107256
|
+
{
|
|
107257
|
+
ref: dialogRef,
|
|
107258
|
+
role: "dialog",
|
|
107259
|
+
"aria-modal": "true",
|
|
107260
|
+
"aria-label": t2("pptx.broadcast.title"),
|
|
107261
|
+
tabIndex: -1,
|
|
107262
|
+
className: "pointer-events-auto w-full max-w-md rounded-xl border border-border bg-popover text-foreground shadow-2xl outline-none",
|
|
107263
|
+
children: [
|
|
107264
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-3 border-b border-border", children: [
|
|
107265
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-sm font-semibold text-foreground flex items-center gap-2", children: [
|
|
107266
|
+
/* @__PURE__ */ jsxRuntime.jsx(lu.LuCast, { className: "w-4 h-4" }),
|
|
107267
|
+
isBroadcasting ? t2("pptx.broadcast.broadcasting") : t2("pptx.broadcast.title")
|
|
107268
|
+
] }),
|
|
107269
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107270
|
+
"button",
|
|
107271
|
+
{
|
|
107272
|
+
type: "button",
|
|
107273
|
+
onClick: onClose,
|
|
107274
|
+
className: "text-muted-foreground hover:text-foreground text-lg leading-none",
|
|
107275
|
+
"aria-label": "Close",
|
|
107276
|
+
children: "\xD7"
|
|
107277
|
+
}
|
|
107278
|
+
)
|
|
107279
|
+
] }),
|
|
107280
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-4", children: isBroadcasting ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
107281
|
+
ActiveBroadcastView,
|
|
107282
|
+
{
|
|
107283
|
+
collab,
|
|
107284
|
+
broadcastUrl,
|
|
107285
|
+
copied,
|
|
107286
|
+
onCopyUrl: handleCopyUrl,
|
|
107287
|
+
onStopBroadcast: handleStopBroadcast
|
|
107288
|
+
}
|
|
107289
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
107290
|
+
StartBroadcastForm,
|
|
107291
|
+
{
|
|
107292
|
+
roomId,
|
|
107293
|
+
userName,
|
|
107294
|
+
serverUrl,
|
|
107295
|
+
onRoomIdChange: setRoomId,
|
|
107296
|
+
onUserNameChange: setUserName,
|
|
107297
|
+
onServerUrlChange: setServerUrl
|
|
107298
|
+
}
|
|
107299
|
+
) }),
|
|
107300
|
+
!isBroadcasting && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 px-5 py-3 border-t border-border", children: [
|
|
107301
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107302
|
+
"button",
|
|
107303
|
+
{
|
|
107304
|
+
type: "button",
|
|
107305
|
+
onClick: onClose,
|
|
107306
|
+
className: "px-3 py-1.5 rounded bg-muted hover:bg-accent text-[12px] text-foreground transition-colors",
|
|
107307
|
+
children: t2("common.close")
|
|
107308
|
+
}
|
|
107309
|
+
),
|
|
107310
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107311
|
+
"button",
|
|
107312
|
+
{
|
|
107313
|
+
type: "button",
|
|
107314
|
+
disabled: !canStart,
|
|
107315
|
+
onClick: handleStartBroadcast,
|
|
107316
|
+
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",
|
|
107317
|
+
children: t2("pptx.broadcast.startBroadcast")
|
|
107318
|
+
}
|
|
107319
|
+
)
|
|
107320
|
+
] })
|
|
107321
|
+
]
|
|
107322
|
+
}
|
|
107323
|
+
) })
|
|
107324
|
+
] });
|
|
107325
|
+
}
|
|
107326
|
+
function StartBroadcastForm({
|
|
107327
|
+
roomId,
|
|
107328
|
+
userName,
|
|
107329
|
+
serverUrl,
|
|
107330
|
+
onRoomIdChange,
|
|
107331
|
+
onUserNameChange,
|
|
107332
|
+
onServerUrlChange
|
|
107333
|
+
}) {
|
|
107334
|
+
const { t: t2 } = reactI18next.useTranslation();
|
|
107335
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
107336
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[13px] text-muted-foreground leading-relaxed", children: t2("pptx.broadcast.description") }),
|
|
107337
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
107338
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107339
|
+
"label",
|
|
107340
|
+
{
|
|
107341
|
+
htmlFor: "broadcast-room-id",
|
|
107342
|
+
className: "block text-[12px] font-medium text-foreground",
|
|
107343
|
+
children: t2("pptx.broadcast.sessionName")
|
|
107344
|
+
}
|
|
107345
|
+
),
|
|
107346
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107347
|
+
"input",
|
|
107348
|
+
{
|
|
107349
|
+
id: "broadcast-room-id",
|
|
107350
|
+
type: "text",
|
|
107351
|
+
value: roomId,
|
|
107352
|
+
onChange: (e2) => onRoomIdChange(e2.target.value),
|
|
107353
|
+
placeholder: "broadcast-abc123",
|
|
107354
|
+
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"
|
|
107355
|
+
}
|
|
107356
|
+
)
|
|
107357
|
+
] }),
|
|
107358
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
107359
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107360
|
+
"label",
|
|
107361
|
+
{
|
|
107362
|
+
htmlFor: "broadcast-user-name",
|
|
107363
|
+
className: "block text-[12px] font-medium text-foreground",
|
|
107364
|
+
children: t2("pptx.broadcast.displayName")
|
|
107365
|
+
}
|
|
107366
|
+
),
|
|
107367
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107368
|
+
"input",
|
|
107369
|
+
{
|
|
107370
|
+
id: "broadcast-user-name",
|
|
107371
|
+
type: "text",
|
|
107372
|
+
value: userName,
|
|
107373
|
+
onChange: (e2) => onUserNameChange(e2.target.value),
|
|
107374
|
+
placeholder: "Presenter",
|
|
107375
|
+
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"
|
|
107376
|
+
}
|
|
107377
|
+
)
|
|
107378
|
+
] }),
|
|
107379
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
107380
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107381
|
+
"label",
|
|
107382
|
+
{
|
|
107383
|
+
htmlFor: "broadcast-server-url",
|
|
107384
|
+
className: "block text-[12px] font-medium text-foreground",
|
|
107385
|
+
children: t2("pptx.broadcast.serverLabel")
|
|
107386
|
+
}
|
|
107387
|
+
),
|
|
107388
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107389
|
+
"input",
|
|
107390
|
+
{
|
|
107391
|
+
id: "broadcast-server-url",
|
|
107392
|
+
type: "text",
|
|
107393
|
+
value: serverUrl,
|
|
107394
|
+
onChange: (e2) => onServerUrlChange(e2.target.value),
|
|
107395
|
+
placeholder: "ws://localhost:1234",
|
|
107396
|
+
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"
|
|
107397
|
+
}
|
|
107398
|
+
)
|
|
107399
|
+
] }),
|
|
107400
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground/70 leading-relaxed", children: t2("pptx.broadcast.hint") })
|
|
107401
|
+
] });
|
|
107402
|
+
}
|
|
107403
|
+
function ActiveBroadcastView({
|
|
107404
|
+
collab,
|
|
107405
|
+
broadcastUrl,
|
|
107406
|
+
copied,
|
|
107407
|
+
onCopyUrl,
|
|
107408
|
+
onStopBroadcast
|
|
107409
|
+
}) {
|
|
107410
|
+
const { t: t2 } = reactI18next.useTranslation();
|
|
107411
|
+
const statusColor = collab.status === "connected" ? "text-green-400" : collab.status === "connecting" ? "text-yellow-400" : "text-red-400";
|
|
107412
|
+
const statusIcon = collab.status === "connected" || collab.status === "connecting" ? /* @__PURE__ */ jsxRuntime.jsx(lu.LuWifi, { className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lu.LuWifiOff, { className: "w-4 h-4" });
|
|
107413
|
+
const viewerCount = collab.remoteUsers.filter((u2) => u2.role === "viewer").length;
|
|
107414
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
107415
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
107416
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: statusColor, children: statusIcon }),
|
|
107417
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[13px] font-medium text-foreground capitalize", children: collab.status }),
|
|
107418
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[12px] text-muted-foreground ml-auto flex items-center gap-1", children: [
|
|
107419
|
+
/* @__PURE__ */ jsxRuntime.jsx(lu.LuUsers, { className: "w-3.5 h-3.5" }),
|
|
107420
|
+
t2("pptx.broadcast.viewerCount", { count: viewerCount })
|
|
107421
|
+
] })
|
|
107422
|
+
] }),
|
|
107423
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
107424
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-[12px] font-medium text-foreground", children: t2("pptx.broadcast.viewerLink") }),
|
|
107425
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
107426
|
+
/* @__PURE__ */ jsxRuntime.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 }),
|
|
106939
107427
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
106940
107428
|
"button",
|
|
106941
107429
|
{
|
|
106942
107430
|
type: "button",
|
|
106943
|
-
onClick:
|
|
106944
|
-
className: "
|
|
106945
|
-
|
|
106946
|
-
children:
|
|
107431
|
+
onClick: onCopyUrl,
|
|
107432
|
+
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",
|
|
107433
|
+
title: t2("pptx.broadcast.copyLink"),
|
|
107434
|
+
children: copied ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
107435
|
+
/* @__PURE__ */ jsxRuntime.jsx(lu.LuCheck, { className: "w-3.5 h-3.5 text-green-400" }),
|
|
107436
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t2("pptx.share.copied") })
|
|
107437
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
107438
|
+
/* @__PURE__ */ jsxRuntime.jsx(lu.LuCopy, { className: "w-3.5 h-3.5" }),
|
|
107439
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t2("pptx.share.copyUrl") })
|
|
107440
|
+
] })
|
|
106947
107441
|
}
|
|
106948
107442
|
)
|
|
106949
107443
|
] }),
|
|
106950
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
106951
|
-
|
|
107444
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground", children: t2("pptx.broadcast.shareHint") })
|
|
107445
|
+
] }),
|
|
107446
|
+
collab.remoteUsers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
107447
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-[12px] font-medium text-foreground", children: t2("pptx.broadcast.viewers") }),
|
|
107448
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-2", children: [
|
|
106952
107449
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
106953
|
-
"
|
|
107450
|
+
"div",
|
|
106954
107451
|
{
|
|
106955
|
-
|
|
106956
|
-
|
|
106957
|
-
|
|
106958
|
-
children: t2("common.close")
|
|
107452
|
+
className: "w-5 h-5 rounded-full flex items-center justify-center text-[8px] font-semibold text-white shrink-0",
|
|
107453
|
+
style: { backgroundColor: user.userColor },
|
|
107454
|
+
children: user.userName.slice(0, 2).toUpperCase()
|
|
106959
107455
|
}
|
|
106960
107456
|
),
|
|
106961
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
106962
|
-
|
|
106963
|
-
|
|
106964
|
-
|
|
106965
|
-
|
|
106966
|
-
|
|
106967
|
-
|
|
106968
|
-
|
|
106969
|
-
|
|
106970
|
-
|
|
106971
|
-
|
|
107457
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12px] text-foreground truncate", children: user.userName }),
|
|
107458
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-muted-foreground ml-auto", children: [
|
|
107459
|
+
"Slide ",
|
|
107460
|
+
user.activeSlideIndex + 1
|
|
107461
|
+
] })
|
|
107462
|
+
] }, user.clientId)) })
|
|
107463
|
+
] }),
|
|
107464
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107465
|
+
"button",
|
|
107466
|
+
{
|
|
107467
|
+
type: "button",
|
|
107468
|
+
onClick: onStopBroadcast,
|
|
107469
|
+
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",
|
|
107470
|
+
children: t2("pptx.broadcast.stopBroadcast")
|
|
107471
|
+
}
|
|
107472
|
+
)
|
|
106972
107473
|
] });
|
|
106973
107474
|
}
|
|
106974
107475
|
function getInitials(name) {
|
|
@@ -108552,7 +109053,8 @@ function useDrawingOverlay({
|
|
|
108552
109053
|
drawingWidth,
|
|
108553
109054
|
isDrawingRef,
|
|
108554
109055
|
onAddInkElement,
|
|
108555
|
-
onAddFreeformShape
|
|
109056
|
+
onAddFreeformShape,
|
|
109057
|
+
onEraseInkElement
|
|
108556
109058
|
}) {
|
|
108557
109059
|
const isDrawing = activeTool !== "select";
|
|
108558
109060
|
const [currentStrokePoints, setCurrentStrokePoints] = React10.useState(
|
|
@@ -108601,6 +109103,7 @@ function useDrawingOverlay({
|
|
|
108601
109103
|
continue;
|
|
108602
109104
|
}
|
|
108603
109105
|
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) {
|
|
109106
|
+
onEraseInkElement?.(el.id);
|
|
108604
109107
|
break;
|
|
108605
109108
|
}
|
|
108606
109109
|
}
|
|
@@ -108619,7 +109122,7 @@ function useDrawingOverlay({
|
|
|
108619
109122
|
isDrawingRef.current = true;
|
|
108620
109123
|
}
|
|
108621
109124
|
},
|
|
108622
|
-
[activeTool, activeSlide, pointerToCanvasCoords, isDrawingRef]
|
|
109125
|
+
[activeTool, activeSlide, pointerToCanvasCoords, isDrawingRef, onEraseInkElement]
|
|
108623
109126
|
);
|
|
108624
109127
|
const handleDrawPointerMove = React10.useCallback(
|
|
108625
109128
|
(e2) => {
|
|
@@ -108689,6 +109192,9 @@ function useDrawingOverlay({
|
|
|
108689
109192
|
i3 === 0 ? { type: "moveTo", pt: scaledPt } : { type: "lineTo", pt: scaledPt }
|
|
108690
109193
|
);
|
|
108691
109194
|
}
|
|
109195
|
+
if (segments.length > 2) {
|
|
109196
|
+
segments.push({ type: "close" });
|
|
109197
|
+
}
|
|
108692
109198
|
const freeformShape = {
|
|
108693
109199
|
id: `shape-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
108694
109200
|
type: "shape",
|
|
@@ -108698,7 +109204,7 @@ function useDrawingOverlay({
|
|
|
108698
109204
|
height: h2,
|
|
108699
109205
|
shapeType: "custom",
|
|
108700
109206
|
shapeStyle: {
|
|
108701
|
-
fillColor:
|
|
109207
|
+
fillColor: "transparent",
|
|
108702
109208
|
strokeColor: drawingColor,
|
|
108703
109209
|
strokeWidth: drawingWidth
|
|
108704
109210
|
},
|
|
@@ -108848,6 +109354,7 @@ function SlideCanvas({
|
|
|
108848
109354
|
isDrawingRef,
|
|
108849
109355
|
onAddInkElement,
|
|
108850
109356
|
onAddFreeformShape,
|
|
109357
|
+
onEraseInkElement,
|
|
108851
109358
|
onActionClick,
|
|
108852
109359
|
onHyperlinkClick,
|
|
108853
109360
|
comments,
|
|
@@ -108933,7 +109440,8 @@ function SlideCanvas({
|
|
|
108933
109440
|
drawingWidth,
|
|
108934
109441
|
isDrawingRef,
|
|
108935
109442
|
onAddInkElement,
|
|
108936
|
-
onAddFreeformShape
|
|
109443
|
+
onAddFreeformShape,
|
|
109444
|
+
onEraseInkElement
|
|
108937
109445
|
});
|
|
108938
109446
|
const rulerOffset = showRulers ? RULER_THICKNESS : 0;
|
|
108939
109447
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -109429,6 +109937,10 @@ function ViewerToolbarSection(props) {
|
|
|
109429
109937
|
onSetMode,
|
|
109430
109938
|
onToggleSidebar: () => s.setIsSlidesPaneOpen((p3) => !p3),
|
|
109431
109939
|
onToggleInspector: () => s.setIsInspectorPaneOpen((p3) => !p3),
|
|
109940
|
+
onOpenAnimationPanel: () => {
|
|
109941
|
+
s.setIsInspectorPaneOpen(true);
|
|
109942
|
+
s.setSidebarPanelMode("properties");
|
|
109943
|
+
},
|
|
109432
109944
|
onToggleCompactToolbar: () => s.setIsCompactToolbarOpen((p3) => !p3),
|
|
109433
109945
|
onSetToolbarSection: s.setToolbarSection,
|
|
109434
109946
|
onZoomIn: zoom.handleZoomIn,
|
|
@@ -111100,13 +111612,6 @@ function ViewerDialogGroup(props) {
|
|
|
111100
111612
|
slideCount: slides.length
|
|
111101
111613
|
}
|
|
111102
111614
|
),
|
|
111103
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
111104
|
-
BroadcastDialog,
|
|
111105
|
-
{
|
|
111106
|
-
open: dialogs.isBroadcastDialogOpen,
|
|
111107
|
-
onClose: () => dialogs.setIsBroadcastDialogOpen(false)
|
|
111108
|
-
}
|
|
111109
|
-
),
|
|
111110
111615
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
111111
111616
|
PrintDialog,
|
|
111112
111617
|
{
|
|
@@ -111349,6 +111854,7 @@ function ViewerCanvasArea(props) {
|
|
|
111349
111854
|
isDrawingRef: s.isDrawingRef,
|
|
111350
111855
|
onAddInkElement: insertHandlers.handleAddInkElement,
|
|
111351
111856
|
onAddFreeformShape: insertHandlers.handleAddFreeformShape,
|
|
111857
|
+
onEraseInkElement: insertHandlers.handleEraseInkElement,
|
|
111352
111858
|
onActionClick: handleActionClick,
|
|
111353
111859
|
onHyperlinkClick: handleHyperlinkClick,
|
|
111354
111860
|
allSlides: mode === "present" ? slides : void 0,
|
|
@@ -111356,6 +111862,24 @@ function ViewerCanvasArea(props) {
|
|
|
111356
111862
|
sourceSlideIndex: mode === "present" ? activeSlideIndex : void 0,
|
|
111357
111863
|
fieldContext,
|
|
111358
111864
|
tableStyleContext,
|
|
111865
|
+
collaborationOverlay: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
111866
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
111867
|
+
RemoteSelectionOverlay,
|
|
111868
|
+
{
|
|
111869
|
+
elements: effectiveSlide?.elements ?? [],
|
|
111870
|
+
activeSlideIndex
|
|
111871
|
+
}
|
|
111872
|
+
),
|
|
111873
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
111874
|
+
CollaborationCursorOverlay,
|
|
111875
|
+
{
|
|
111876
|
+
activeSlideIndex,
|
|
111877
|
+
canvasWidth: canvasSize.width,
|
|
111878
|
+
canvasHeight: canvasSize.height,
|
|
111879
|
+
selectedElementId: s.selectedElementId
|
|
111880
|
+
}
|
|
111881
|
+
)
|
|
111882
|
+
] }),
|
|
111359
111883
|
comments: activeSlide?.comments,
|
|
111360
111884
|
showCommentMarkers: s.sidebarPanelMode === "comments",
|
|
111361
111885
|
onCommentMarkerClick: () => s.setSidebarPanelMode("comments"),
|
|
@@ -112937,6 +113461,37 @@ function useYjsDocumentSync({
|
|
|
112937
113461
|
};
|
|
112938
113462
|
}, [doc2, isConnected, getDocMap, setSlides]);
|
|
112939
113463
|
}
|
|
113464
|
+
function useBroadcastFollower({
|
|
113465
|
+
collab,
|
|
113466
|
+
activeSlideIndex,
|
|
113467
|
+
setActiveSlideIndex,
|
|
113468
|
+
slideCount
|
|
113469
|
+
}) {
|
|
113470
|
+
const lastBroadcasterSlide = React10.useRef(-1);
|
|
113471
|
+
React10.useEffect(() => {
|
|
113472
|
+
if (!collab) {
|
|
113473
|
+
return;
|
|
113474
|
+
}
|
|
113475
|
+
if (collab.config.role !== "viewer") {
|
|
113476
|
+
return;
|
|
113477
|
+
}
|
|
113478
|
+
const broadcaster = collab.remoteUsers.find((u2) => u2.role === "broadcaster");
|
|
113479
|
+
if (!broadcaster) {
|
|
113480
|
+
return;
|
|
113481
|
+
}
|
|
113482
|
+
const targetSlide = broadcaster.activeSlideIndex;
|
|
113483
|
+
if (targetSlide < 0 || targetSlide >= slideCount) {
|
|
113484
|
+
return;
|
|
113485
|
+
}
|
|
113486
|
+
if (targetSlide === lastBroadcasterSlide.current) {
|
|
113487
|
+
return;
|
|
113488
|
+
}
|
|
113489
|
+
lastBroadcasterSlide.current = targetSlide;
|
|
113490
|
+
if (targetSlide !== activeSlideIndex) {
|
|
113491
|
+
setActiveSlideIndex(targetSlide);
|
|
113492
|
+
}
|
|
113493
|
+
}, [collab, activeSlideIndex, setActiveSlideIndex, slideCount]);
|
|
113494
|
+
}
|
|
112940
113495
|
function computeGridSpacingPx(presentationGridSpacing) {
|
|
112941
113496
|
if (presentationGridSpacing) {
|
|
112942
113497
|
const px2 = Math.round(presentationGridSpacing.cx / EMU_PER_PX);
|
|
@@ -115277,6 +115832,17 @@ function useInsertElements(input) {
|
|
|
115277
115832
|
}
|
|
115278
115833
|
addElement(shape);
|
|
115279
115834
|
};
|
|
115835
|
+
const handleEraseInkElement = (elementId) => {
|
|
115836
|
+
if (!activeSlide) {
|
|
115837
|
+
return;
|
|
115838
|
+
}
|
|
115839
|
+
ops.updateSlides(
|
|
115840
|
+
(prev) => prev.map(
|
|
115841
|
+
(s, i3) => i3 === activeSlideIndex ? { ...s, elements: s.elements.filter((el) => el.id !== elementId) } : s
|
|
115842
|
+
)
|
|
115843
|
+
);
|
|
115844
|
+
history.markDirty();
|
|
115845
|
+
};
|
|
115280
115846
|
return {
|
|
115281
115847
|
handleAddTextBox,
|
|
115282
115848
|
handleAddShape,
|
|
@@ -115284,6 +115850,7 @@ function useInsertElements(input) {
|
|
|
115284
115850
|
...structured,
|
|
115285
115851
|
handleAddInkElement,
|
|
115286
115852
|
handleAddFreeformShape,
|
|
115853
|
+
handleEraseInkElement,
|
|
115287
115854
|
...fileHandlers
|
|
115288
115855
|
};
|
|
115289
115856
|
}
|
|
@@ -116113,7 +116680,8 @@ function useEditorOperations(input) {
|
|
|
116113
116680
|
selectedElementIds,
|
|
116114
116681
|
canvasSize,
|
|
116115
116682
|
dialogs,
|
|
116116
|
-
presentation
|
|
116683
|
+
presentation,
|
|
116684
|
+
userName
|
|
116117
116685
|
} = input;
|
|
116118
116686
|
const ops = useElementOperations({
|
|
116119
116687
|
activeSlide,
|
|
@@ -116147,6 +116715,7 @@ function useEditorOperations(input) {
|
|
|
116147
116715
|
const comments = useComments({
|
|
116148
116716
|
slides,
|
|
116149
116717
|
canEdit,
|
|
116718
|
+
userName,
|
|
116150
116719
|
selectedElementId: state2.selectedElementId,
|
|
116151
116720
|
onUpdateSlides: ops.updateSlides,
|
|
116152
116721
|
onMarkDirty: history.markDirty
|
|
@@ -122893,6 +123462,7 @@ var PowerPointViewer = React10.forwardRef(
|
|
|
122893
123462
|
onDirtyChange,
|
|
122894
123463
|
onActiveSlideChange,
|
|
122895
123464
|
theme,
|
|
123465
|
+
authorName,
|
|
122896
123466
|
collaboration,
|
|
122897
123467
|
onStartCollaboration,
|
|
122898
123468
|
onStopCollaboration,
|
|
@@ -123050,7 +123620,8 @@ var PowerPointViewer = React10.forwardRef(
|
|
|
123050
123620
|
selectedElementIds,
|
|
123051
123621
|
canvasSize,
|
|
123052
123622
|
dialogs,
|
|
123053
|
-
presentation
|
|
123623
|
+
presentation,
|
|
123624
|
+
userName: authorName ?? collaboration?.userName
|
|
123054
123625
|
});
|
|
123055
123626
|
const {
|
|
123056
123627
|
exportHandlers,
|
|
@@ -123253,6 +123824,19 @@ var PowerPointViewer = React10.forwardRef(
|
|
|
123253
123824
|
defaultServerUrl: shareDefaults?.serverUrl
|
|
123254
123825
|
}
|
|
123255
123826
|
),
|
|
123827
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
123828
|
+
BroadcastDialog,
|
|
123829
|
+
{
|
|
123830
|
+
open: dialogs.isBroadcastDialogOpen,
|
|
123831
|
+
onClose: () => dialogs.setIsBroadcastDialogOpen(false),
|
|
123832
|
+
onStartBroadcast: onStartCollaboration,
|
|
123833
|
+
onStopBroadcast: onStopCollaboration,
|
|
123834
|
+
onStartPresenting: () => handleSetMode("present"),
|
|
123835
|
+
defaultRoomId: shareDefaults?.roomId,
|
|
123836
|
+
defaultUserName: shareDefaults?.userName,
|
|
123837
|
+
defaultServerUrl: shareDefaults?.serverUrl
|
|
123838
|
+
}
|
|
123839
|
+
),
|
|
123256
123840
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
123257
123841
|
ViewerOverlays,
|
|
123258
123842
|
{
|
|
@@ -123302,6 +123886,14 @@ var PowerPointViewer = React10.forwardRef(
|
|
|
123302
123886
|
canvasHeight: canvasSize.height,
|
|
123303
123887
|
children: [
|
|
123304
123888
|
/* @__PURE__ */ jsxRuntime.jsx(CollaborationDocumentSync, { slides, setSlides: state2.setSlides }),
|
|
123889
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
123890
|
+
BroadcastFollowerSync,
|
|
123891
|
+
{
|
|
123892
|
+
activeSlideIndex,
|
|
123893
|
+
setActiveSlideIndex: state2.setActiveSlideIndex,
|
|
123894
|
+
slideCount: slides.length
|
|
123895
|
+
}
|
|
123896
|
+
),
|
|
123305
123897
|
viewerContent
|
|
123306
123898
|
]
|
|
123307
123899
|
}
|
|
@@ -123329,6 +123921,20 @@ function CollaborationDocumentSync({
|
|
|
123329
123921
|
});
|
|
123330
123922
|
return null;
|
|
123331
123923
|
}
|
|
123924
|
+
function BroadcastFollowerSync({
|
|
123925
|
+
activeSlideIndex,
|
|
123926
|
+
setActiveSlideIndex,
|
|
123927
|
+
slideCount
|
|
123928
|
+
}) {
|
|
123929
|
+
const collab = useCollaboration();
|
|
123930
|
+
useBroadcastFollower({
|
|
123931
|
+
collab,
|
|
123932
|
+
activeSlideIndex,
|
|
123933
|
+
setActiveSlideIndex,
|
|
123934
|
+
slideCount
|
|
123935
|
+
});
|
|
123936
|
+
return null;
|
|
123937
|
+
}
|
|
123332
123938
|
/*! Bundled license information:
|
|
123333
123939
|
|
|
123334
123940
|
three/build/three.core.js:
|