`
* First enable the feature and then define which elements should sync realtime.
```jsx
const liveStateSyncElement = useLiveStateSyncUtils();
// Enable auto-sync state
liveStateSyncElement.enableAutoSyncState();
// In your JSX
return (
);
```
```html
```
# Editor
### setUserAsEditor
Sets the current user as the editor, making all other users read-only.
```jsx
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.setUserAsEditor();
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
liveStateSyncElement.setUserAsEditor();
```
### isUserEditor
Get the current user's editor status.
**Returns**
* `UserEditorAccess` object:
* `isEditor` (`boolean`) - Whether the user is the editor
* `isEditorOnCurrentTab` (`boolean`) - Whether the user is editor on current tab
```jsx
// Using Hooks
const { isEditor, isEditorOnCurrentTab } = useUserEditorState();
// Using API
const liveStateSyncElement = useLiveStateSyncUtils();
let subscription = liveStateSyncElement.isUserEditor().subscribe((userEditorAccess) => {
console.log('Is Editor:', userEditorAccess.isEditor);
console.log('Is Editor on Current Tab:', userEditorAccess.isEditorOnCurrentTab);
});
```
To unsubscribe from the subscription:
```jsx
subscription?.unsubscribe()
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
let subscription = liveStateSyncElement.isUserEditor().subscribe((userEditorAccess) => {
console.log('Is Editor:', userEditorAccess.isEditor);
console.log('Is Editor on Current Tab:', userEditorAccess.isEditorOnCurrentTab);
});
// To unsubscribe from the subscription:
subscription?.unsubscribe()
```
### getEditor
Get information about the current editor.
**Returns**
* `User` object:
* `email` (`string`) - Editor's email
* `name` (`string`) - Editor's name
* `photoUrl` (`string`) - Editor's photo URL
* `userId` (`string`) - Editor's unique ID
```jsx
// Using Hooks
const editor = useEditor();
// Using API
const liveStateSyncElement = useLiveStateSyncUtils();
let subscription = liveStateSyncElement.getEditor().subscribe((user) => {
console.log('Editor:', user);
});
```
To unsubscribe from the subscription:
```jsx
subscription?.unsubscribe()
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
let subscription = liveStateSyncElement.getEditor().subscribe((user) => {
console.log('Editor:', user);
});
// To unsubscribe from the subscription:
subscription?.unsubscribe()
```
### isEditorAccessRequested
Check if any viewer has requested editor access.
**Returns**
* `null` - User is not editor or request was canceled
* `EditorRequest` object:
* `requestStatus` (`string`) - 'requested' for active requests
* `requestedBy` (`User`) - User object of the requester
```jsx
// Using Hooks
const editorAccessRequested = useEditorAccessRequestHandler();
// Using API
const liveStateSyncElement = useLiveStateSyncUtils();
let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
if (data === null) {
console.log('No active requests or user is not editor');
} else {
console.log('Request from:', data.requestedBy.name);
}
});
```
To unsubscribe from the subscription:
```jsx
subscription?.unsubscribe()
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
if (data === null) {
console.log('No active requests or user is not editor');
} else {
console.log('Request from:', data.requestedBy.name);
}
});
// To unsubscribe from the subscription:
subscription?.unsubscribe()
```
### acceptEditorAccessRequest
Accept editor access requests.
```jsx
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.acceptEditorAccessRequest();
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
liveStateSyncElement.acceptEditorAccessRequest();
```
### rejectEditorAccessRequest
Reject editor access requests.
```jsx
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.rejectEditorAccessRequest();
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
liveStateSyncElement.rejectEditorAccessRequest();
```
### editCurrentTab
Make current tab editable when editor has multiple tabs open.
```jsx
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.editCurrentTab();
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
liveStateSyncElement.editCurrentTab();
```
# Viewer
### requestEditorAccess
Request editor access from the current editor.
**Returns**
* `null` - Request is pending
* `true` - Request accepted
* `false` - Request rejected
```jsx
const liveStateSyncElement = useLiveStateSyncUtils();
let subscription = liveStateSyncElement.requestEditorAccess().subscribe((status) => {
if (status === null) console.log('Request pending');
else if (status === true) console.log('Request accepted');
else console.log('Request rejected');
});
```
To unsubscribe from the subscription:
```jsx
subscription?.unsubscribe()
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
let subscription = liveStateSyncElement.requestEditorAccess().subscribe((status) => {
if (status === null) console.log('Request pending');
else if (status === true) console.log('Request accepted');
else console.log('Request rejected');
});
// To unsubscribe from the subscription:
subscription?.unsubscribe()
```
### cancelEditorAccessRequest
Cancel the editor access request.
```jsx
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.cancelEditorAccessRequest();
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
liveStateSyncElement.cancelEditorAccessRequest();
```
### resetUserAccess
Reset editor access for all users.
```jsx
const liveStateSyncElement = useLiveStateSyncUtils();
liveStateSyncElement.resetUserAccess();
```
```jsx
const liveStateSyncElement = Velt.getLiveStateSyncElement();
liveStateSyncElement.resetUserAccess();
```
# Best Practices
* Use `singleTabEditor` to prevent confusion when users have multiple tabs open
* Add IDs to HTML elements with sync attributes for more robust syncing
* Only apply sync attributes to native HTML elements, not framework components
# null
## Video Player Sync
`Video Player Sync` allows users to sync their video player with other `Users` in the same document.
This lets all `Users` watch the same video at the same time.
# Setup
To enable `Video Player Sync` in any video, add the `data-sync-video-player="true"` attribute to your video player.
```html
```
Test out `Video Player Sync` by opening two clients side-by-side and having one client play the video player.
To enable `Video Player Sync` in any video, add the `data-sync-video-player="true"` attribute to your video player.
```html
```
```jsx React / Next.js
export default function App() {
return (
);
}
```
```html HTML
```
# Version 3.0.0
## Change Log
### Improvements
* \[**Comments**]: Added pagination in autocomplete option dropdown for improved performance.
* \[**Comments**]: Added "Edit Comment" option in header options dropdown menu for editing the first comment. Only visible to comment author and admins. [Learn more](/ui-customization/features/async/comments/comment-dialog/subcomponents/options-dropdown).
* \[**Recorder**]: Added `shadow dom` prop in Recorder Player component to control shadow DOM encapsulation.
Using Props:
```jsx
```
Using Props:
```html
```
### Bug Fixes
* \[**Recorder**]: Fixed an issue where `summary` prop was not working in Recorder Player component.
### Improvements
* \[**Core**]: Added updates to the core library packages.
### Improvements
* \[**Core**]: Added accessibility props and test ids for most Velt components within Comments, Notifications, Live Selection features.
### Features
* \[**UI Customization**]: Added additional CSS variables for z-index customization. [Learn more](/ui-customization/customize-css/themes#available-theme-variables).
* `--velt-comment-pin-z-index: 2147483557`: For Components like Comment Pin, Triangle, etc.
* `--velt-arrow-z-index: 2147483557`: For Arrow Component.
* `--velt-recorder-player-z-index: 2147483557`: For Recorder Player Component.
* `--velt-cursor-z-index: 2147483647`: For Cursor Component.
* `--velt-persistent-comment-frame-z-index: 2147483647`: For Persistent Comment Frame Component.
* `--velt-toast-popup-z-index: 2147483647`: For Toast Popup Component.
* `--velt-live-state-sync-overlay-z-index: 2147483647`: For Live State Sync Overlay Component.
* `--velt-follow-mode-overlay-z-index: 2147483647`: For Follow Mode Overlay Component.
* `--velt-comments-minimap-z-index: 2147483637`: For Comments Minimap Component.
* `--velt-global-overlay-z-index: 2147483637`: For Global Overlay Component.
### Improvements
* \[**Comments**]: Improved comment annotation view count logic.
### Bug Fixes
* \[**Comments**]: Fixed an issue where default custom status was not applied when adding new comment annotation.
* \[**Comments**]: Added support for setting dynamic `targetElementId` value asynchronously in comment tool.
* \[**Comments**]: Fixed an issue where assign dropdown input wasn't closing after user selection.
* \[**Comments**]: Fixed padding around assign dropdown.
* \[**Comments**]: Fixed horizontal scroll and overflow issues for longer emails in assign dropdown input and assign banner.
This release changes how users navigate to comments from the sidebar. We've made navigation more explicit by requiring users to click a dedicated button rather than the comment itself.
### Improvements
* \[**Comments**]: Added navigation button as default in Comments Sidebar.
* Now just clicking on a comment doesn't open the comment on the DOM.
* A lot of users reported this behaviour as frustrating. That's why now there is an explicit navigation button for that.
* You will still get the [`onCommentClick`](/async-collaboration/comments-sidebar/customize-behavior#oncommentclick) event. You can still use that to maintain the old behavior [using this](/async-collaboration/comments/customize-behavior/customize-behavior#selectcommentbyannotationid).
* If you had previously used a wireframe for the comment dialog, you will need to add the [navigation button wireframe](/ui-customization/features/async/comments/comment-dialog/subcomponents/header) to show the navigation button.
* \[**Comments**]: Added feature to show resolved comments on for inline comments section.
* \[**Comments**]: Disabled collapsed comments by default. Most customers don't want to show collapsed comments by default so we disabled it. You can enable it by setting using [this](/async-collaboration/comments/customize-behavior/customize-behavior#enablecollapsedcomments).
* \[**Comments**]: Disabled auto-focus on new comments in inline comments section and sidebar page mode.
### Bug Fixes
* \[**Comments**]: Fixed inline comment section horizontal scroll issue when the available width is too narrow.
* \[**Comments**]: Fixed Composer Send Button vertical alignment.
* \[**Comments**]: Removed autofocus for inline comments section when the page loads.
* \[**Comments**]: Fixed issue where clicking composer in edit mode was passing clicks through to the sidebar.
* \[**Comments**]: Fixed copy paste replace issue in the composer where pasting text over selected text was not working correctly.
* \[**Comments**]: Fixed Velt Button Sidebar wireframe loading default UI initially.
* \[**Comments**]: Fixed unread comments count APIs to return correct values on document switch.
### Improvements
* \[**Core**]: Added library upgrades to the SDK.
### Improvements
* \[**Comments**]: Added `readOnly` property in comment sidebar context so that it's available in `Velt Data` and `Velt If` features.
### Bug Fixes
* \[**Comments**]: Fixed an issue where the Comments Sidebar was emitting multiple update calls.
* \[**UI Customization**]: Updated border radius for the status component in the Comment Dialog.
### Features
* \[**Velt Button**]: Added a customizable button component that can be used to add custom actions and extend the functionality of any Velt component. [Learn more](/ui-customization/custom-action-component). Some examples include:
* Add custom filtering, sorting and grouping to the Comment Sidebar.
* Add custom actions to each item in the Notifications panel.
* Add custom actions to the Comment Dialog.
* \[**Theme Playground**]: Added a new [Theme Playground](https://playground.velt.dev/themes). You can customize and test your themes. It will generate CSS variables that you can just copy and paste into your app.
### Improvements
* \[**Comments**]: Added additional wireframes for Comment Dialog Toggle Reply Component. [Learn more](/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/togglereply).
* \[**Comments**]: Now users can't submit empty comments during editing.
* \[**Comments**]: Improved the padding on the @mention autocomplete dropdown.
* \[**Ergonomics**]: Updated `useCommentActionCallback` to `useCommentEventCallback`. The old hook name will continue to work.
* \[**Ergonomics**]: For Sidebar Custom actions and filters, updated APIs and Hooks:
* `onCommentSidebarInit` can now be also be accessed with `useCommentEventCallback('commentSidebarDataInit')` or `commentElement.on('commentSidebarDataInit')`
* `onCommentSidebarData` can now be also be accessed with `useCommentEventCallback('commentSidebarDataUpdate')` or `commentElement.on('commentSidebarDataUpdate')`
### Bug Fixes
* \[**Comments**]: Fixed an issue where the Comment sidebar group count was not updated correctly.
* \[**Comments**]: Fixed an issue where attached files were not displayed on the very first comment in inline and page mode comments.
* \[**Comments**]: Fixed a UI issue where attachments were misaligned when a comment was edited.
* \[**Comments**]: Fixed a UX issue where the comment composer did not scroll into view when comment edit button was clicked.
* \[**Comments**]: Resolved a UI issue where the Page Mode composer in the comment sidebar during embed mode was not taking the full width of the parent container.
### Bug Fixes
* \[**Comments**]: Fixed an issue where the Comment Annotation unread count was not updated correctly.
### Features
* \[**Comments**]: Added ability to make comments read-only. When comments are made read-only, any features requiring user interaction (e.g., Composer, Reactions, Status) will be removed.
Using Props:
```jsx
```
Using API:
```js
const commentElement = client.getCommentElement();
commentElement.enableReadOnly();
commentElement.disableReadOnly();
```
Using Props:
```html
```
Using API:
```js
const commentElement = Velt.getCommentElement();
commentElement.enableReadOnly();
commentElement.disableReadOnly();
```
### Bug Fixes
* \[**Comments**]: Fixed image lightbox CSS related issue
### Bug Fixes
* \[**Comments**]: Fixed undefined value error while updating context.
### Bug Fixes
* \[**Comments**]: Added `composerVariant` prop to `VeltInlineCommentsSection` component to support inline composer variant
```jsx
```
```html
```
* \[**UI**]: Minor CSS fixes and improvements
### Bug Fixes
* \[**Comments**]: Fixed undefined value error while updating context.
### Improvements
* \[**Comments**]: Added support for programatic selection and scrolling to comments in the `velt-comment-text` component used in Tiptap Comments.
### Features
* \[**Comments**]: Added ability to customize the placeholder text shown in the search input of the comments sidebar:
```jsx
...
...
```
```html
...
...
```
### Features
* \[**Comment**]: Added [new APIs, hooks and event callbacks](/async-collaboration/comments/customize-behavior/customize-behavior) for each action that the user can perform on the Comment's Feature Components or API:
* **APIs & Hooks**:
* **Comment Annotation**: addCommentAnnotation, deleteCommentAnnotation
* **Comment**: addComment, deleteComment, updateComment, getComment
* **@Mention**: subscribeCommentAnnotation, unsubscribeCommentAnnotation, assignUser
* **Reaction**: addReaction, deleteReaction, toggleReaction
* **Attachment**: addAttachment, deleteAttachment, getAttachment
* **Status & Priority**: updateStatus, updatePriority, resolveCommentAnnotation
* **Recording**: getRecording, deleteRecording
* **Deep Link**: getLink, copyLink
* **Moderation**: approveCommentAnnotation, acceptCommentAnnotation, rejectCommentAnnotation, updateAccess
* **More Event Callbacks**:
* [On](/async-collaboration/comments/customize-behavior/customize-behavior#on)
* [Here](/api-reference/sdk/models/api-event-types-enum) is the list of events you can subscribe to.
* \[**Metadata**]: Get the currently set organization, document and location objects:
```jsx
const metadata = await client.getMetadata();
```
* \[**UI Customization**]: Added ability to customize comment sidebar search placeholder:
```jsx
```
```html
```
### Features
* \[**UI Customization**]: Extended themes to include more components:
* Comments:
* Autocomplete
* Tooltip
* Chart Comments
* Text Comment Toolbar
* Comment Inbox
* Comment Text Portal
* Persistent Comment Mode
* Minimap
* Inline Comment Section
* Multi Thread Comments
* Notifications
* Notifications Panel
* Notification Tool
### Features
* \[**UI Customization**]: Introducing Themes! Now you can customize the look and feel of Velt components using CSS variables. This enables you to match Velt's UI with your application's design system.
* The following components now support theming (others will be added soon):
* Comment Components
* Recording Components
* Reactions
* You can customize:
* Border radius
* Spacing
* Typography
* Colors for light and dark modes
* Base Colors
* Accent Colors
* Text Shades
* Background Shades
* Border Shades
* Status Colors (error, warning, success)
* Transparent colors
* Learn more about UI Customization [here](/ui-customization/overview).
```css
--velt-border-radius-2xs: 0.125rem; // 2px
--velt-border-radius-xs: 0.25rem; // 4px
--velt-border-radius-sm: 0.5rem; // 8px
--velt-border-radius-md: 0.75rem; // 12px
--velt-border-radius-lg: 1rem; // 16px
--velt-border-radius-xl: 1.25rem; // 20px
--velt-border-radius-2xl: 1.5rem; // 24px
--velt-border-radius-3xl: 2rem; // 32px
--velt-border-radius-full: 5rem; // 80px
```
```css
--velt-spacing-2xs: 0.125rem; // 2px
--velt-spacing-xs: 0.25rem; // 4px
--velt-spacing-sm: 0.5rem; // 8px
--velt-spacing-md: 0.75rem; // 12px
--velt-spacing-lg: 1rem; // 16px
--velt-spacing-xl: 1.25rem; // 20px
--velt-spacing-2xl: 1.5rem; // 24px
```
```css
--velt-default-font-family: sans-serif;
--velt-font-size-2xs: 0.625rem; // 10px
--velt-font-size-xs: 0.75rem; // 12px
--velt-font-size-sm: 0.875rem; // 14px
--velt-font-size-md: 1rem; // 16px
--velt-font-size-lg: 1.5rem; // 24px
--velt-font-size-xl: 1.75rem; // 28px
--velt-font-size-2xl: 2rem; // 32px
```
```css
/* Base Colors */
--velt-light-mode-green: #0DCF82;
--velt-light-mode-magenta: #A259FE;
--velt-light-mode-amber: #FF7162;
--velt-light-mode-purple: #625DF5;
--velt-light-mode-cyan: #4BC9F0;
--velt-light-mode-orange: #FE965C;
--velt-light-mode-black: #080808;
--velt-light-mode-white: #FFFFFF;
--velt-light-mode-gray: #EBEBEB;
/* Accent Colors */
--velt-light-mode-accent: #625DF5;
--velt-light-mode-accent-text: #9491F8;
--velt-light-mode-accent-hover: #534FCF;
--velt-light-mode-accent-foreground: #FFFFFF;
--velt-light-mode-accent-light: #F2F2FE;
--velt-light-mode-accent-transparent: rgba(148, 145, 248, 0.08);
/* Text Shades */
--velt-light-mode-text-0: #0A0A0A;
--velt-light-mode-text-1: #141414;
--velt-light-mode-text-2: #1F1F1F;
--velt-light-mode-text-3: #292929;
--velt-light-mode-text-4: #3D3D3D;
--velt-light-mode-text-5: #525252;
--velt-light-mode-text-6: #666666;
--velt-light-mode-text-7: #7A7A7A;
--velt-light-mode-text-8: #858585;
--velt-light-mode-text-9: #999999;
--velt-light-mode-text-10: #B8B8B8;
--velt-light-mode-text-11: #A3A3A3;
--velt-light-mode-text-12: #8F8F8F;
/* Background Shades */
--velt-light-mode-background-0: #FFFFFF;
--velt-light-mode-background-1: #FAFAFA;
--velt-light-mode-background-2: #F5F5F5;
--velt-light-mode-background-3: #F0F0F0;
--velt-light-mode-background-4: #EBEBEB;
--velt-light-mode-background-5: #E5E5E5;
--velt-light-mode-background-6: #E0E0E0;
--velt-light-mode-background-7: #DBDBDB;
--velt-light-mode-background-8: #D6D6D6;
--velt-light-mode-background-9: #D1D1D1;
--velt-light-mode-background-10: #CCCCCC;
/* Border Shades */
--velt-light-mode-border-0: #FFFFFF;
--velt-light-mode-border-1: #FAFAFA;
--velt-light-mode-border-2: #F5F5F5;
--velt-light-mode-border-3: #F0F0F0;
--velt-light-mode-border-4: #EBEBEB;
--velt-light-mode-border-5: #E5E5E5;
--velt-light-mode-border-6: #E0E0E0;
--velt-light-mode-border-7: #DBDBDB;
--velt-light-mode-border-8: #D6D6D6;
--velt-light-mode-border-9: #D1D1D1;
--velt-light-mode-border-10: #CCCCCC;
/* Status Colors */
/* Error */
--velt-light-mode-error: #FF7162;
--velt-light-mode-error-hover: #DE5041;
--velt-light-mode-error-foreground: #FFFFFF;
--velt-light-mode-error-light: #FFF4F2;
--velt-light-mode-error-transparent: rgba(255, 113, 98, 0.08);
/* Warning */
--velt-light-mode-warning: #FFCD2E;
--velt-light-mode-warning-hover: #C69400;
--velt-light-mode-warning-foreground: #474747;
--velt-light-mode-warning-light: #FFFBEE;
--velt-light-mode-warning-transparent: rgba(255, 205, 46, 0.08);
/* Success */
--velt-light-mode-success: #198F65;
--velt-light-mode-success-hover: #006B41;
--velt-light-mode-success-foreground: #FFFFFF;
--velt-light-mode-success-light: #EDF6F3;
--velt-light-mode-success-transparent: rgba(25, 143, 101, 0.08);
/* Transparent Colors */
--velt-light-mode-background-transparent: rgba(255, 255, 255, 0.80);
--velt-light-mode-border-transparent: rgba(0, 0, 0, 0.16);
--velt-light-mode-animation-transparent: rgba(255, 255, 255, 0.2);
```
```css
/* Base Colors */
--velt-dark-mode-green: #0DCF82;
--velt-dark-mode-magenta: #A259FE;
--velt-dark-mode-amber: #FF7162;
--velt-dark-mode-purple: #625DF5;
--velt-dark-mode-cyan: #4BC9F0;
--velt-dark-mode-orange: #FE965C;
--velt-dark-mode-black: #080808;
--velt-dark-mode-white: #FFFFFF;
--velt-dark-mode-gray: #EBEBEB;
/* Accent Colors */
--velt-dark-mode-accent: #625DF5;
--velt-dark-mode-accent-text: #9491F8;
--velt-dark-mode-accent-hover: #534FCF;
--velt-dark-mode-accent-foreground: #FFFFFF;
--velt-dark-mode-accent-light: #F2F2FE;
--velt-dark-mode-accent-transparent: rgba(148, 145, 248, 0.08);
/* Text Shades */
--velt-dark-mode-text-0: #FFFFFF;
--velt-dark-mode-text-1: #F5F5F5;
--velt-dark-mode-text-2: #EBEBEB;
--velt-dark-mode-text-3: #E0E0E0;
--velt-dark-mode-text-4: #D6D6D6;
--velt-dark-mode-text-5: #C2C2C2;
--velt-dark-mode-text-6: #ADADAD;
--velt-dark-mode-text-7: #8F8F8F;
--velt-dark-mode-text-8: #7A7A7A;
--velt-dark-mode-text-9: #666666;
--velt-dark-mode-text-10: #525252;
--velt-dark-mode-text-11: #474747;
--velt-dark-mode-text-12: #3D3D3D;
/* Background Shades */
--velt-dark-mode-background-0: #0F0F0F;
--velt-dark-mode-background-1: #1A1A1A;
--velt-dark-mode-background-2: #1F1F1F;
--velt-dark-mode-background-3: #242424;
--velt-dark-mode-background-4: #292929;
--velt-dark-mode-background-5: #2E2E2E;
--velt-dark-mode-background-6: #333333;
--velt-dark-mode-background-7: #383838;
--velt-dark-mode-background-8: #3D3D3D;
--velt-dark-mode-background-9: #424242;
--velt-dark-mode-background-10: #474747;
/* Border Shades */
--velt-dark-mode-border-0: #0F0F0F;
--velt-dark-mode-border-1: #1A1A1A;
--velt-dark-mode-border-2: #1F1F1F;
--velt-dark-mode-border-3: #242424;
--velt-dark-mode-border-4: #292929;
--velt-dark-mode-border-5: #2E2E2E;
--velt-dark-mode-border-6: #333333;
--velt-dark-mode-border-7: #383838;
--velt-dark-mode-border-8: #3D3D3D;
--velt-dark-mode-border-9: #424242;
--velt-dark-mode-border-10: #474747;
/* Status Colors */
/* Error */
--velt-dark-mode-error: #FF7162;
--velt-dark-mode-error-hover: #DE5041;
--velt-dark-mode-error-foreground: #FFFFFF;
--velt-dark-mode-error-light: #FFF4F2;
--velt-dark-mode-error-transparent: rgba(255, 113, 98, 0.08);
/* Warning */
--velt-dark-mode-warning: #FFCD2E;
--velt-dark-mode-warning-hover: #C69400;
--velt-dark-mode-warning-foreground: #474747;
--velt-dark-mode-warning-light: #FFFBEE;
--velt-dark-mode-warning-transparent: rgba(255, 205, 46, 0.08);
/* Success */
--velt-dark-mode-success: #198F65;
--velt-dark-mode-success-hover: #006B41;
--velt-dark-mode-success-foreground: #FFFFFF;
--velt-dark-mode-success-light: #EDF6F3;
--velt-dark-mode-success-transparent: rgba(25, 143, 101, 0.08);
/* Transparent Colors */
--velt-dark-mode-background-transparent: rgba(0, 0, 0, 0.80);
--velt-dark-mode-border-transparent: rgba(255, 255, 255, 0.16);
--velt-dark-mode-animation-transparent: rgba(255, 255, 255, 0.2);
```
* Example of theme customisation:
* You can update the following variables in `` tag to change the theme.
* For testing, try copy pasting the following sample themes in body tag:
```css
body {
--velt-light-mode-accent: #0BA528;
--velt-light-mode-accent-text: #0BA528;
--velt-light-mode-accent-hover: #08841F;
--velt-light-mode-accent-foreground: #FFFFFF;
--velt-light-mode-accent-light: #DFF9E4;
--velt-light-mode-accent-transparent: rgba(11, 165, 40, 0.08);
--velt-dark-mode-accent: #0BA528;
--velt-dark-mode-accent-text: #0BA528;
--velt-dark-mode-accent-hover: #08841F;
--velt-dark-mode-accent-foreground: #FFFFFF;
--velt-dark-mode-accent-light: #DFF9E4;
--velt-dark-mode-accent-transparent: rgba(11, 165, 40, 0.08);
--velt-border-radius-2xs: 2px;
--velt-border-radius-xs: 2px;
--velt-border-radius-sm: 2px;
--velt-border-radius-md: 2px;
--velt-border-radius-lg: 2px;
--velt-border-radius-xl: 2px;
--velt-border-radius-2xl: 2px;
--velt-border-radius-3xl: 2px;
--velt-border-radius-full: 2px;
}
```
### Features
* \[**Comments**]: Added support for passing Comment Annotation objects to Standalone Comment Thread component.
* When using annotations from other documents:
* Comments will be read-only
* Reactions and recordings will not be rendered
* This enables creating Kanban boards by fetching comment annotations from multiple documents using our REST APIs.
```jsx
```
```html
```
* \[**Comments**]: Added `shortUserName` feature to control display of user names.
* For long names, this will first create an initial of the second name and if the name is still long, it will truncate it with ellipses.
* It's enabled by default.
**Using Props:**
```jsx
```
**Using API:**
```js
const commentElement = client.getCommentElement();
commentElement.enableShortUserName();
commentElement.disableShortUserName();
```
**Using Props:**
```html
```
**Using API:**
```js
const commentElement = Velt.getCommentElement();
commentElement.enableShortUserName();
commentElement.disableShortUserName();
```
### Improvements
* \[**Comments**]: Added support for light mode in the contact chip tooltip.
* \[**Comments**]: Removed unnecessary filtering in the sidebar when comment annotation selection changes.
### Bug Fixes
* \[**Comments**]: Fixed an issue where `onCommentSidebarData` event was getting triggered multiple times on sidebar clicks.
* \[**Comments**]: Fixed an issue where empty placeholder was not being displayed in the sidebar for page mode and custom action filters.
### Bug Fixes
* \[**Comments**]: Fixed issue where bottom sheet was incorrectly opening in the sidebar on mobile devices.
### Features
* \[**Comments**]: Fixed issue where edit comment composer was not appearing in the sidebar.
* \[**Comments**]: Added offset property to Comment Player Timeline. This allows comment bubbles to be positioned relative to both parent and child video clips.
```jsx
```
```html
```
### Improvements
* \[**Dynamic Hooks**]: Now the LiveStateSync and Views hooks support dynamic input parameters for non-primitive data types.
### Bug Fixes
* \[**Comments**]: Fixed issue where edit comment composer was not appearing in the sidebar.
### Features
* \[**REST APIs**]: Added advanced queries and pagination for GET endpoints.
* You need to upgrade to version 3.0.61 and enable this in your developer console.
* Check out the [V2 REST APIs endpoints](/api-reference/rest-apis/comments-feature/comment-annotations/get-comment-annotations-v2) for more information.
### Features
* \[**Comments**]: Added ability to enable/disable recording transcription feature on recorder:
**Using Props:**
```jsx
```
**Using API Methods:**
```javascript
// Using comment element
const commentElement = client.getCommentElement();
commentElement.enableRecordingTranscription();
commentElement.disableRecordingTranscription();
// Or using recorder element
const recorderElement = client.getRecorderElement();
recorderElement.enableRecordingTranscription();
recorderElement.disableRecordingTranscription();
```
**Using Props:**
```html
```
**Using API Methods:**
```javascript
// Using comment element
const commentElement = Velt.getCommentElement();
commentElement.enableRecordingTranscription();
commentElement.disableRecordingTranscription();
// Or using recorder element
const recorderElement = Velt.getRecorderElement();
recorderElement.enableRecordingTranscription();
recorderElement.disableRecordingTranscription();
```
### Bug Fixes
* \[**Comments**]: Fixed range error that occurred when recording without comment text.
### Bug Fixes
* \[**Comments**]: Fixed several issues with the comment dialog and inline comments:
* Fixed cursor position not being set correctly when focusing comment input
* Fixed an issue where editing a comment and saving it as a draft created a new comment
* Fixed an issue where sometimes comment pin was visible on the inline comments section
### Improvements
* \[**Comments**]: Added ability to sort inline comments:
* `asc`: Show comments in ascending order of last updated timestamp
* `desc`: Show comments in descending order of last updated timestamp
* `none`: Show comments in order of creation (default)
```jsx
```
```html
```
* \[**Comments**]: Further improved how empty comments are handled:
* Empty comments are now hidden from the sidebar and sidebar button count
* In popover mode, clicking a new comment button discards any previous empty comment
* \[**Comments**]: Added delete option for each comment in annotations when user has admin privileges.
### Bug Fixes
* \[**Notifications**]: Optimized and fixed issues related to loading notifications on `documentId` and `organizationId` change.
### Improvements
* \[**Comments**]: Improved the system grouping logic for locations.
* \[**Comments**]: Enhanced `updateContext` logic to prevent unnecessary updates if the passed context object remains unchanged.
* \[**Comments**]: Exposed `commentAnnotations` variable in the comments sidebar so that it can be used in `Velt Data` and `Velt If` Components.
### Bug Fixes
* \[**Comments**]: Fixed an issue where adding the `Copy Link` wireframe component in the header options menu generated undefined Comment URLs.
### Improvements
* \[**Comments**]: The "clear filter" button in the sidebar now only appears when comments are hidden due to active filters, not when there are no comments on the document.
### Bug Fixes
* \[**Comments**]: Fixed an issue with the Assign feature across different comment modes:
* Page mode
* Inline mode
* Multi-thread mode
* \[**Comments**]: Fixed an issue where reactions were not updated in focused thread mode.
### New Features
* \[**Comments**]: Now comments are supported on elements with duplicate DOM IDs.
* This is useful in cases where you have multiple instances of the same data component on a page and want the comment to appear on each instance, eg: Popover comments on a table.
* By default, comments appear on all matching elements. Use the `sourceId` attribute to control which element displays the comment dialog when adding a new comment.
```jsx
```
```html
```
### Improvements
* \[**Comments**]: In multithread mode, now you can deselect a thread by clicking on the header of the multi-thread dialog.
* \[**Comments**]: Removed self user from the list of users in the "Seen By" dropdown.
* \[**Comments**]: Removed users without name and email from the list of users in the "Seen By" dropdown.
### Bug Fixes
* \[**Tiptap Comments**]: Removed `data-velt-content` attribute. Now the highlighted text styling is only applied to text when there are comments available.
* \[**Comments**]: Fixed an issue where undefined and null string values appeared in individual and group contact lists.
### Bug Fixes
* \[**Security**]: Added security updates.
### New Features
* \[**Recorder**]: Added `getRecordingData` API to fetch [recording data](/api-reference/models/RecorderData) including transcript, summary, and recording URLs.
**Using Hook:**
```jsx
const recorderData = useRecordingDataByRecorderId('-O9yTMWmEe5u6YGX8EFV');
useEffect(() => {
console.log('Recorder Data: ', recorderData);
}, [recorderData]);
```
**Using API:**
```jsx
const recorderElement = client.getRecorderElement();
recorderElement.getRecordingDataByRecorderId("-O9yGiYS8lehOXMpQf4j").subscribe((recorderData) => {
console.log('Recorder Data: ', recorderData);
});
```
```javascript
const recorderElement = Velt.getRecorderElement();
recorderElement.getRecordingDataByRecorderId("-O9yGiYS8lehOXMpQf4j").subscribe((recorderData) => {
console.log('Recorder Data: ', recorderData);
});
```
### Improvements
* \[**Comments**]: In the sidebar, changed default `isExpanded` behavior in custom filtering. If not explicitly set, the first group will be expanded while remaining groups are collapsed.
### New Features
* \[**Comments**]: Added variant support to the `Velt Comment Pin` component. This is useful for customizing how the pin looks on different elements like charts, tables, etc.
```jsx
```
```html
```
* \[**Access Control**]: Enabled users logged in with "Org A" to access documents belonging to "Org B".
* By default, users can only access documents within their own organization.
* You can enable cross-organization access by specifying the `organizationId` of the target document in the document metadata.
* Ensure that the user has access to the target document in the target organization.
**Using Hook:**
```jsx
useSetDocument(DOCUMENT_ID, {
organizationId: 'ANOTHER_ORGANIZATION_ID'
});
```
**Using API:**
```jsx
client.setDocument(DOCUMENT_ID, {
organizationId: 'ANOTHER_ORGANIZATION_ID'
});
```
```javascript
Velt.setDocument(DOCUMENT_ID, {
organizationId: 'ANOTHER_ORGANIZATION_ID'
});
```
* \[**Comments**]: Added ability to toggle the "Seen By" feature:
**Using Props:**
```jsx
```
**Using API:**
```jsx
const commentElement = client.getCommentElement();
commentElement.enableSeenByUsers();
commentElement.disableSeenByUsers();
```
**Using Props:**
```html
```
**Using API:**
```javascript
const commentElement = Velt.getCommentElement();
commentElement.enableSeenByUsers();
commentElement.disableSeenByUsers();
```
### Improvements
* \[**Live Selection**]: Improved the live selection UI.
* \[**Recording**]: Added new wireframes for the recording feature:
* Media Source Settings
* Recorder All Tool
* Recorder All Tool Menu
* Recorder Audio Tool
* Recorder Video Tool
* Recorder Screen Tool
* Recording Preview Steps Dialog
* Recorder Control Panel
* Recorder Player
* Video Player
* Subtitles
* Transcription
* \[**Comments**]: Updated the empty state UI and added a clear filter button in the sidebar.
* \[**Comments**]: The "Custom filters" applied by the user are now stored in session storage just like the System filters.
### Improvements
### Bug Fixes
* \[**Comments**]: Fixed an issue in TipTap editor where the comment dialog closed prematurely after adding a comment in single-thread mode.
* \[**Comments**]: Fixed an issue on minimap where clicking on it was not navigating to the comment location.
* \[**Comments**]: Fixed an issue where image attachments in comments were not opening in the lightbox.
* \[**Comments**]: Fixed an issue where the "AtHere" was not working when the label was set to "all".
### Improvements
* \[**Security**]: Added security updates.
### Improvements
* \[**Comments**]: Added dark mode support for the "Seen By" dropdown in the comment dialog.
### New Features
* \[**Webhooks**]: Added configuration option to encrypt webhook payloads using a secret key.
* Configure this option in the [Velt Console](https://console.velt.dev/dashboard/config/webhook).
* Encryption details:
* Payload encryption: AES-256-CBC
* Key encryption: RSA with PKCS1 OAEP padding and SHA-256 hash
* Public key format:
* Provide only the base64-encoded key string, without PEM headers/footers
* Recommended key size: 2048 bits
* Example of setting up encryption for Node.js:
```js
{
"encryptedData": "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",
"encryptedKey": "OzSHFXzrXFC5wDvM5NPRkriY/NaC/USvFUPE+f4NZ30tiD2qb8sJM2XT2K7uNIZ05uDLfsJ6/BbEoYC1SOPXcFJMYqRiYFiI9RWrNgR4EtPWZ84RgrmxGcZZjzSqHzjuls8g++cuqJGRV+ePbTRH+z2OuZZu0vMKZiemaZpHL46Ewi9HUnbRDXvOlKFFHmQm5tayZ7m7Mv5iu4T5R3DPEAHlZnGqtP98ToLxUJUS2Eku/iLHXRmhmZXn55Qt5GYiyss8P5/miPqJCu1QG0CStn5Nsl4KvU+I4QYAOcMFWWUAGofOwPWtt8vPh8Bx+7t7BbayKpA4ZUEWWAjC+zASxg==",
"iv": "SHM0UHU5WXoyTG03TnExWA=="
}
```
```javascript
const crypto = require('crypto');
/**
* Decrypts the symmetric key using the provided private key.
* @param {string} encryptedKey - Base64 encoded encrypted symmetric key
* @param {string} privateKey - RSA private key
* @returns {Buffer} Decrypted symmetric key
*/
function decryptSymmetricKey(encryptedKey, privateKey) {
try {
const encryptedSymmetricKey = Buffer.from(encryptedKey, 'base64');
const decryptedSymmetricKey = crypto.privateDecrypt(
{
key: `-----BEGIN RSA PRIVATE KEY-----\n${privateKey}\n-----END RSA PRIVATE KEY-----`,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256',
},
encryptedSymmetricKey
);
return decryptedSymmetricKey;
} catch (error) {
console.error('Error decrypting symmetric key:', error);
throw new Error('Failed to decrypt symmetric key');
}
}
/**
* Decrypts the webhook data using the provided symmetric key and IV.
* @param {string} encryptedWebhookData - Base64 encoded encrypted webhook data
* @param {Buffer} symmetricKey - Decrypted symmetric key
* @param {string} payloadIv - Base64 encoded initialization vector
* @returns {Object} Decrypted webhook data as a JSON object
*/
function decryptWebhookData(encryptedWebhookData, symmetricKey, payloadIv) {
try {
const iv = Buffer.from(payloadIv, 'base64');
const decipher = crypto.createDecipheriv('aes-256-cbc', symmetricKey, iv);
let decryptedData = decipher.update(encryptedWebhookData, 'base64', 'utf8');
decryptedData += decipher.final('utf8');
return JSON.parse(decryptedData);
} catch (error) {
console.error('Error decrypting webhook data:', error);
throw new Error('Failed to decrypt webhook data');
}
}
// Example usage:
// const decryptedKey = decryptSymmetricKey(encryptedKey, privateKey);
// const decryptedData = decryptWebhookData(encryptedWebhookData, decryptedKey, payloadIv);
```
### Improvements
* \[**Comments**]: Improved time display in comment dialog by removing "just" from timeago text to make it more concise.
### New Features
* \[**Comments**]: Added "Seen" Feature in the comment dialog. It shows which users have seen the comments. It's automatically enabled in the default component.
* If you had previously used a wireframe for the comment dialog, you will need to add the [seen component wireframe](/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/threadcard).
![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/seen-feature.png)
* \[**Comments**]: Added a dynamic attribute to identify if the current user is the author of a comment inside the comment thread:
* Use the `velt-current-user-author` attribute to conditionally hide options for non-authors:
```css
[velt-current-user-author='false'] app-comment-dialog-thread-card-options {
display: none;
}
```
### New Features
* \[**Comments**]: Added config to restrict resolve action to admin users only:
**Using props:**
```jsx
```
**Using API:**
```javascript
const commentElement = client.getCommentElement();
// To enable resolve status access admin only
commentElement.enableResolveStatusAccessAdminOnly();
// To disable resolve status access admin only
commentElement.disableResolveStatusAccessAdminOnly();
```
**Using props:**
```html
```
**Using API:**
```javascript
const commentElement = Velt.getCommentElement();
// To enable resolve status access admin only
commentElement.enableResolveStatusAccessAdminOnly();
// To disable resolve status access admin only
commentElement.disableResolveStatusAccessAdminOnly();
```
### Improvements
* \[**Comments**]: Added ability to @mention emails not present in the contact list.
* \[**Comments**]: Implemented focus on composer when clicked anywhere within the composer.
### Improvements
* \[**Comments**]: Added "This page" label to the sidebar filters.
* \[**Comments**]: Added React wireframe component for Navigation button:
```jsx
```
```html
```
### New Features
* \[**Comments**]: Added "focused thread mode" in the comments sidebar:
* In this mode, when you click on a comment in the sidebar, it will open the thread in expanded view within the sidebar itself.
* Other threads and actions like filters, search etc are hidden behind a back button.
* Turning this on also adds a navigation button in the comment dialog. Clicking it will navigate to the comment and also trigger a callback.
* If you had previously used a wireframe for the comment dialog, you will need to add the [navigation button wireframe](/ui-customization/features/async/comments/comment-dialog/subcomponents/navigation-button) and the [focused thread wireframe](/ui-customization/features/async/comments/comments-sidebar/subcomponents/focused-thread).
```jsx
```
**Handling the navigation button click:**
```jsx
// event handler for when a comment is clicked on
const onCommentNavigationButtonClick = (event) => {
console.log('onCommentNavigationButtonClick', event);
//handle custom navigation by getting location if you have used Locations
const { pageId } = event.location;
//handle custom navigation by getting context if you have used addContext()
const { pageId } = event.context;
yourNavigateToPageMethod(pageId);
};
```
```html
```
**Handling the navigation button click:**
```javascript
const commentSidebarElement = document.querySelector('velt-comments-sidebar');
commentSidebarElement.addEventListener('onCommentNavigationButtonClick', (s) => {
console.log('onCommentNavigationButtonClick', s.detail);
});
```
* \[**Comments**]: Added standalone thread wireframe component:
```jsx
{/* Velt Comment Dialog Wireframe */}
```
```html
```
* \[**Live Selection**]: Add ability to get live selection data for the document:
**Using Hook:**
```jsx
const liveSelectionData = useLiveSelectionDataHandler();
useEffect(() => {
console.log('liveSelectionData', liveSelectionData);
}, [liveSelectionData]);
```
**Using API:**
```javascript
const selectionElement = client.getSelectionElement();
selectionElement.getLiveSelectionData().subscribe((liveSelectionData: LiveSelectionData) => {
console.log("liveSelectionData: ", liveSelectionData);
});
```
**Using API:**
```javascript
const selectionElement = Velt.getSelectionElement();
selectionElement.getLiveSelectionData().subscribe((liveSelectionData: LiveSelectionData) => {
console.log("liveSelectionData: ", liveSelectionData);
});
```
* \[**Comments**]: Added standalone `Velt Comment Text` component:
* When you put any text inside this component and provide an annotationId, it will automatically highlight the text and attach the comment to it.
```jsx
{/* your content here */}
{/* your content here */}
```
```html
```
### Improvements
* \[**Notifications**]: Changed the default maximum days for which Notifications should be displayed from 30 days to 15 days.
* \[**Notifications**]: Added complete document and organization metadata objects to the Notification metadata object.
### New Features
* \[**Live Selection**]: Added new configurations to customize the UI and behavior of the live selection feature:
* Enable/disable user indicator
* Set user indicator position
* Set user indicator type
* Enable/disable default elements tracking
* Enable/disable default styling
* Earlier the live selection was triggered on click, now it is triggered on keyboard actions as well.
* [Learn more](/realtime-collaboration/live-selection/customize-behavior).
### New Features
* \[**Comments**]: Added ability to apply custom filtering, sorting and grouping in comments sidebar.
* Here is the overview on how it works:
* Enable custom actions in the comments sidebar.
* Add action buttons to the sidebar wireframe.
* Implement callback and event handlers to handle custom filtering, sorting, and grouping logic.
* Set custom filtered data in the comments sidebar.
* [Learn more](/async-collaboration/comments-sidebar/customize-behavior#2-custom-filtering-sorting-and-grouping).
### Bug Fixes
* \[**Mentions**]: Resolved an issue where `atHereDescription` was not rendering for non-organization users.
### New Features
* \[**Notifications**]: Added API to mark a single notification as read by notificationId.
```javascript
const notificationElement = client.getNotificationElement();
notificationElement.markNotificationAsReadById("notificationId");
```
```javascript
const notificationElement = Velt.getNotificationElement();
notificationElement.markNotificationAsReadById("notificationId");
```
* \[**Debugger**]: Added call to `setDocument` method to the debugger.
### Improvements
* \[**Mentions**]: Added `atHereDescription` to the `description` field of the @mention data object.
### Bug Fixes
* \[**Notifications**]: Fixed an issue where the "For You" tab was not displaying the updated document name on initial load.
### New Features
* \[**Mentions**]: Added styling for @mention in the composer when adding or editing a comment.
### Improvements
* \[**React Hooks**]: Updated client and comment related hooks to support dynamic input values.
### Bug Fixes
* \[**Mentions**]: Fixed an issue in the `updateContactList` API where the passed contact list data was being mutated directly.
* \[**Mentions**]: Resolved an issue where @mentions with special characters were not working correctly.
### Bug Fixes
* \[**Notifications**]: Fixed an issue where the `unreadCommentsMap` count was not updating correctly when switching between documents with no unread comments.
### New Features
* \[**Comments**]: Added shadowDOM, dark mode, and variant support in standalone Comment Thread component.
```jsx
```
```html
```
### Bug Fixes
* \[**Comments**]: Fixed an issue where scroll was causing the "Add reply" button to hide.
* \[**Comments**]: Fixed an issue where the assign to dialog was not closing after assigning a user using the keyboard.
### Bug Fixes
* \[**Notifications**]: Fixed an issue where the `document` tab was not visible when user email was not set.
### New Features
* \[**Comments**]: Added support for overlay text commenting in Tiptap editor.
* It works with all frontend frameworks that are supported by Tiptap.
* You can find the extension [here](https://www.npmjs.com/package/@veltdev/tiptap-velt-comments).
```bash
npm i @veltdev/tiptap-velt-comments
```
```javascript
import { TiptapVeltComments } from '@veltdev/tiptap-velt-comments';
const editor = new Editor({
extensions: [
TiptapVeltComments,
// ... other extensions
],
});
```
* Call this method to add a comment to selected text in the Tiptap editor. You can use this when the user clicks on the comment button in context menu or presses a keyboard shortcut.
* Args:
* `editor`: instance of the Tiptap editor.
* `tiptapVeltCommentConfig`: optional object to set the Comment Annotation's custom metadata.
* Example:
```javascript
import { addTiptapVeltComment } from '@veltdev/tiptap-velt-comments';
addTiptapVeltComment(editor, tiptapVeltCommentConfig);
```
### Improvements
* \[**Console Debugger**]: Added logs for the `updateContactList` method to improve debugging.
### Improvements
* \[**Console Debugger**]: Added logs for `addContext` and `updateContext` methods. The context object is now included in the log event properties for better debugging and tracking.
* \[**Comments**]: Now comments will be marked as read if opened via the `selectCommentByAnnotationId()` API.
### Bug Fixes
* \[**Comment Display**]: Improved comment rendering performance for Comments Sidebar.
### New Features
* \[**Comments Sidebar**]: Added a reset filter button to easily clear all applied filters.
* This new button allows users to quickly reset all filters in the comments sidebar when no comments are available for the applied filters.
* Here is the wireframe for the reset filter button:
```jsx
```
```html
```
### Improvements
* \[**Notifications**]: Improved loading state for API calls, now returns null until data is fully loaded.
### New Features
* \[**Notifications**]: Added API to get unread notifications count.
* **Sample response:**
```javascript
{
forYou: 4, // # of unread notifications in the "For You" tab
all: 5 // # of unread notifications in the "All" or "Document" tab
}
```
Using Hooks:
```jsx
const unreadCount = useUnreadNotificationsCount();
useEffect(() => {
console.log('Unread Count', unreadCount);
}, [unreadCount]);
```
Using API:
```javascript
const notificationElement = client.getNotificationElement();
notificationElement.getUnreadNotificationsCount().subscribe((data) => {
console.log('Unread notifications count:', data);
});
```
```javascript
const notificationElement = Velt.getNotificationElement();
notificationElement.getUnreadNotificationsCount().subscribe((data) => {
console.log('Unread notifications count:', data);
});
```
### Improvements
* \[**Comments**]: Improved search functionality in @mentions to support spaces in search queries.
### New Features
* \[**Comments**]: Added ability to control whether comments inside the annotation should be collapsed.
Using Props:
```jsx
```
Using API:
```javascript
const commentElement = client.getCommentElement();
commentElement.enableCollapsedComments();
commentElement.disableCollapsedComments();
```
Using Props:
```html
```
Using API:
```javascript
const commentElement = Velt.getCommentElement();
commentElement.enableCollapsedComments();
commentElement.disableCollapsedComments();
```
* \[**Comments**]: Added ability to get comment annotation by ID.
Using Hooks:
```jsx
const annotation = useCommentAnnotationById({
annotationId: '-O6W3jD0Lz3rxuDuqQFx', // AnnotationID
documentId: 'document-id' // DocumentId (Optional)
});
React.useEffect(() => {
console.log('annotation', annotation);
}, [annotation]);
```
Using API:
```javascript
const commentElement = client.getCommentElement();
commentElement.getCommentAnnotationById({
annotationId: '-O6W3jD0Lz3rxuDuqQFx', // AnnotationID
documentId: 'document-id' // DocumentId (Optional)
}).subscribe((annotation) => {
console.log('annotation', annotation);
});
```
Using API:
```javascript
const commentElement = Velt.getCommentElement();
commentElement.getCommentAnnotationById({
annotationId: '-O6W3jD0Lz3rxuDuqQFx', // AnnotationID
documentId: 'document-id' // DocumentId (Optional)
}).subscribe((annotation) => {
console.log('annotation', annotation);
});
```
* \[**Notifications**]: Added API to mark all notifications as read.
* Mark all notifications as read, either globally or for a specific tab.
* Using 'all' or 'document' as the `tabId` marks all notifications as read across all tabs (equivalent to calling `setAllNotificationsAsRead()` without arguments).
* Using 'for-you' as the `tabId` only marks notifications in the 'for-you' tab as read.
```javascript
const notificationElement = client.getNotificationElement();
// Mark all notifications as read
notificationElement.setAllNotificationsAsRead();
// Mark all notifications as read for a specific tab
notificationElement.setAllNotificationsAsRead({ tabId: 'for-you' });
notificationElement.setAllNotificationsAsRead({ tabId: 'all' });
notificationElement.setAllNotificationsAsRead({ tabId: 'document' });
```
```javascript
const notificationElement = Velt.getNotificationElement();
// Mark all notifications as read
notificationElement.setAllNotificationsAsRead();
// Mark all notifications as read for a specific tab
notificationElement.setAllNotificationsAsRead({ tabId: 'for-you' });
notificationElement.setAllNotificationsAsRead({ tabId: 'all' });
notificationElement.setAllNotificationsAsRead({ tabId: 'document' });
```
### Bug Fixes
* \[**UI Customization**]: Fixed an issue in `velt if` where string comparisions were not working as expected.
### New Features
* \[**Comments**]: Added a reset filter button wireframe in multithread comment dialog.
* \[**Notifications**]: Added a notifications panel loading state skeleton with wireframes.
```javascript
```
```html
```
### Bug Fixes
* \[**Comments**]: Fixed an issue where draft comments were not being saved for multithread comments in some cases.
* \[**Comments**]: Fixed an issue where in inline mode, when editing a comment, the annotation was not being selected.
### New Features
* \[**Comments**]: Added a prop to enable confirmation before deleting a reply.
Using Props:
```jsx
```
Using API:
```javascript
const commentElement = client.getCommentElement();
commentElement.enableDeleteReplyConfirmation();
commentElement.disableDeleteReplyConfirmation();
```
Using Props:
```html
```
Using API:
```javascript
const commentElement = Velt.getCommentElement();
commentElement.enableDeleteReplyConfirmation();
commentElement.disableDeleteReplyConfirmation();
```
* \[**Comments**]: Added a callback method for when a comment link is copied. You can use this to track when a comment link is copied or show a confirmation toast.
Using Hooks:
```jsx
const commentLink = useCommentCopyLinkHandler();
useEffect(() => {
console.log('commentLink', commentLink);
}, [commentLink]);
```
Using API:
```jsx
const commentElement = client.getCommentElement();
commentElement.onCopyLink().subscribe((commentLink) => {
console.log(commentLink);
});
```
Using API:
```jsx
const commentElement = client.getCommentElement();
commentElement.onCopyLink().subscribe((commentLink) => {
console.log(commentLink);
});
```
Using API:
```javascript
const commentElement = Velt.getCommentElement();
commentElement.onCopyLink().subscribe((commentLink) => {
console.log(commentLink);
});
```
* \[**Comments**]: Added a minimal Actions Dropdown in Multithread comment dialog. It contains actions like 'Mark all as read', 'Mark all as resolved'.
### Improvements
* \[**UI Customization**]: Renamed the `velt data` prop to `field` (old: `path`) to improve readability. This is backward compatible.
```jsx
```
```jsx
```
### Improvements
* \[**Comments**]: Renamed `multiThreadMode` prop to `multiThread` for improved clarity and consistency.
* \[**Comments**]: Removed the "0 comments" from the multithread container header, when the first thread is created.
* \[**Comments**]: The comment pin bubble count in multithread mode would sync with the number of unresolved comments in the multithread container.
* \[**Comments**]: Added an unread indicator on the comment pin bubble in multithread mode to help users quickly identify new or unread comments.
* \[**UI Customization**]: Added improvements to the `velt if` conditional rendering logic.
### Bug Fixes
* \[**Comments**]: Fixed an issue where the menu trigger button would hide when the mouse moved on the menu.
* \[**Notifications**]: Resolved an issue where `documentName` wasn't displayed on the notification item in the notification panel.
### Bug Fixes
* \[**Comments**]: Fixed an issue where the composer would throw a console error on Firefox. This didn't have any impact on functionality or UX.
* \[**Comments**]: Fixed reply button toggle issue.
### Improvements
* \[**Comments**]: Improvements to the comments UX in multithread mode.
### Bug Fixes
* \[**Comments**]: Fixed an issue where sign in button was showing up for logged in users on mobile. This only impacted customers where signIn button was enabled.
### New Features
* \[**Webhooks**]: Added configuration option for base64 encoding of webhook payloads (disabled by default).
* Addresses issues with payloads containing HTML tags that may fail due to strict endpoint policies.
* Ensures payload validity and processability by your endpoint.
* Example of decoding a base64 encoded payload:
```js
const encodedData="eyJ0ZXN0IjoxLCJ0ZXN0MSI6IjxkaXY+PC9kaXY+In0="
const decodedData = Buffer.from(encodedData, 'base64').toString('utf-8');
console.log(JSON.parse(decodedData));
```
### Improvements
* \[**Comments**]: Significant enhancements to the comments UX in multithread mode:
* Implemented smooth auto-scroll animation to new threads for improved visibility
* Added a new comment button to the header for easier thread creation
* Refined composer show/hide logic for a more intuitive user experience
* Shortened the displayed timestamp format
* \[**Comments**]: Improved the UI for [custom autocomplete dropdown chip](async-collaboration/comments/customize-behavior/custom-lists#2-add-custom-lists-on-comment).
* \[**Notifications**]: Notifications feature and API no longer require documentId to be set for initialization.
### Bug Fixes
* \[**Comments**]: Fixed an issue where the custom autocomplete chip would fail to render if the same chip is added multiple times.
### Bug Fixes
* \[**Comments**]: Fixed a bug where clicking on one's own reaction on the [Velt Comment Player Timeline](/async-collaboration/comments/setup/video-player-setup/custom-video-player-setup) didn't toggle it correctly.
### Improvements
* \[**Comments**]: Added `createdAt` field for [CommentAnnotation](/api-reference/models/CommentAnnotation) model. This can now be used to sort annotations in ascending order of creation.
* \[**Comments**]: Added `isEdited` and `editedAt` fields in [Comment](/api-reference/models/Comment) model. This can now used to indicate if and when a comment is edited.
* \[**Comments**]: In multithread mode, the count on the header is now synced with the total threads visible after all the fitlers are applied.
* \[**Comments**]: Inline and multi-thread comments are now sorted in ascending order by the `createdAt` field, maintaining backward compatibility.
* \[**Comments**]: Improved the behavior where the mutlthread container was auto-closing when one of the threads was deleted or resolved.
### Bug Fixes
* \[**Comments**]: Fixed a bug where deleting a recording in a single-comment thread incorrectly triggered the Delete Thread dialog.
* \[**Comments**]: Fixed a bug where resolved comment threads weren't disappearing in [inline comment mode](/async-collaboration/comments/setup/inline-comments).
### New Features
* \[**Notifications**]: Added a configurable option to show read notifications in the "For You" tab. By default, read notifications are removed from the "For You" tab.
Using Props:
```jsx
```
Using APIs:
```jsx
const notificationElement = useNotificationUtils();
// Enable to keep read notifications in the for you tab
notificationElement.enableReadNotificationsOnForYouTab();
// Disable to hide read notifications in the for you tab
notificationElement.disableReadNotificationsOnForYouTab();
```
Using Props:
```jsx
```
Using APIs:
```jsx
const notificationElement = client.getNotificationElement();
// Enable to keep read notifications in the for you tab
notificationElement.enableReadNotificationsOnForYouTab();
// Disable to hide read notifications in the for you tab
notificationElement.disableReadNotificationsOnForYouTab();
```
Using Props:
```html
```
Using API:
```html
```
For more details on customizing notifications behavior, refer to the [Notifications Behavior](/async-collaboration/notifications/customize-behavior) section.
### Improvements
* \[**REST API**]: Added advanced querying and pagination on REST APIs for improved performance and functionality.
* \[**Comments**]: Made the rendering of comment dialog action buttons configurable via CSS on hover or selection.
### Bug Fixes
* \[**Comments**]: Resolved a rare bug where the triangle pin component would cause the comment dialog to flicker on hover in popover comment mode.
* \[**Autocomplete dropdowns**]: Fixed a bug where the autocomplete dropdown component would not apply the `--velt-default-font-family`.
* \[**Notifications**]: Fixed a bug occurring when marking all notifications as read in large notification data sets.
### New Features
* \[**Comments**]: Added a standalone Comment Composer component. Now you can use this in combination with [Velt Comment Threads](/async-collaboration/comments/standalone-components/comment-thread/overview) component to embed commenting experiences in custom ways.
```jsx
```
```html
```
* \[**Inline Comments**]: Added single thread option to inline comments. By default, it will be in multithread mode.
Default value: `true`
```jsx
```
```html
```
### New Features
* \[**Comments**]: Added a new prop to control the use of ShadowDOM for [Persistent Comment Mode](/async-collaboration/comments/customize-behavior/modes#persistent-comment-mode) banner.
```jsx
```
```html
```
### Improvements
* \[**Comments**]: Action buttons are now consistently displayed across all states (default, hover, selection) of the comment dialog and can be customized via CSS alone.
### Bug Fixes
* \[**Notifications**]: Fixed an issue where the `tabConfig` React props was not working as expected.
### Improvements
* \[**Notifications**]: Added an empty state for the document and all tabs in the notification panel.
* \[**Notifications**]: Added type definition for the `tabConfig` prop to improve TypeScript support.
### Bug Fixes
* \[**Notifications**]: Fixed an issue where React props for customizing the notification panel were not working as expected.
### New Features
* \[**Comments**]: Added a new `atHereDescription` prop to customize the description that appears for the @here mention.
Using Props:
```jsx
```
Using API Method:
```jsx
const contactElement = useContactUtils();
useEffect(() => {
contactElement.setAtHereDescription('Notify all users in this document');
}, [contactElement]);
```
Using Props:
```jsx
```
Using API Method:
```jsx
const contactElement = client.getContactElement();
contactElement.setAtHereDescription('Notify all users in this document');
```
Using Props:
```html
```
Using API Method:
```javascript
const contactElement = Velt.getContactElement();
contactElement.setAtHereDescription('Notify all users in this document');
```
* \[**Comments**]: Added the `getSelectedComments()` API to get the currently selected comment annotations.
* This returns an array of [`CommentAnnotation`](/api-reference/models/CommentAnnotation) objects.
```jsx
const commentElement = client.getCommentElement();
const subscription = commentElement.getSelectedComments().subscribe((selectedComments) => {
console.log('Selected comments:', selectedComments);
});
```
Unsubscribe from the subscription when you're done:
```jsx
subscription?.unsubscribe()
```
```js
const commentElement = Velt.getCommentElement();
const subscription = commentElement.getSelectedComments().subscribe((selectedComments) => {
console.log('Selected comments:', selectedComments);
});
```
Unsubscribe from the subscription when you're done:
```js
subscription?.unsubscribe()
```
### Bug Fixes
* \[**Comments**]: Fixed an issue where the [custom list](/async-collaboration/comments/customize-behavior/custom-lists#1-add-custom-lists-on-comment-annotation) chip tooltip icon was not displayed.
* \[**Comments**]: Fixed an issue where the reaction tooltip in the [comment player timeline component](/async-collaboration/comments/setup/video-player-setup/custom-video-player-setup) was getting distorted on hover.
* \[**Comments**]: Fixed an issue where the reaction bubble on the [comment player timeline component](/async-collaboration/comments/setup/video-player-setup/custom-video-player-setup) had a transparent background.
### New Features
* \[**Comments**]: Added a Minimal Filter Dropdown Component for the Multithread Comment Dialog. This provides basic filtering and sorting options, including:
* Sorting: by date, by unread status
* Filtering: unread comments, read comments, resolved comments
### Improvements
* \[**Comments**]: Updated multithread behavior to ensure only one composer is open at a time.
### Bug Fixes
* \[**Comments**]: Fixed an issue where the Floating Mode Comment Sidebar would not close when clicked outside.
* \[**Comments**]: Resolved a problem where sidebar dropdowns were not closing when clicked on the trigger button again.
* \[**Comments**]: Fixed an issue where the Add Reply button wasn't working in Inline Comment Section.
### Bug Fixes
* \[**Comments**]: Fixed a bug related to updating comment annotations.
### New Features
* \[**Comments**]: Added Draft State:
* Empty comments are no longer saved.
* Partial comments are saved as drafts, visible only to the author.
* Draft creation:
* Comment is saved as draft when the user adds text, recording, or attachment and closes the comment dialog without submitting.
* On first attempt to close: Dialog shakes to indicate draft status.
* On second attempt: the comment is saved as draft and the dialog closes.
* Added a visual indicator for draft comments in the dialog.
* If you had previously used a wireframe for the comment dialog, you will need to add the [draft wireframe](/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/threadcard).
### Improvements
* \[**UI Customization**]: Refactored `velt if` and `velt data` logic for improved performance.
### New Features
* \[**Comments**]: Added Draft State:
* Empty comments are no longer saved.
* Partial comments are saved as drafts, visible only to the author.
* Draft creation:
* Comment is saved as draft when the user adds text, recording, or attachment and closes the comment dialog without submitting.
* On first attempt to close: Dialog shakes to indicate draft status.
* On second attempt: the comment is saved as draft and the dialog closes.
* Added a visual indicator for draft comments in the dialog.
* If you had previously used a wireframe for the comment dialog, you will need to add the [draft wireframe](/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/threadcard).
### New Features
* \[**UI Customization**]: Added **Conditional Templates**! These let you conditionally show or hide parts of the Velt Component Wireframes.
* You can add conditions based on the same data models available in [Template Variables](/ui-customization/template-variables).
```jsx
{/* Content to render if condition is true */}
```
```html
```
* \[**UI Customization**]: You can now customize confirmation dialogs (eg: Delete thread, Delete recorder etc) for each feature by defining variants.
* Supported variants: `recorder`, `comment`, `arrow`, `area`.
```jsx
Custom Title
Custom Message
Custom Reject Button
Custom Approve Button
```
```html
Custom Title
Custom Message
Custom Reject Button
Custom Approve Button
```
* \[**UI Customization**]: Added two new global [Template Variables](/ui-customization/template-variables):
* `unreadCommentAnnotationCount`: Number of unread comment annotations on the current document.
* `unreadCommentCount`: Total number of unread comments on the current document.
* \[**Comments**]: Added `updateContext` method for updating custom metadata (`context`) on comment annotations. [Learn more](/async-collaboration/comments/customize-behavior/custom-metadata#2-update-custom-metadata-on-comment-annotation). This method is available in two scenarios:
1. **In the `onCommentUpdate` event callback:**
Use this to update the context when a comment is modified.
2. **Via the `updateContext` API method:**
Utilize this method to update the context of a comment annotation at any time. For example, you might use this when the name of the dashboard containing the comment annotation changes.
### Improvements
* \[**Comments**]: Updated the icon for the Unresolve button.
* \[**Comments**]: Whenever the comment sidebar is opened using the button or the api, any open comment dialog will be closed.
* \[**Comments**]: Made position of the reaction tool consistent across different states and content types in the comment dialog.
### Bug Fixes
* \[**Comments**]: Fixed the flicker issue when new popover comment thread was created. This only happened when the triangle component was disabled.
* \[**Comments**]: Fixed minor rendering issue with the @mention chip when it was added at the end of the content.
* \[**Velt Components**]: Reduced the default z-index for all Velt Components to prevent them from going over the host app's header or any other important UI elements.
* \[**Comments**]: Fixed menu overlay positioning to stay with its trigger during page scrolling.
### Bug Fixes
* \[**Comments**]: Reverted comment sidebar button wireframe changes.
### New Features
* \[**Inline Reactions**]: Added `customReactions` prop for `VeltInlineReactionsSection` component in React, allowing custom emoji definitions:
```jsx
const customReactions = {
"EMOJI_ID_1": {
"emoji": "🔥" // You could also set emoji using a url or raw svg definition
},
"EMOJI_ID_2": {
"emoji": "🙌" // You could also set emoji using a url or raw svg definition
},
"EMOJI_ID_3": {
"emoji": "💪" // You could also set emoji using a url or raw svg definition
}
}
```
* \[**Comments**]: Added `multiThreadMode` prop for `VeltComments` component in React:
```jsx
```
### Improvements
* \[**Comments**]: Updated the unresolved button icon for better understanding.
* \[**Comments**]: Added types for `enableMultiThreadMode` and `disableMultiThreadMode` API methods.
### New Features
* \[**Comments**]: Added multi-thread support for Comments:
Using Props:
```html
```
Using API Method:
```javascript
const commentElement = Velt.getCommentElement();
// To enable multi-thread mode
commentElement.enableMultiThreadMode();
// To disable multi-thread mode
commentElement.disableMultiThreadMode();
```
* \[**Inline Reactions**]: Added ability to add list of custom reactions:
Using API Method:
```javascript
const reactionElement = client.getReactionElement();
const customReactions = {
"EMOJI_ID_1": {
"emoji": "🔥" // You could also set emoji using a url or raw svg definition
},
"EMOJI_ID_2": {
"emoji": "🙌" // You could also set emoji using a url or raw svg definition
},
"EMOJI_ID_3": {
"emoji": "💪" // You could also set emoji using a url or raw svg definition
}
};
reactionElement.setCustomReactions(customReactions);
```
* \[**UI Customization**]: Added wireframe for MultiThreaded Comment Dialog.
* \[**UI Customization**]: Added wireframe for Comment Sidebar Button with the new name.
### Improvements
* \[**Comments**]: Made element binding consistent by using common `targetElementId` attribute in comment feature components:
```jsx
```
```html
```
### Bug Fixes
* \[**Notifications**]: Fixed an issue where unread icon was not showing up when a comment was added by the user themselves.
* \[**Notifications**]: Resolved a UI issue where the "All Read" container was showing up while the data was still loading.
* \[**Notifications**]: Fixed the load more button on all notifications tabs.
* \[**Notifications**]: Fixed an issue where using the "assign to" options from the thread options menu wasn't generating a notification.
* \[**Recorder**]: Fixed an issue where recording was saved when minimizing the preview panel.
### Improvements
* \[**Comments**]: Pass the `id` attribute on either the `
### New Features
* \[**Comments**]: Added an "Unresolve Comment" button component in the comment dialog. This button is used to unresolve a comment that was previously marked as resolved.
```jsx
```
```html
```
### Improvements
* \[**Comments**]: Improved comment text handling by trimming whitespace from `commentText` and `commentHtml` in the comment dialog.
### Bug Fixes
* \[**Comments**]: Fixed an issue with autocomplete chip shadowDOM not being updated.
* \[**Notifications**]: Resolved an issue where documents with empty notifications were still being rendered.
* \[**Users**]: Fixed a bug related to special characters in user names.
* \[**Comments**]: Fixed an issue where the checkbox in the location filter dropdown in sidebar wasn't updating on selection.
* \[**Comments**]: Fixed an issue where the status filter menu in the sidebar wasn't closing properly.
* \[**Recorder**]: Resolved a problem where the device list wasn't updating correctly in the recording settings menu in certain scenarios.
### New Features
* \[**Comments**]: Added a minimal location filter in the sidebar wireframe for basic location based filtering. By default it's not enabled. You need to explicitly add the wireframe to the sidebar.
* \[**Sidebar**]: Added `Floating Mode` for Comments Sidebar. This allows the sidebar panel to appear as an overlay on top of the sidebar button when clicked.
```jsx
```
```html
```
### Bug Fixes
* \[**Comments**]: Fixed a bug where clicking the "replies" button in the sidebar comment dialog incorrectly opened the comment dialog on the DOM. This issue only affected implementations using the sidebar comment dialog wireframe.
### New Features
* \[**Comments**]: Added persistent comment mode banner wireframe.
* \[**API**]: Added `getDocumentMetadata` method to get the current document's metadata. It returns a subscription with [`DocumentMetadata`](/api-reference/models/DocumentMetadata) object.
```javascript
client.getDocumentMetadata().subscribe((documentMetadata) => {
console.log("Current document metadata: ", documentMetadata);
});
```
```js
Velt.getDocumentMetadata().subscribe((documentMetadata) => {
console.log("Current document metadata: ", documentMetadata);
});
```
### Improvements
* \[**Comments**]: The persistent comment banner now inherits the shadow DOM property from `Velt Comments`.
### New Features
* \[**Comments**]: Added a minimal filtering and sorting dropdown in the sidebar wireframe. By default it's not enabled. You need to explicitly add the wireframe to the sidebar. It includes options like:
* Filter by `All`
* Filter by `Unread`
* Filter by `Read`
* Filter by `Resolved`
* Sort by `Unread`
* Sort by `Last Updated Timestamp`
### Bug Fixes
* \[**Comments**]: Fixed an issue where the dialog was overflowing out of the screen in some cases.
### New Features
* \[**Reactions**]: Added [inline reaction section](/async-collaboration/reactions/setup) feature component.
```jsx
```
```html
```
### Improvements
* \[**Comments**]: Truncated video timeline comment card to 100 characters for improved readability.
* \[**Users**]: Limited user names to a maximum of 20 characters and disallowed URLs in names for security purposes.
### Bug Fixes
* \[**Comments**]: Resolved an issue with the unread indicator in the comment dialog.
### New Features
* \[**Comments**]: Added feature to render a comment bubble on the comment pin or triangle instead of the comment dialog. Hovering or clicking the bubble will open the comment dialog.
* `bubbleOnPin`: Whether to show bubble on pin \[default: false]
* `bubbleOnPinHover`: If the above is true, whether to show bubble when the pin is hovered over or clicked \[default: true]
Using Props:
```jsx
```
Using API:
```javascript
const commentElement = client.getCommentElement();
// To enable showing bubble on pin
commentElement.enableBubbleOnPin();
// To disable showing bubble on pin
commentElement.disableBubbleOnPin();
// To enable option to show bubble on pin hover vs only on click
commentElement.enableBubbleOnPinHover();
// To disable option to show bubble on pin hover
commentElement.disableBubbleOnPinHover();
```
Using Props:
```html
```
Using API:
```javascript
const commentElement = Velt.getCommentElement();
// To enable showing bubble on pin
commentElement.enableBubbleOnPin();
// To disable showing bubble on pin
commentElement.disableBubbleOnPin();
// To enable option to show bubble on pin hover vs only on click
commentElement.enableBubbleOnPinHover();
// To disable option to show bubble on pin hover
commentElement.disableBubbleOnPinHover();
```
### Improvements
* \[**Comments**]: Increased the max allowed size of attachments in composer from 2MB to 15MB.
* \[**Comments**]: Decreased the size of triangle in comment pin from 15px to 10px.
### Bug Fixes
* \[**Comments**]: Fixed an issue where the comment dialog composer user avatar wireframe was not working.
* \[**Comments**]: Resolved minor signal-related issues.
* \[**Comments**]: Fixed Comment Dialog Attachments and Recording UI for inline comment mode, addressing aspect ratio issues.
### Improvements
* \[**Performance**]: Rewrote change detection and state management for the entire SDK to make it more performant. This is a major update and will benefit all developers.
# null
## Versions
* Latest SDK: [1.0.107](https://www.npmjs.com/package/@veltdev/react)
* Latest Types: [1.0.119](https://www.npmjs.com/package/@veltdev/types)
## Method to Hide Comments from Users on specific Locations
The [client.excludeLocationIds()](https://docs.velt.dev/async-collaboration/comments/customize-behavior/general-controls) method can be used to hide `Comments` at specific `Locations` from `Users`.
```jsx
const locationIds = ['location1', 'location2']; // list of location ids
client.excludeLocationIds(locationIds);
```
## Configuration to Disable Recording Summaries
If you want to [disable the Recording summaries](https://docs.velt.dev/async-collaboration/comments/customize-behavior/multimedia) that appear when you record you audio, voice or screen, you can can now do so.
Example:
```jsx
```
API Methods:
```jsx
const commentElement = client.getCommentElement();
// to show recording summary
commentElement.enableRecordingSummary();
// to hide recording summary
commentElement.disableRecordingSummary();
```
## Configuration to Disable Recording countdown
If you want to [disable the countdown](https://docs.velt.dev/async-collaboration/comments/customize-behavior/multimedia) that appears when you begin recording your audio, voice, or screen, you can now do so. When the countdown is disabled, recordings will begin instantly.
Example
```jsx
```
API Methods:
```jsx
// API method - comment element
const commentElement = client.getCommentElement();
// To enable recording countdown
commentElement.enableRecordingCountdown();
// To disable recording countdown
commentElement.disableRecordingCountdown();
// API method - recorder element
const recorderElement = client.getRecorderElement();
// To enable recording countdown
recorderElement.enableRecordingCountdown();
// To disable recording countdown
recorderElement.disableRecordingCountdown();
```
## Method to Remove the Document ID
You can now unset the `Document Id` to pause the Velt SDK functions.
```jsx
client.unsetDocumentId()
```
## More File Type Support in Comment attachments
We've added support for more file types in `Comment` attachments (`csv`, `docx`, `pptx`, `xlsx`, `webp`, `mp4` etc.).
# null
## Versions
* Latest SDK: [1.0.112](https://www.npmjs.com/package/@veltdev/react)
* Latest Types: [1.0.127](https://www.npmjs.com/package/@veltdev/types)
## Option to Disable ShadowDOM
We've added an option for you to [disable the ShadowDOM on certain components](https://docs.velt.dev/async-collaboration/comments/customize-behavior/ui-controls).
By default, a ShadowDOM is used with certain components to ensure that your application's CSS does not interfere with the styling of the SDK components.
If you want your application's CSS to affect the styling of the SDK components, you can disable the ShadowDOM.
```jsx
```
API methods:
```jsx
const commentElement = client.getCommentElement();
commentElement.enablePinShadowDOM();
commentElement.disablePinShadowDOM();
commentElement.enableDialogShadowDOM();
commentElement.disableDialogShadowDOM();
commentElement.enableSidebarShadowDOM();
commentElement.disableSidebarShadowDOM();
```
## Method to Unsubscribe from Subscriptions
We added an `unsubscribe()` method to unsubscribe from any event subscriptions.
Example subscription:
```jsx
let subscription = commentElement.getAllCommentAnnotations().subscribe((comments) => {
// Do something with comments
});
```
To unsubscribe from the subscription:
```jsx
subscription?.unsubscribe()
```
## Added webhook notifications for `Huddle` Create and Join Events
Your users will now receive [webhook notifications](https://docs.velt.dev/webhooks/huddle-webhooks) when a `Huddle` is created or joined.
Example notification schema:
```jsx
{
"from": {
// UserObject
},
"projectName": "string",
"projectUrl": "string",
"actionType": "string", // created | joined
"notificationSource": "huddle",
"documentId": "string",
"clientDocumentId": "string",
"id": "string",
"timestamp": 1234567890,
"actionUser": {
// UserObject
},
}
```
Click here to see the [Notification](https://docs.velt.dev/api-reference/models/Notification) schema.
## Added Validations to check for Audio and Video permissions on `Huddles`
Your users will now be prompted to check for Audio and Video permissions on `Huddles`
## Option to disable `Chat` feature on `Huddles`
You can now [disable the Chat feature](https://docs.velt.dev/realtime-collaboration/huddle/customize-behavior) that is enabled by default on `Huddle` component.
## Option to disable `flockMode` feature on `Huddles`
You can now [disable the flockMode feature](https://docs.velt.dev/realtime-collaboration/huddle/customize-behavior) that is enabled by default on `Huddle` component when clicking on another user's Avatar.
## Added support to set a custom order of locations to sort by in the `Comments Sidebar`.
You can now define the [order in which locations appear](https://docs.velt.dev/async-collaboration/comments-sidebar/customize-behavior) in the `Comments Sidebar` filter through the 'order' field in the `filterConfig` object.
```jsx
```
## Added configuration for Unread Comments Indicator
You can now configure the [Unread Comments Indicator](https://docs.velt.dev/async-collaboration/comments/customize-behavior/display-metadata) to be either `minimal` or `verbose`.
In `minimal` mode unread comments will be indicated by a small red dot.
In `verbose` mode unread comments will be indicated by a larger badge that says UNREAD
![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/verbose-mode-comments.png)
## Added hook for `useUnsetDocumentId`
There is now a hook called [useUnsetDocumentId()](https://docs.velt.dev/api-reference/hooks/hooks#useunsetdocumentid) that calls [client.unsetDocumentId()](https://docs.velt.dev/api-reference/api-methods/velt-client)
```jsx
import { useUnsetDocumentId} from '@veltdev/react'
import React from 'react'
export default function YourComponent() {
useUnsetDocumentId();
return (
...
)
}
```
## Added option to use a specific version of the Velt React SDK.
You can now use a [specific version of the Velt React SDK](https://docs.velt.dev/get-started/setup/advanced).
To do so, in your `VeltProvider` component, set the `config` props object to `{ version: '1.0.XYZ' }`.
Example:
```jsx
...
```
# null
# 2.0.30
### New Features
* \[**Comments**]: Added `resolvedByUserId` field on comment resolve. This allows tracking which user resolved a comment thread.
* \[**Comments**]: Added a configuration on sidebar to open the filter panel as a bottom sheet (default) or overlap on the filter button.
* Prop: `filterPanelLayout`. Values: `'menu' | 'bottomSheet'` (default)
* Usage:
```jsx
```
```html
```
# null
# 2.0.31
### New Features
* \[**UI Customization**]: Added [Confirm Dialog Wireframe](/ui-customization/features/async/comments/confirm-dialog/overview) and added support for light and dark modes.
* This is a common UI component used for multiple features like deleting comment thread, deleting a recorded content and more.
* It will automatically inherit the light or dark mode property from the parent feature.
# null
# 2.0.33
### New Features
* \[**UI Customization**]: Added conditional dynamic classes for different states of various interactive components:
* `velt-sidebar-tool-open`: For the sidebar button when the sidebar is open.
* `velt-notification-tool-open`: For the notification tool when the notification panel is open.
* `velt-comments-sidebar-status-open`: For the status dropdown trigger when the dropdown is open.
* `velt-comments-sidebar-filter-button-open`: For the filter button when the filter panel is open.
### Bug Fixes
* \[**Comments**]: Fixed an issue where after adding '@here' the cursor position was incorrectly placed at the start of the text.
# 2.0.32
### New Features
* \[**UI Customization**]: Added conditional classes for different states of various interactive components:
* `velt-comment-pin-open`: For the comment pin when the pin is selected.
* `velt-dropdown-open`: For the dropdown trigger when the dropdown is open.
* `velt-assign-dropdown-open`: For the assign dropdown trigger when the dropdown is open.
* `velt-custom-dropdown-open`: For the custom dropdown trigger when the dropdown is open.
* `velt-options-dropdown-open`: For the options dropdown trigger when the dropdown is open.
* `velt-priority-dropdown-open`: For the priority dropdown trigger when the dropdown is open.
* `velt-status-dropdown-open`: For the status dropdown trigger when the dropdown is open.
* `velt-reaction-tool-open`: For the reaction tool when the tool is open.
* `velt-comment-bubble-open`: For the comment bubble when the bubble is selected.
* `velt-comment-bubble-hover`: For the comment bubble when the bubble is hovered over.
* \[**Comments**]: Added configuration for customizing the '@here' mention label. eg: @all, @everyone, @team, etc:
Using Props:
```jsx
```
Using API:
```javascript
const contactElement = client.getContactElement();
contactElement.setAtHereLabel('@all');
```
Using Props:
```html
```
Using API:
```javascript
const contactElement = Velt.getContactElement();
contactElement.setAtHereLabel('@all');
```
### Improvements
* \[**Notifications**]: Various UI improvements on the notification panel.
### Bug Fixes
* \[**Comments**]: Fixed a bug where email contacts could have an invalid character ('.') at the end.
* \[**Comments**]: Resolved an issue where the comment sidebar filter wouldn't be sticky on page refresh.
* \[**Debugger**]: Fixed typo with event name `commentMoreReplayOptionClicked` and updated it to `commentMoreReplyOptionClicked`.
# null
# 2.0.35
### Improvements
* \[**Comments**]: Added dynamic `velt-composer-input-focused` class on the composer container whenever the input is focused.
This provides more control over the styling of the composer input when it is focused.
# 2.0.34
### Improvements
* \[**Comments**]: Added dynamic `velt-composer-open` class on the composer container whenever the composer is opened.
* \[**Comments**]: Improved contact and reaction tooltips:
* Inherited shadow DOM property from parent's shadow DOM property.
* Added light mode and dark mode support.
### Bug Fixes
* \[**Comments**]: Fixed user avatar background color in autocomplete chip tooltip to match the color assigned to the user in the SDK.
# null
# 2.0.39
### Bug Fixes
* \[**Comments**]: Fixed a css padding issue related to the action buttons in the comment dialog composer.
# 2.0.38
## Bug Fixes
* \[**Comments**]: Fixed an issue with the user-avatar component, ensuring it's consistently used across all the components.
# 2.0.37
### New Features
* \[**Comments**]: Added the ability to exclude specific location IDs from the comments sidebar. This provides more control over the displayed content.
Using Props:
```jsx
```
Using API:
```jsx
const commentElement = client.getCommentElement();
commentElement.excludeLocationIdsFromSidebar(['location1', 'location2']);
```
Using Props:
```html
```
Using API:
```javascript
const commentElement = Velt.getCommentElement();
commentElement.excludeLocationIdsFromSidebar(['location1', 'location2']);
```
# 2.0.36
### Improvements
* \[**Comments**]: Applied `location` filters to the inline-comments-section component as well, following the same pattern like other comment components.
* \[**UI Customization**]: Removed `!important` declarations from some component CSS, improving overall style flexibility and reducing potential conflicts.
### Bug Fixes
* \[**Comments**]: Resolved an issue related to calculating comment pin positions, ensuring more accuracy and robustness.
# null
# 2.0.40
### Bug Fixes
* \[**Comments**]: Fixed an issue related to `addContext` in the `onCommentAdd` event. This ensures that context is consistently added when a new comment is created.
# null
# 2.0.27
### Bug Fixes
* \[**Comments**]: Fixed an issue with changes detection in the text comment feature.
# 2.0.26
### Improvements
* \[**Notifications**]: Renamed Notification panel "all read" container wireframe components for better clarity and consistency:
This is a breaking change.
```jsx
// Old
// New
```
```html
```
# 2.0.25
### New Features
* \[**Comments**]: For [Custom Comment Annotation dropdown](/async-collaboration/comments/customize-behavior/custom-lists#1-add-custom-lists-on-comment-annotation) on comment dialog:
* Added a default placeholder for the custom dropdown and made it configurable.
* Added it to the composer by default.
```jsx
let customList = [
{ id: 'violent', label: 'Violent' },
{ id: 'inappropriate', label: 'Inappropriate' },
{ id: 'robbery', label: 'Robbery' },
{ id: 'nsfw', label: 'NSFW' },
];
const customListDataOnCommentAnnotation = {
type: 'multi', // choose from 'multi' or 'single'
placeholder: 'Custom Placeholder',
data: customList, // your customList data here
};
```
**Using Props:**
```jsx
```
**Using API:**
```jsx
const commentElement = useCommentUtils();
commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
```
Using Wireframe:
```jsx
Custom Placeholder
```
**Using Props:**
```jsx
```
**Using API:**
```jsx
const commentElement = client.getCommentElement();
commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
```
Using Wireframe:
```jsx
Custom Placeholder
```
**Using API:**
```jsx
const commentElement = Velt.getCommentElement();
commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
```
**Using Wireframe:**
```html
Custom Placeholder
```
### Bug Fixes
* \[**Comments**]: Fixed an issue related to `disableReactions` in comment dialog customization.
# null
# 2.0.29
### New Features
* \[**Comments**]: Added feature to render a comment bubble on the comment pin or triangle instead of the comment dialog. Hovering or clicking the bubble will open the comment dialog.
Using props:
```jsx
```
Using API:
```javascript
const commentElement = client.getCommentElement();
commentElement.showBubbleOnHover(); // Enable bubble on hover
commentElement.hideBubbleOnHover(); // Disable bubble on hover
```
Using props:
```html
```
Using API:
```javascript
const commentElement = Velt.getCommentElement();
commentElement.showBubbleOnHover(); // Enable bubble on hover
commentElement.hideBubbleOnHover(); // Disable bubble on hover
```
* \[**Location**]: For multiple location setup, added support for using `data-velt-location-id` vs full location object for marking additional locations.
### Improvements
* \[**Comments**]:Refactored comment components code for better maintainability.
### Bug Fixes
* \[**Comments**]: Fixed an issue where assignee banner text color was not being applied correctly for custom statuses.
* \[**Notifications**]: Fixed an issue where the document name in the notifications documents tab was not being displayed correctly.
# 2.0.28
### New Features
* \[**Notifications**]: Added ability to customize tabs on the Notifications Panel.
```jsx
```
Using APIs:
```jsx
const notificationElement = useNotificationUtils();
const tabConfig = {
"forYou": {
name: 'Custom For You',
enable: true,
},
"documents": {
name: 'Custom Documents',
enable: true,
},
"all": {
name: "Custom All",
enable: false,
},
};
notificationElement.setTabConfig(tabConfig);
```
```jsx
```
Using APIs:
```jsx
const notificationElement = client.getNotificationElement();
const tabConfig = {
"forYou": {
name: 'Custom For You',
enable: true,
},
"documents": {
name: 'Custom Documents',
enable: true,
},
"all": {
name: 'Custom All',
enable: false,
},
};
notificationElement.setTabConfig(tabConfig);
```
```js
const tabConfig = {
"forYou": {
name: 'Custom For You',
enable: true,
},
"documents": {
name: 'Custom Documents',
enable: true,
},
"all": {
name: 'Custom All',
enable: false,
},
};
const notificationsTool = document.querySelector('velt-notifications-tool');
notificationsTool?.setAttribute("tab-config", JSON.stringify(tabConfig));
```
Using APIs:
```jsx
const notificationElement = Velt.getNotificationElement();
const tabConfig = {
"forYou": {
name: 'Custom For You',
enable: true,
},
"documents": {
name: 'Custom Documents',
enable: true,
},
"all": {
name: 'Custom All',
enable: false,
},
};
notificationElement.setTabConfig(tabConfig);
```
* \[**@ mention**]: Added ability to override contact list on the client side. [Learn more](/async-collaboration/comments/customize-behavior/@mentions).
* The `merge` parameter is used to determine if the new contact list should be merged with the existing contact list or replaced. Default: `false`.
```jsx
const contactElement = useContactUtils();
useEffect(() => {
contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: true});
}, [contactElement]);
```
```jsx
const contactElement = client.getContactElement();
contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: true});
```
```jsx
const