@veltdev/react
Version:
Velt is an SDK to add collaborative features to your product within minutes. Example: Comments like Figma, Frame.io, Google docs or sheets, Recording like Loom, Huddles like Slack and much more.
674 lines (655 loc) • 858 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
var reactDom = require('react-dom');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
function __spreadArray(to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
}
var VeltContext = React.createContext({ client: null });
function useVeltClient() {
return React.useContext(VeltContext);
}
/**
* Loads the Velt script dynamically and calls the callback when ready.
* Returns a cleanup function to remove the event listener if component unmounts.
*
* ## Issue (Rapid Mount/Unmount with Slow Network)
*
* When VeltProvider is rapidly mounted/unmounted (e.g., conditional rendering,
* React Strict Mode, or route changes) while the Velt script is still loading
* over a slow network, multiple issues can occur:
*
* 1. First component mount creates the script tag and starts loading
* 2. Component unmounts before script loads (script tag remains in DOM)
* 3. Second component mount finds existing script tag
* 4. OLD BEHAVIOR: Immediately triggered callback assuming script was loaded
* 5. PROBLEM: Script wasn't actually loaded yet (still loading due to network delay)
* 6. This caused initVelt to run with window.Velt = undefined
*
* ## Fix
*
* 1. Check if window.Velt exists before triggering callback for existing scripts
* 2. If script tag exists but window.Velt doesn't, attach a new load event listener
* 3. Return a cleanup function that removes the event listener when component unmounts
* 4. This prevents orphaned callbacks from firing on destroyed component instances
*
* @returns Cleanup function to remove event listener (call on component unmount)
*/
var loadVelt = function (callback, version, staging, develop, proxyDomain, integrity, integrityValue) {
if (version === void 0) { version = 'latest'; }
if (staging === void 0) { staging = false; }
if (develop === void 0) { develop = false; }
var existingScript = document.getElementById('veltScript');
// Store reference to the handler so we can remove it on cleanup.
// This is essential for proper cleanup - we need the exact same function
// reference to remove the event listener later.
var loadHandler = null;
var scriptElement = null;
if (!existingScript) {
// No script tag exists - this is the first component to request Velt
var script = document.createElement('script');
if (staging) {
script.src = "https://us-central1-snipply-sdk-staging.cloudfunctions.net/getprivatenpmpackagefile?packageName=sdk-staging&packageVersion=".concat((!version || version === 'latest') ? '1.0.1' : version, "&filePath=velt.js&orgName=@veltdev");
}
else if (develop) {
script.src = "https://us-central1-snipply-sdk-staging.cloudfunctions.net/getprivatenpmpackagefile?packageName=sdk-dev&packageVersion=".concat((!version || version === 'latest') ? '1.0.1' : version, "&filePath=velt.js&orgName=@veltdev");
}
else {
if (proxyDomain) {
// remove trailing slash from proxy
if (proxyDomain[proxyDomain.length - 1] === '/') {
proxyDomain = proxyDomain.slice(0, -1);
}
script.src = "".concat(proxyDomain, "/lib/sdk@").concat(version, "/velt.js");
}
else {
script.src = "https://cdn.velt.dev/lib/sdk@".concat(version, "/velt.js");
}
}
script.id = 'veltScript';
script.type = 'module';
if (integrity && integrityValue) {
script.integrity = integrityValue;
script.crossOrigin = 'anonymous';
}
document.body.appendChild(script);
// Create handler and store reference for cleanup.
// We store the reference so we can remove this exact listener on cleanup.
loadHandler = function () {
if (callback) {
callback();
}
};
scriptElement = script;
script.addEventListener('load', loadHandler);
}
else {
// Script tag already exists in DOM (created by a previous component instance).
// We need to check if it's actually finished loading or still in progress.
if (window.Velt) {
// Script has finished loading - window.Velt is available.
// Trigger callback directly without attaching any event listener.
if (callback) {
callback();
}
}
else {
// IMPORTANT: Script tag exists but window.Velt is undefined.
// This means the script is still loading (slow network scenario).
//
// Previous bug: We used to trigger callback immediately here,
// which caused initVelt to run with window.Velt = undefined.
//
// Fix: Attach a load event listener to wait for the script to finish loading.
// Using addEventListener (not onload) to avoid overwriting existing handlers.
loadHandler = function () {
if (callback) {
callback();
}
};
scriptElement = existingScript;
existingScript.addEventListener('load', loadHandler);
}
}
// Return cleanup function to remove event listener when component unmounts.
// This prevents the callback from firing on destroyed component instances,
// which would cause React state updates on unmounted components.
return function () {
if (loadHandler && scriptElement) {
scriptElement.removeEventListener('load', loadHandler);
}
};
};
var VELT_SDK_VERSION = '5.0.2-beta.31';
var VELT_SDK_INIT_EVENT = 'onVeltInit';
var VELT_TAB_ID = 'veltTabId';
// integrity map for the Velt SDK
// Note: generate integrity hashes with: https://www.srihash.org/
var INTEGRITY_MAP = {
'5.0.2-beta.31': 'sha384-5O4aQGXMlfDw5Fjpqlx3lSqOIKqigAy+vpKuCyR0RpuMrBgm1Ich/+zN2IcBp1sZ',
};
var validProps = ['veltIf', 'veltClass', 'className', 'variant'];
var transformWireframeProps = function (props) {
try {
var transformedProps_1 = {};
Object.entries(props).forEach(function (_a) {
var key = _a[0], value = _a[1];
if (key === 'children' || key === 'ref' || !validProps.includes(key)) {
transformedProps_1[key] = value;
return;
}
if (key === 'className') {
transformedProps_1['class'] = value;
return;
}
// Convert camelCase to dash-case
var dashKey = key.replace(/[A-Z]/g, function (letter) { return "-".concat(letter.toLowerCase()); });
transformedProps_1[dashKey] = value;
// // Handle boolean values - only convert if explicitly true/false
// if (typeof value === 'boolean') {
// transformedProps[dashKey] = [true, false].includes(value) ? (value ? 'true' : 'false') : undefined;
// } else {
// transformedProps[dashKey] = value;
// }
});
return transformedProps_1;
}
catch (error) {
return props;
}
};
/**
* To deep compare two objects.
* @param arg1 object 1
* @param arg2 object 2
* @returns true if both objects are equal, false otherwise
*/
var deepCompare = function (arg1, arg2) {
try {
if (Object.prototype.toString.call(arg1) === Object.prototype.toString.call(arg2)) {
if (Object.prototype.toString.call(arg1) === '[object Object]' || Object.prototype.toString.call(arg1) === '[object Array]') {
if (Object.keys(arg1).length !== Object.keys(arg2).length) {
return false;
}
return (Object.keys(arg1).every(function (key) {
return deepCompare(arg1[key], arg2[key]);
}));
}
return (arg1 === arg2);
}
return false;
}
catch (err) {
return false;
}
};
var SnippylyProvider = function (props) {
var apiKey = props.apiKey, user = props.user, config = props.config, documentId = props.documentId, language = props.language, translations = props.translations, autoTranslation = props.autoTranslation, userDataProvider = props.userDataProvider, dataProviders = props.dataProviders, encryptionProvider = props.encryptionProvider, authProvider = props.authProvider, permissionProvider = props.permissionProvider, onClientLoad = props.onClientLoad, children = props.children;
var _a = React.useState(null), client = _a[0], setClient = _a[1];
var prevAuthProviderRef = React.useRef(undefined);
var prevUserDataProviderRef = React.useRef(undefined);
var prevDataProvidersRef = React.useRef(undefined);
var prevPermissionProviderRef = React.useRef(undefined);
/**
* Tracks whether the component is currently mounted.
* Used to prevent state updates and async operations on unmounted components.
*
* ## Issue (Rapid Mount/Unmount)
* When VeltProvider is rapidly mounted/unmounted (e.g., conditional rendering
* based on state changes, React Strict Mode, or route transitions), multiple
* component instances can have async operations (like Velt.init()) in flight.
* When these async operations complete, they try to call setClient() on
* unmounted component instances, causing React warnings and incorrect state.
*
* ## Fix
* Track mount state and check it before/after async operations to bail out
* if the component has been unmounted.
*/
var isMountedRef = React.useRef(true);
React.useEffect(function () {
// IMPORTANT: Reset isMountedRef to true on every mount/remount.
// This is critical for React Strict Mode which simulates unmount/remount:
//
// React Strict Mode sequence:
// 1. Mount → isMountedRef = true (initial value)
// 2. Effect runs
// 3. Strict Mode simulates unmount → cleanup sets isMountedRef = false
// 4. Strict Mode simulates remount → effect runs again
//
// Without this reset, step 4 would still see isMountedRef = false from step 3,
// causing initVelt to skip even though the component is actually mounted.
isMountedRef.current = true;
// Cleanup: mark component as unmounted
return function () {
isMountedRef.current = false;
};
}, []);
React.useEffect(function () {
var _a;
// Store cleanup function returned from loadVelt to remove event listeners on unmount
var cleanupLoadVelt;
if (apiKey) {
var staging = config === null || config === void 0 ? void 0 : config.staging;
var develop = config === null || config === void 0 ? void 0 : config.develop;
var version = (config === null || config === void 0 ? void 0 : config.version) || VELT_SDK_VERSION;
var integrity = !!(config === null || config === void 0 ? void 0 : config.integrity);
var integrityValue = "";
if (integrity) {
if (develop || staging) {
if (config === null || config === void 0 ? void 0 : config.sriv) {
integrityValue = config === null || config === void 0 ? void 0 : config.sriv;
}
}
else {
if (INTEGRITY_MAP[version]) {
integrityValue = INTEGRITY_MAP[version];
}
}
}
// Rapid mount/unmount issue found in OpenEnvoy client code with slow network.
//
// Scenario: VeltProvider is conditionally rendered and toggles rapidly while
// the Velt script is loading over a slow network connection.
//
// We check if Velt is already loaded (window.Velt exists) and call initVelt
// directly. If not loaded, we call loadVelt which handles the script loading
// and returns a cleanup function to remove event listeners.
if (window === null || window === void 0 ? void 0 : window.Velt) {
initVelt();
}
else {
// loadVelt returns a cleanup function that removes the load event listener.
// This prevents the callback from firing on destroyed component instances.
cleanupLoadVelt = loadVelt(function () {
initVelt();
}, version, staging, develop, ((_a = config === null || config === void 0 ? void 0 : config.proxyConfig) === null || _a === void 0 ? void 0 : _a.cdnHost) || (config === null || config === void 0 ? void 0 : config.proxyDomain), integrity, integrityValue);
}
}
// Cleanup: remove event listener when component unmounts.
// This is critical for rapid mount/unmount scenarios - without this cleanup,
// the load callback would fire on destroyed component instances and try to
// call initVelt, which would then try to update state on an unmounted component.
return function () {
if (cleanupLoadVelt) {
cleanupLoadVelt();
}
};
}, []);
React.useEffect(function () {
if (!deepCompare(prevUserDataProviderRef.current, userDataProvider)) {
if (client && userDataProvider) {
if (typeof (client === null || client === void 0 ? void 0 : client.setUserDataProvider) === "function") {
client === null || client === void 0 ? void 0 : client.setUserDataProvider(userDataProvider);
}
prevUserDataProviderRef.current = userDataProvider;
}
else {
// Only update ref to undefined if client is available (to track removal)
// If client is not available, keep old ref so we can set provider when client becomes available
if (client) {
prevUserDataProviderRef.current = userDataProvider;
}
}
}
}, [client, userDataProvider]);
React.useEffect(function () {
if (!deepCompare(prevDataProvidersRef.current, dataProviders)) {
if (client && dataProviders) {
if (typeof (client === null || client === void 0 ? void 0 : client.setDataProviders) === "function") {
client === null || client === void 0 ? void 0 : client.setDataProviders(dataProviders);
}
prevDataProvidersRef.current = dataProviders;
}
else {
// Only update ref to undefined if client is available (to track removal)
// If client is not available, keep old ref so we can set provider when client becomes available
if (client) {
prevDataProvidersRef.current = dataProviders;
}
}
}
}, [client, dataProviders]);
React.useEffect(function () {
if (client && encryptionProvider) {
if (typeof (client === null || client === void 0 ? void 0 : client.setEncryptionProvider) === "function") {
client === null || client === void 0 ? void 0 : client.setEncryptionProvider(encryptionProvider);
}
}
}, [client, encryptionProvider]);
React.useEffect(function () {
if (!deepCompare(prevAuthProviderRef.current, authProvider)) {
if (client && authProvider && authProvider.user) {
client.setVeltAuthProvider(authProvider);
prevAuthProviderRef.current = authProvider;
}
else {
// Only update ref to undefined if client is available (to track removal)
// If client is not available, keep old ref so we can set provider when client becomes available
if (client) {
prevAuthProviderRef.current = authProvider;
}
}
}
}, [client, authProvider]);
React.useEffect(function () {
if (!deepCompare(prevPermissionProviderRef.current, permissionProvider)) {
if (client && permissionProvider) {
if (typeof (client === null || client === void 0 ? void 0 : client.setPermissionProvider) === "function") {
client === null || client === void 0 ? void 0 : client.setPermissionProvider(permissionProvider);
}
prevPermissionProviderRef.current = permissionProvider;
}
else {
// Only update ref to undefined if client is available (to track removal)
// If client is not available, keep old ref so we can set provider when client becomes available
if (client) {
prevPermissionProviderRef.current = permissionProvider;
}
}
}
}, [client, permissionProvider]);
/**
* Initializes the Velt SDK with proper mount state checks.
*
* ## Async Safety Pattern
* This function contains async operations (Velt.init). During the await,
* the component might unmount. We must check isMountedRef:
* 1. BEFORE starting - skip if already unmounted
* 2. AFTER await completes - abort if unmounted during the wait
*
* Without these checks, setClient() would be called on unmounted components,
* causing React warnings and potential memory leaks.
*/
var initVelt = function () { return __awaiter(void 0, void 0, void 0, function () {
var velt, event;
var _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
// CHECK 1: Skip initialization if component has already been unmounted.
// This handles the case where cleanup ran before initVelt was called.
if (!isMountedRef.current) {
return [2 /*return*/];
}
if (!config) return [3 /*break*/, 2];
if (config.staging) {
delete config.staging;
}
if (config.develop) {
delete config.develop;
}
if (config === null || config === void 0 ? void 0 : config.version) {
config === null || config === void 0 ? true : delete config.version;
}
if (config === null || config === void 0 ? void 0 : config.proxyDomain) {
delete config.proxyDomain;
}
return [4 /*yield*/, ((_a = window.Velt) === null || _a === void 0 ? void 0 : _a.init(apiKey, config))];
case 1:
velt = _c.sent();
return [3 /*break*/, 4];
case 2: return [4 /*yield*/, ((_b = window.Velt) === null || _b === void 0 ? void 0 : _b.init(apiKey))];
case 3:
velt = _c.sent();
_c.label = 4;
case 4:
// CHECK 2: Abort if component unmounted during the await.
// Velt.init() is async and can take time. The component might have
// been unmounted while we were waiting. Check again before proceeding
// with state updates and side effects.
if (!isMountedRef.current) {
return [2 /*return*/];
}
// Set language
if (language && (velt === null || velt === void 0 ? void 0 : velt.setLanguage)) {
velt === null || velt === void 0 ? void 0 : velt.setLanguage(language);
}
// Set translations
if (translations && (velt === null || velt === void 0 ? void 0 : velt.setTranslations)) {
if (typeof translations === "object") {
Object.keys(translations).forEach(function (languageCode) {
velt === null || velt === void 0 ? void 0 : velt.setTranslations(languageCode, translations[languageCode] || {});
});
}
}
if ([true, false].includes(autoTranslation)) {
if (autoTranslation && (velt === null || velt === void 0 ? void 0 : velt.enableAutoTranslation)) {
velt === null || velt === void 0 ? void 0 : velt.enableAutoTranslation();
}
else if (!autoTranslation && (velt === null || velt === void 0 ? void 0 : velt.disableAutoTranslation)) {
velt === null || velt === void 0 ? void 0 : velt.disableAutoTranslation();
}
}
if (velt === null || velt === void 0 ? void 0 : velt.st) {
velt === null || velt === void 0 ? void 0 : velt.st("react");
}
setClient(velt);
if (onClientLoad) {
onClientLoad(velt);
}
if (!user) return [3 /*break*/, 6];
return [4 /*yield*/, (velt === null || velt === void 0 ? void 0 : velt.identify(user))];
case 5:
_c.sent();
_c.label = 6;
case 6:
if (documentId) {
velt === null || velt === void 0 ? void 0 : velt.setDocumentId(documentId);
}
event = new CustomEvent(VELT_SDK_INIT_EVENT, { detail: velt });
window.dispatchEvent(event);
return [2 /*return*/];
}
});
}); };
return (React__default["default"].createElement(React__default["default"].Fragment, null,
React__default["default"].createElement(VeltContext.Provider, { value: { client: client } }, children)));
};
var SnippylyCommentBubble = function (props) {
var targetCommentElementId = props.targetCommentElementId, targetElementId = props.targetElementId, avatar = props.avatar, showAvatar = props.showAvatar, commentBubbleTargetPinHover = props.commentBubbleTargetPinHover, children = props.children, shadowDom = props.shadowDom, variant = props.variant, darkMode = props.darkMode, commentCountType = props.commentCountType, context = props.context, contextOptions = props.contextOptions, annotationId = props.annotationId, documentId = props.documentId, folderId = props.folderId, locationId = props.locationId, readOnly = props.readOnly, openDialog = props.openDialog;
return (React__default["default"].createElement("velt-comment-bubble", { "annotation-id": annotationId, "comment-count-type": commentCountType, "target-comment-element-id": targetCommentElementId, "target-element-id": targetElementId, context: JSON.stringify(context), "context-options": JSON.stringify(contextOptions), "location-id": locationId, "document-id": documentId, "folder-id": folderId, "show-avatar": [true, false].includes(showAvatar) ? (showAvatar ? 'true' : 'false') : undefined, avatar: [true, false].includes(avatar) ? (avatar ? 'true' : 'false') : undefined, "comment-bubble-target-pin-hover": commentBubbleTargetPinHover ? 'true' : undefined, "shadow-dom": [true, false].includes(shadowDom) ? (shadowDom ? 'true' : 'false') : undefined, "dark-mode": [true, false].includes(darkMode) ? (darkMode ? 'true' : 'false') : undefined, "read-only": [true, false].includes(readOnly) ? (readOnly ? 'true' : 'false') : undefined, "open-dialog": [true, false].includes(openDialog) ? (openDialog ? 'true' : 'false') : undefined, variant: variant }, children));
};
var SnippylyComments = function (props) {
var autoCategorize = props.autoCategorize, streamViewContainerId = props.streamViewContainerId, onSignIn = props.onSignIn, onUpgrade = props.onUpgrade, textMode = props.textMode, popoverMode = props.popoverMode, popoverTriangleComponent = props.popoverTriangleComponent, floatingCommentDialog = props.floatingCommentDialog, moderatorMode = props.moderatorMode, streamMode = props.streamMode, signInButton = props.signInButton, upgradeButton = props.upgradeButton, attachments = props.attachments, recordings = props.recordings, reactions = props.reactions, deviceInfo = props.deviceInfo, commentIndex = props.commentIndex, dialogOnHover = props.dialogOnHover, dialogOnTargetElementClick = props.dialogOnTargetElementClick, priority = props.priority, inboxMode = props.inboxMode, suggestionMode = props.suggestionMode, mobileMode = props.mobileMode, inlineCommentMode = props.inlineCommentMode, privateCommentMode = props.privateCommentMode, minimap = props.minimap, minimapPosition = props.minimapPosition, persistentCommentMode = props.persistentCommentMode, ghostComments = props.ghostComments, ghostCommentsIndicator = props.ghostCommentsIndicator, commentsOnDom = props.commentsOnDom, resolvedCommentsOnDom = props.resolvedCommentsOnDom, filterCommentsOnDom = props.filterCommentsOnDom, bubbleOnPin = props.bubbleOnPin, bubbleOnPinHover = props.bubbleOnPinHover, commentTool = props.commentTool, sidebarButtonOnCommentDialog = props.sidebarButtonOnCommentDialog, deviceIndicatorOnCommentPins = props.deviceIndicatorOnCommentPins, scrollToComment = props.scrollToComment, userMentions = props.userMentions, deleteOnBackspace = props.deleteOnBackspace, hotkey = props.hotkey, recordingSummary = props.recordingSummary, recordingTranscription = props.recordingTranscription, recordingCountdown = props.recordingCountdown, unreadIndicatorMode = props.unreadIndicatorMode, enterKeyToSubmit = props.enterKeyToSubmit, pinShadowDom = props.pinShadowDom, dialogShadowDom = props.dialogShadowDom, persistentCommentShadowDom = props.persistentCommentShadowDom, shadowDom = props.shadowDom, changeDetectionInCommentMode = props.changeDetectionInCommentMode, areaComment = props.areaComment, pinCursorImage = props.pinCursorImage, allowedElementIds = props.allowedElementIds, allowedElementClassNames = props.allowedElementClassNames, allowedElementQuerySelectors = props.allowedElementQuerySelectors, commentPinHighlighter = props.commentPinHighlighter, customReactions = props.customReactions, onCommentAdd = props.onCommentAdd, onCommentUpdate = props.onCommentUpdate, onCommentAccept = props.onCommentAccept, onCommentReject = props.onCommentReject, onSidebarButtonOnCommentDialogClick = props.onSidebarButtonOnCommentDialogClick, onCommentSelectionChange = props.onCommentSelectionChange, customStatus = props.customStatus, customListDataOnAnnotation = props.customListDataOnAnnotation, customListDataOnComment = props.customListDataOnComment, customPriority = props.customPriority, customCategory = props.customCategory, status = props.status, visibilityOptions = props.visibilityOptions, resolveButton = props.resolveButton, darkMode = props.darkMode, onCustomPinInject = props.onCustomPinInject, children = props.children, textCommentToolShadowDom = props.textCommentToolShadowDom, textCommentToolbarShadowDom = props.textCommentToolbarShadowDom, dialogDarkMode = props.dialogDarkMode, pinDarkMode = props.pinDarkMode, textCommentToolDarkMode = props.textCommentToolDarkMode, textCommentToolbarDarkMode = props.textCommentToolbarDarkMode, composerMode = props.composerMode, atHereLabel = props.atHereLabel, atHereDescription = props.atHereDescription, multiThreadMode = props.multiThreadMode, multiThread = props.multiThread, groupMultipleMatch = props.groupMultipleMatch, groupMatchedComments = props.groupMatchedComments, onCopyLink = props.onCopyLink, deleteReplyConfirmation = props.deleteReplyConfirmation, collapsedComments = props.collapsedComments, shortUserName = props.shortUserName, resolveStatusAccessAdminOnly = props.resolveStatusAccessAdminOnly, svgAsImg = props.svgAsImg, seenByUsers = props.seenByUsers, readOnly = props.readOnly, atHereEnabled = props.atHereEnabled, customAutocompleteSearch = props.customAutocompleteSearch, deleteThreadWithFirstComment = props.deleteThreadWithFirstComment, expandMentionGroups = props.expandMentionGroups, showMentionGroupsFirst = props.showMentionGroupsFirst, showMentionGroupsOnly = props.showMentionGroupsOnly, fullExpanded = props.fullExpanded, commentToNearestAllowedElement = props.commentToNearestAllowedElement, draftMode = props.draftMode, maxReplyAvatars = props.maxReplyAvatars, replyAvatars = props.replyAvatars, linkCallback = props.linkCallback, replyPlaceholder = props.replyPlaceholder, commentPlaceholder = props.commentPlaceholder, editPlaceholder = props.editPlaceholder, editCommentPlaceholder = props.editCommentPlaceholder, editReplyPlaceholder = props.editReplyPlaceholder, allowedFileTypes = props.allowedFileTypes, attachmentNameInMessage = props.attachmentNameInMessage, forceCloseAllOnEsc = props.forceCloseAllOnEsc, screenshot = props.screenshot, paginatedContactList = props.paginatedContactList, autoCompleteScrollConfig = props.autoCompleteScrollConfig, assignToType = props.assignToType, formatOptions = props.formatOptions, attachmentDownload = props.attachmentDownload, pinDrag = props.pinDrag, anonymousEmail = props.anonymousEmail;
var ref = React.useRef();
var onSignInRef = React.useRef(onSignIn);
var onUpgradeRef = React.useRef(onUpgrade);
var onCommentAddRef = React.useRef(onCommentAdd);
var onCommentUpdateRef = React.useRef(onCommentUpdate);
var onCommentAcceptRef = React.useRef(onCommentAccept);
var onCommentRejectRef = React.useRef(onCommentReject);
var onSidebarButtonOnCommentDialogClickRef = React.useRef(onSidebarButtonOnCommentDialogClick);
var onCustomPinInjectRef = React.useRef(onCustomPinInject);
var onCommentSelectionChangeRef = React.useRef(onCommentSelectionChange);
var onCopyLinkRef = React.useRef(onCopyLink);
// Update the ref to always point to the latest callback function
React.useEffect(function () {
onSignInRef.current = onSignIn;
}, [onSignIn]);
React.useEffect(function () {
onCopyLinkRef.current = onCopyLink;
}, [onCopyLink]);
React.useEffect(function () {
onUpgradeRef.current = onUpgrade;
}, [onUpgrade]);
React.useEffect(function () {
onCommentAddRef.current = onCommentAdd;
}, [onCommentAdd]);
React.useEffect(function () {
onCommentUpdateRef.current = onCommentUpdate;
}, [onCommentUpdate]);
React.useEffect(function () {
onCommentAcceptRef.current = onCommentAccept;
}, [onCommentAccept]);
React.useEffect(function () {
onCommentRejectRef.current = onCommentReject;
}, [onCommentReject]);
React.useEffect(function () {
onSidebarButtonOnCommentDialogClickRef.current = onSidebarButtonOnCommentDialogClick;
}, [onSidebarButtonOnCommentDialogClick]);
React.useEffect(function () {
onCustomPinInjectRef.current = onCustomPinInject;
}, [onCustomPinInject]);
React.useEffect(function () {
onCommentSelectionChangeRef.current = onCommentSelectionChange;
}, [onCommentSelectionChange]);
React.useEffect(function () {
var element;
var handleSignIn = function (event) {
if (onSignInRef.current) {
onSignInRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
var handleUpgrade = function (event) {
if (onUpgradeRef.current) {
onUpgradeRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
var handleCommentAdd = function (event) {
if (onCommentAddRef.current) {
onCommentAddRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
var handleCommentUpdate = function (event) {
if (onCommentUpdateRef.current) {
onCommentUpdateRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
var handleCommentAccept = function (event) {
if (onCommentAcceptRef.current) {
onCommentAcceptRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
var handleCommentReject = function (event) {
if (onCommentRejectRef.current) {
onCommentRejectRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
var handleSidebarButtonOnCommentDialogClick = function (event) {
if (onSidebarButtonOnCommentDialogClickRef.current) {
onSidebarButtonOnCommentDialogClickRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
var handleCustomPinInject = function (event) {
if (onCustomPinInjectRef.current) {
onCustomPinInjectRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
var handleCommentSelectionChange = function (event) {
if (onCommentSelectionChangeRef.current) {
onCommentSelectionChangeRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
var handleCopyLink = function (event) {
if (onCopyLinkRef.current) {
onCopyLinkRef.current(event === null || event === void 0 ? void 0 : event.detail);
}
};
if (ref.current) {
element = ref.current;
if (element) {
element.addEventListener('onSignIn', handleSignIn);
element.addEventListener('onUpgrade', handleUpgrade);
element.addEventListener('onCommentAdd', handleCommentAdd);
element.addEventListener('onCommentUpdate', handleCommentUpdate);
element.addEventListener('onCommentAccept', handleCommentAccept);
element.addEventListener('onCommentReject', handleCommentReject);
element.addEventListener('onSidebarButtonOnCommentDialogClick', handleSidebarButtonOnCommentDialogClick);
element.addEventListener('onCustomPinInject', handleCustomPinInject);
element.addEventListener('onCommentSelectionChange', handleCommentSelectionChange);
element.addEventListener('onCopyLink', handleCopyLink);
}
}
return function () {
if (element) {
element.removeEventListener('onSignIn', handleSignIn);
element.removeEventListener('onUpgrade', handleUpgrade);
element.removeEventListener('onCommentAdd', handleCommentAdd);
element.removeEventListener('onCommentUpdate', handleCommentUpdate);
element.removeEventListener('onCommentAccept', handleCommentAccept);
element.removeEventListener('onCommentReject', handleCommentReject);
element.removeEventListener('onSidebarButtonOnCommentDialogClick', handleSidebarButtonOnCommentDialogClick);
element.removeEventListener('onCustomPinInject', handleCustomPinInject);
element.removeEventListener('onCommentSelectionChange', handleCommentSelectionChange);
element.removeEventListener('onCopyLink', handleCopyLink);
}
};
}, []);
return (React__default["default"].createElement("velt-comments", { ref: ref, "at-here-label": atHereLabel, "at-here-description": atHereDescription, "at-here-enabled": [true, false].includes(atHereEnabled) ? (atHereEnabled ? 'true' : 'false') : undefined, "composer-mode": composerMode, "seen-by-users": [true, false].includes(seenByUsers) ? (seenByUsers ? 'true' : 'false') : undefined, "collapsed-comments": [true, false].includes(collapsedComments) ? (collapsedComments ? 'true' : 'false') : undefined, "short-user-name": [true, false].includes(shortUserName) ? (shortUserName ? 'true' : 'false') : undefined, "resolve-status-access-admin-only": [true, false].includes(resolveStatusAccessAdminOnly) ? (resolveStatusAccessAdminOnly ? 'true' : 'false') : undefined, "delete-reply-confirmation": [true, false].includes(deleteReplyConfirmation) ? (deleteReplyConfirmation ? 'true' : 'false') : undefined, "auto-categorize": [true, false].includes(autoCategorize) ? (autoCategorize ? 'true' : 'false') : undefined, "data-stream-view-container-id": streamViewContainerId, "text-mode": [true, false].includes(textMode) ? (textMode ? 'true' : 'false') : undefined, "popover-mode": [true, false].includes(popoverMode) ? (popoverMode ? 'true' : 'false') : undefined, "popover-triangle-component": [true, false].includes(popoverTriangleComponent) ? (popoverTriangleComponent ? 'true' : 'false') : undefined, "floating-comment-dialog": [true, false].includes(floatingCommentDialog) ? (floatingCommentDialog ? 'true' : 'false') : undefined, "moderator-mode": [true, false].includes(moderatorMode) ? (moderatorMode ? 'true' : 'false') : undefined, "stream-mode": [true, false].includes(streamMode) ? (streamMode ? 'true' : 'false') : undefined, "sign-in-button": [true, false].includes(signInButton) ? (signInButton ? 'true' : 'false') : undefined, "upgrade-button": [true, false].includes(upgradeButton) ? (upgradeButton ? 'true' : 'false') : undefined, attachments: [true, false].includes(attachments) ? (attachments ? 'true' : 'false') : undefined, recordings: recordings, reactions: [true, false].includes(reactions) ? (reactions ? 'true' : 'false') : undefined, "device-info": [true, false].includes(deviceInfo) ? (deviceInfo ? 'true' : 'false') : undefined, "comment-index": [true, false].includes(commentIndex) ? (commentIndex ? 'true' : 'false') : undefined, "dialog-on-hover": [true, false].includes(dialogOnHover) ? (dialogOnHover ? 'true' : 'false') : undefined, "dialog-on-target-element-click": [true, false].includes(dialogOnTargetElementClick) ? (dialogOnTargetElementClick ? 'true' : 'false') : undefined, priority: [true, false].includes(priority) ? (priority ? 'true' : 'false') : undefined, status: [true, false].includes(status) ? (status ? 'true' : 'false') : undefined, "visibility-options": [true, false].includes(visibilityOptions) ? (visibilityOptions ? 'true' : 'false') : undefined, "resolve-button": [true, false].includes(resolveButton) ? (resolveButton ? 'true' : 'false') : undefined, "inbox-mode": [true, false].includes(inboxMode) ? (inboxMode ? 'true' : 'false') : undefined, "suggestion-mode": [true, false].includes(suggestionMode) ? (suggestionMode ? 'true' : 'false') : undefined, "mobile-mode": [true, false].includes(mobileMode) ? (mobileMode ? 'true' : 'false') : undefined, "inline-comment-mode": [true, false].includes(inlineCommentMode) ? (inlineCommentMode ? 'true' : 'false') : undefined, "private-comment-mode": [true, false].includes(privateCommentMode) ? (privateCommentMode ? 'true' : 'false') : undefined, minimap: [true, false].includes(minimap) ? (minimap ? 'true' : 'false') : undefined, "minimap-position": minimapPosition, "persistent-comment-mode": [true, false].includes(persistentCommentMode) ? (persistentCommentMode ? 'true' : 'false') : undefined, "ghost-comments": [true, false].includes(ghostComments) ? (ghostComments ? 'true' : 'false') : undefined, "ghost-comments-indicator": [true, false].includes(ghostCommentsIndicator) ? (ghostCommentsIndicator ? 'true' : 'false') : undefined, "comments-on-dom": [true, false].includes(commentsOnDom) ? (commentsOnDom ? 'true' : 'false') : undefined, "resolved-comments-on-dom": [true, false].includes(resolvedCommentsOnDom) ? (resolvedCommentsOnDom ? 'true' : 'false') : undefined, "filter-comments-on-dom": [true, false].includes(filterCommentsOnDom) ? (filterCommentsOnDom ? 'true' : 'false') : undefined, "bubble-on-pin": [true, false].includes(bubbleOnPin) ? (bubbleOnPin ? 'true' : 'false') : undefined, "bubble-on-pin-hover": [true, false].includes(bubbleOnPinHover) ? (bubbleOnPinHover ? 'true' : 'false') : undefined, "comment-tool": [true, false].includes(commentTool) ? (commentTool ? 'true' : 'false') : undefined, "sidebar-button-on-comment-dialog": [true, false].includes(sidebarButtonOnCommentDialog) ? (sidebarButtonOnCommentDialog ? 'true' : 'false') : undefined, "device-indicator-on-comment-pins": [true, false].includes(deviceIndicatorOnCommentPins) ? (deviceIndicatorOnCommentPins ? 'true' : 'false') : undefined, "scroll-to-comment": [true, false].includes(scrollToComment) ? (scrollToComment ? 'true' : 'false') : undefined, "user-mentions": [true, false].includes(userMentions) ? (userMentions ? 'true' : 'false') : undefined, "delete-on-backspace": [true, false].includes(deleteOnBackspace) ? (deleteOnBackspace ? 'true' : 'false') : undefined, hotkey: [true, false].includes(hotkey) ? (hotkey ? 'true' : 'false') : undefined, "recording-summary": [true, false].includes(recordingSummary) ? (recordingSummary ? 'true' : 'false') : undefined, "recording-transcription": [true, false].includes(recordingTranscription) ? (recordingTranscription ? 'true' : 'false') : undefined, "recording-countdown": [true, false].includes(recordingCountdown) ? (recordingCountdown ? 'true' : 'false') : undefined, "unread-indicator-mode": unreadIndicatorMode, "enter-key-to-submit": [true, false].includes(enterKeyToSubmit) ? (enterKeyToSubmit ? 'true' : 'false') : undefined, "pin-shadow-dom": [true, false].includes(pinShadowDom) ? (pinShadowDom ? 'true' : 'false') : undefined, "dialog-shadow-dom": [true, false].includes(dialogShadowDom) ? (dialogShadowDom ? 'true' : 'false') : undefined, "shadow-dom": [true, false].includes(shadowDom) ? (shadowDom ? 'true' : 'false') : undefined, "text-comment-tool-shadow-dom": [true, false].includes(textCommentToolShadowDom) ? (textCommentToolShadowDom ? 'true' : 'false') : undefined, "text-comment-toolbar-shadow-dom": [true, false].includes(textCommentToolbarShadowDom) ? (textCommentToolbarShadowDom ? 'true' : 'false') : undefined, "persistent-comment-shadow-dom": [true, false].includes(persistentCommentShadowDom) ? (persistentCommentShadowDom ? 'true' : 'false') : undefined, "change-detection-in-comment-mode": [true, false].includes(changeDetectionInCommentMode) ? (changeDetectionInCommentMode ? 'true' : 'false') : undefined, "area-comment": [true, false].includes(areaComment) ? (areaComment ? 'true' : 'false') : undefined, "pin-cursor-image": pinCursorImage, "allowed-element-ids": JSON.stringify(allowedElementIds), "allowed-element-class-names": JSON.stringify(allowedElementClassNames), "allowed-element-query-selectors": JSON.stringify(allowedElementQuerySelectors), "comment-pin-highlighter": [true, false].includes(commentPinHighlighter) ? (commentPinHighlighter ? 'true' : 'false') : undefined, "custom-reactions": JSON.stringify(customReactions), "custom-status": JSON.stringify(customStatus), "custom-list-data-on-annotation": JSON.stringify(customListDataOnAnnotation), "custom-list-data-on-comment": JSON.stringify(customListDataOnComment), "custom-priority": JSON.stringify(customPriority), "custom-category": JSON.stringify(customCategory), "dark-mode": [true, false].includes(darkMode) ? (darkMode ? 'true' : 'false') : undefined, "dialog-dark-mode": [true, false].includes(dialogDarkMode) ? (dialogDarkMode ? 'true' : 'false') : undefined, "pin-dark-mode": [true, false].includes(pinDarkMode) ? (pinDarkMode ? 'true' : 'false') : undefined, "text-comment-tool-dark-mode": [true, false].includes(textCommentToolDarkMode) ? (textCommentToolDarkMode ? 'true' : 'false') : undefined, "text-comment-toolbar-dark-mode": [true, false].includes(textCommentToolbarDarkMode) ? (textCommentToolbarDarkMode ? 'true' : 'false') : undefined, "multi-thread-mode": [true, false].includes(multiThreadMode) ? (multiThreadMode ? 'true' : 'false') : undefined, "multi-thread": [true, false].includes(multiThread) ? (multiThread ? 'true' : 'false') : undefined, "group-multiple-match": [true, false].includes(groupMultipleMatch) ? (groupMultipleMatch ? 'true' : 'false') : undefined, "group-matched-comments": [true, false].includes(groupMatchedComments) ? (groupMatchedComments ? 'true' : 'false') : undefined, "read-only": [true, false].includes(readOnly) ? (readOnly ? 'true' : 'false') : undefined, "custom-autocomplete-search": [true, false].includes(customAutocompleteSearch) ? (customAutocompleteSearch ? 'true' : 'false') : undefined, "delete-thread-with-first-comment": [true, false].includes(deleteThreadWithFirstComment) ? (deleteThreadWithFirstComment ? 'true' : 'false') : undefined, "svg-as-img": [true, false].includes(svgAsImg) ? (svgAsImg ? 'true' : 'false') : undefined, "expand-mention-groups": [true, false].includes(expandMentionGroups) ? (expandMentionGroups ? 'true' : 'false') : undefined, "show-mention-groups-first": [true, false].includes(showMentionGroupsFirst) ? (showMentionGroupsFirst ? 'true' : 'false') : undefined, "show-mention-groups-only": [true, false].includes(showMentionGroupsOnly) ? (showMentionGroupsOnly ? 'true' : 'false') : undefined, "full-expanded": [true, false].includes(fullExpanded) ? (fullExpanded ? 'true' : 'false') : undefined, "comment-to-nearest-allowed-