From b9d2722e41067f218fd3adf26a2dd46d412e11a5 Mon Sep 17 00:00:00 2001
From: Devansh
Date: Mon, 16 Sep 2024 18:04:11 +0530
Subject: [PATCH 001/153] Fix: emoji parsing issue in file description
---
.../react/src/views/AttachmentPreview/AttachmentPreview.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
index 236c3ec1ba..209c9e33e8 100644
--- a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
+++ b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
@@ -6,6 +6,7 @@ import CheckPreviewType from './CheckPreviewType';
import RCContext from '../../context/RCInstance';
import { useMessageStore } from '../../store';
import getAttachmentPreviewStyles from './AttachmentPreview.styles';
+import { parseEmoji } from '../../lib/emoji';
const AttachmentPreview = () => {
const { RCInstance, ECOptions } = useContext(RCContext);
@@ -25,7 +26,7 @@ const AttachmentPreview = () => {
};
const handleFileDescription = (e) => {
- setFileDescription(e.target.value);
+ setFileDescription(parseEmoji(e.target.value));
};
const submit = async () => {
From 5cdba75ff9fb58f967e896a38f0c843142d10b45 Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Wed, 18 Sep 2024 22:28:39 +0530
Subject: [PATCH 002/153] fix
---
packages/react/src/views/ChatHeader/ChatHeader.js | 7 ++++++-
.../src/views/ReportMessage/MessageReportWindow.js | 10 +++++++---
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index d9b6b8461b..0e46b9ccdd 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -93,8 +93,13 @@ const ChatHeader = ({
const headerTitle = useMessageStore((state) => state.headerTitle);
const filtered = useMessageStore((state) => state.filtered);
const setFilter = useMessageStore((state) => state.setFilter);
- const threadTitle = useMessageStore((state) => state.threadMainMessage?.msg);
+
const isThreadOpen = useMessageStore((state) => state.isThreadOpen);
+ const threadMainMessage = useMessageStore((state) => state.threadMainMessage);
+ const threadTitle =
+ threadMainMessage?.msg ||
+ (threadMainMessage?.file ? threadMainMessage.file.name : '');
+
const closeThread = useMessageStore((state) => state.closeThread);
const setShowMembers = useMemberStore((state) => state.setShowMembers);
diff --git a/packages/react/src/views/ReportMessage/MessageReportWindow.js b/packages/react/src/views/ReportMessage/MessageReportWindow.js
index 96bf234353..0f5e9644e9 100644
--- a/packages/react/src/views/ReportMessage/MessageReportWindow.js
+++ b/packages/react/src/views/ReportMessage/MessageReportWindow.js
@@ -7,9 +7,13 @@ import styles from './ReportMessage.styles';
const MessageReportWindow = ({ messageId }) => {
const [reportDescription, setDescription] = useState('');
- const messages = useMessageStore((state) => state.messages);
- const messageText = messages.filter((message) => message._id === messageId)[0]
- ?.msg;
+ const messages = useMessageStore((state) => state.messages) || [];
+ const threadMessages = useMessageStore((state) => state.threadMessages) || [];
+ const allMessages = [...messages, ...threadMessages];
+ const messageText = allMessages.filter(
+ (message) => message._id === messageId
+ )[0]?.msg;
+ console.log('messagetext', messageText);
return (
Date: Sat, 21 Sep 2024 22:19:48 +0530
Subject: [PATCH 003/153] Starred Model fix
---
.../src/views/MessageAggregators/common/MessageAggregator.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index a49f547e18..81a277084e 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -26,9 +26,11 @@ export const MessageAggregator = ({
const styles = getMessageAggregatorStyles(theme);
const setExclusiveState = useSetExclusiveState();
const messages = useMessageStore((state) => state.messages);
+ const threadMessages=useMessageStore((state)=>state.threadMessages)|| [];
+ const allMessages=[...messages,...threadMessages];
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
- searchFiltered || messages,
+ searchFiltered || allMessages,
shouldRender
);
From 5c78a16e76ce40f76b9f68da06375e04d267997b Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Thu, 26 Sep 2024 00:50:59 +0530
Subject: [PATCH 004/153] removed console.log
---
packages/react/src/views/ReportMessage/MessageReportWindow.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/react/src/views/ReportMessage/MessageReportWindow.js b/packages/react/src/views/ReportMessage/MessageReportWindow.js
index 0f5e9644e9..74bc1fb814 100644
--- a/packages/react/src/views/ReportMessage/MessageReportWindow.js
+++ b/packages/react/src/views/ReportMessage/MessageReportWindow.js
@@ -13,7 +13,6 @@ const MessageReportWindow = ({ messageId }) => {
const messageText = allMessages.filter(
(message) => message._id === messageId
)[0]?.msg;
- console.log('messagetext', messageText);
return (
Date: Fri, 27 Sep 2024 21:53:31 +0530
Subject: [PATCH 005/153] prettier
---
.../src/views/MessageAggregators/common/MessageAggregator.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 81a277084e..9b9c573066 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -26,8 +26,8 @@ export const MessageAggregator = ({
const styles = getMessageAggregatorStyles(theme);
const setExclusiveState = useSetExclusiveState();
const messages = useMessageStore((state) => state.messages);
- const threadMessages=useMessageStore((state)=>state.threadMessages)|| [];
- const allMessages=[...messages,...threadMessages];
+ const threadMessages = useMessageStore((state) => state.threadMessages) || [];
+ const allMessages = [...messages, ...threadMessages];
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
searchFiltered || allMessages,
From 13d807e7f781e298c3839179f3e16ec55c9747e4 Mon Sep 17 00:00:00 2001
From: Devansh Kansagra <125076549+devanshkansagra@users.noreply.github.com>
Date: Sat, 5 Oct 2024 18:25:48 +0530
Subject: [PATCH 006/153] Combine build steps for react, ui-elements, and
layout_editor packages (#637)
* Combine build steps for react, ui-elements, and layout_editor packages
* Small change in build-lint
---
.github/workflows/build-and-lint.yml | 2 +-
.github/workflows/deploy.yml | 15 +++------------
2 files changed, 4 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/build-and-lint.yml b/.github/workflows/build-and-lint.yml
index d92c4001a5..375ec8c3af 100644
--- a/.github/workflows/build-and-lint.yml
+++ b/.github/workflows/build-and-lint.yml
@@ -34,7 +34,7 @@ jobs:
${{ runner.os }}-yarn-
- name: Install dependencies
- run: yarn
+ run: yarn install
- name: Format check
run: yarn format:check
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 3099455b0c..b3b61cc78c 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -30,19 +30,10 @@ jobs:
node-version: "16.19.0"
- name: Install Dependencies
- run: yarn
-
- - name: Build Storybook
- run: yarn build:storybook
- working-directory: packages/react
-
- - name: Build UI-Elements
- run: yarn build:storybook
- working-directory: packages/ui-elements
+ run: yarn install
- - name: Build Layout Editor
- run: npm run build
- working-directory: packages/layout_editor
+ - name: Build packages
+ run: yarn build && yarn build:storybook
- name: Setup Node.js for Docs
uses: actions/setup-node@v4
From 3657c15f23917c11d4508694e9e7433fca06a136 Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sat, 5 Oct 2024 18:28:18 +0530
Subject: [PATCH 007/153] Changed workflow name
---
.github/workflows/deploy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index b3b61cc78c..4055f20ca6 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -1,4 +1,4 @@
-name: Build and Publish Storybook to GitHub Pages
+name: Build and Publish
on:
push:
From ebca321b2fa034376c8100cf381637fa88df8538 Mon Sep 17 00:00:00 2001
From: Devansh Kansagra <125076549+devanshkansagra@users.noreply.github.com>
Date: Sun, 6 Oct 2024 12:32:46 +0530
Subject: [PATCH 008/153] Added Feature to deploy previews of pull requests
(#638)
* Added Feature to deploy previews of pull requests
* Removed environment variables from build-lint workflow
* Modified the changes mentioned in the code-review
---
.github/workflows/build-pr.yml | 65 +++++++++++++++++++++++++++
.github/workflows/deploy-pr.yml | 36 +++++++++++++++
.github/workflows/pr-cleanup.yml | 34 ++++++++++++++
packages/docs/docusaurus.config.js | 2 +-
packages/layout_editor/vite.config.ts | 2 +-
5 files changed, 137 insertions(+), 2 deletions(-)
create mode 100644 .github/workflows/build-pr.yml
create mode 100644 .github/workflows/deploy-pr.yml
create mode 100644 .github/workflows/pr-cleanup.yml
diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
new file mode 100644
index 0000000000..66c97af32c
--- /dev/null
+++ b/.github/workflows/build-pr.yml
@@ -0,0 +1,65 @@
+name: Build PR-Preview
+
+on:
+ pull_request_review:
+ types: submitted
+
+concurrency:
+ group: ${{github.workflow}}-${{github.ref}}
+ cancel-in-progress: true
+
+env:
+ LAYOUT_EDITOR_BASE_URL: "/EmbeddedChat/pulls/pr-${{github.event.pull_request.number}}/layout_editor"
+ DOCS_BASE_URL: "/EmbeddedChat/pulls/pr-${{github.event.pull_request.number}}/docs"
+ STORYBOOK_RC_HOST: "https://demo.qa.rocket.chat"
+
+jobs:
+ build:
+ if: github.event.review.state == 'approved' && (github.event.review.author_association == 'COLLABORATOR' || github.event.review.author_association == 'OWNER')
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "16.19.0"
+
+ - name: Install Dependencies
+ run: yarn install
+
+ - name: Build packages
+ run: yarn build && yarn build:storybook
+
+ - name: Setup Node.js for Docs
+ uses: actions/setup-node@v4
+ with:
+ node-version: "18.x"
+
+ - name: "Install dependencies for docs"
+ run: yarn install
+ working-directory: packages/docs/
+
+ - name: Build Docs
+ run: yarn build
+ working-directory: packages/docs/
+
+ - name: Prepare Build Folder
+ run: |
+ mkdir -p build/pulls/pr-${{github.event.pull_request.number}}/
+ mkdir -p build/pulls/pr-${{github.event.pull_request.number}}/ui-elements
+ mkdir -p build/pulls/pr-${{github.event.pull_request.number}}/layout_editor
+ mkdir -p build/pulls/pr-${{github.event.pull_request.number}}/docs
+
+ mv -v packages/react/storybook-static/* build/pulls/pr-${{github.event.pull_request.number}}/
+ mv -v packages/ui-elements/storybook-static/* build/pulls/pr-${{github.event.pull_request.number}}/ui-elements/
+ mv -v packages/layout_editor/dist/* build/pulls/pr-${{github.event.pull_request.number}}/layout_editor/
+ mv -v packages/docs/build/* build/pulls/pr-${{github.event.pull_request.number}}/docs/
+
+ - name: Upload Artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: github-pages
+ path: build/
diff --git a/.github/workflows/deploy-pr.yml b/.github/workflows/deploy-pr.yml
new file mode 100644
index 0000000000..4f687507d3
--- /dev/null
+++ b/.github/workflows/deploy-pr.yml
@@ -0,0 +1,36 @@
+name: Deploy PR-Preview
+
+on:
+ workflow_run:
+ workflows: ["Build PR-Preview"]
+ types:
+ - completed
+
+permissions:
+ contents: write
+ pages: write
+
+jobs:
+ deploy:
+ if: github.event.workflow_run.conclusion == 'success'
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/download-artifact@v4
+ with:
+ name: github-pages
+ path: build/
+ github-token: ${{github.token}}
+ repository: ${{github.repository}}
+ run-id: ${{github.event.workflow_run.id}}
+
+ - name: Deploy to GitHub Pages
+ uses: crazy-max/ghaction-github-pages@v2
+ with:
+ target_branch: gh-deploy
+ build_dir: build/
+ commit_message: "Deploy to Github Pages"
+ jekyll: false
+ keep_history: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/pr-cleanup.yml b/.github/workflows/pr-cleanup.yml
new file mode 100644
index 0000000000..c5b878373c
--- /dev/null
+++ b/.github/workflows/pr-cleanup.yml
@@ -0,0 +1,34 @@
+name: Pull Request Cleanup
+on:
+ pull_request_target:
+ types: [closed]
+
+jobs:
+ cleanup:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ with:
+ ref: gh-deploy
+
+ - name: Check if Deployment Exists
+ id: check_deployment
+ run: |
+ if [ -d "pulls/pr-${{ github.event.pull_request.number }}" ]; then
+ echo "deployment_exists=true" >> $GITHUB_ENV
+ else
+ echo "deployment_exists=false" >> $GITHUB_ENV
+ fi
+
+ - name: Remove Deployment
+ if: env.deployment_exists == 'true'
+ run: |
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "github-actions[bot]"
+ git fetch origin gh-deploy
+ git checkout gh-deploy
+ git rm -r pulls/pr-${{github.event.pull_request.number}}
+ git commit -m "Remove deployment for PR #${{github.event.pull_request.number}}"
+ git push origin gh-deploy
diff --git a/packages/docs/docusaurus.config.js b/packages/docs/docusaurus.config.js
index f9073bfa8e..1201dae919 100644
--- a/packages/docs/docusaurus.config.js
+++ b/packages/docs/docusaurus.config.js
@@ -17,7 +17,7 @@ const config = {
url: "https://rocketchat.github.io/",
// Set the // pathname under which your site is served
// For GitHub pages deployment, it is often '//'
- baseUrl: "/EmbeddedChat/docs/",
+ baseUrl: process.env.DOCS_BASE_URL || "/EmbeddedChat/docs/",
// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
diff --git a/packages/layout_editor/vite.config.ts b/packages/layout_editor/vite.config.ts
index 2b9daff2d3..b6ab8acd24 100644
--- a/packages/layout_editor/vite.config.ts
+++ b/packages/layout_editor/vite.config.ts
@@ -11,5 +11,5 @@ export default defineConfig({
},
}),
],
- base: "/EmbeddedChat/layout_editor"
+ base: process.env.LAYOUT_EDITOR_BASE_URL || '/EmbeddedChat/layout_editor',
});
From 9187d953545ad04199682a44080a9d9b205470da Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sun, 6 Oct 2024 12:54:20 +0530
Subject: [PATCH 009/153] added pr test info in pr template
---
.github/pull_request_template.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 337559b404..8a4d4f38d1 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -9,3 +9,9 @@
Fixes # (issue)
## Video/Screenshots
+
+## PR Test Details
+
+**Note**: The PR will be ready for live testing at https://rocketchat.github.io/EmbeddedChat/pulls/pr- after approval.
+
+
From d21255c9e1d88e0ddae73c052396cfbda7b306bf Mon Sep 17 00:00:00 2001
From: Rahul Singh Thakur <65606499+Barrylimarti@users.noreply.github.com>
Date: Sat, 2 Nov 2024 21:44:15 +0530
Subject: [PATCH 010/153] [fix] Re-rendering fixed while opening pinned and
starred messages. (#644)
* added memoization to stop rerenders
* added memoization for allmessage and shouldrender
* fixed linting errors and imports
---
packages/react/src/hooks/useSetMessageList.js | 14 ++++++--------
.../views/MessageAggregators/StarredMessages.js | 13 ++++++++-----
.../MessageAggregators/common/MessageAggregator.js | 7 +++++--
3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/packages/react/src/hooks/useSetMessageList.js b/packages/react/src/hooks/useSetMessageList.js
index a2b3917d59..69b4bef7cf 100644
--- a/packages/react/src/hooks/useSetMessageList.js
+++ b/packages/react/src/hooks/useSetMessageList.js
@@ -1,16 +1,14 @@
-import { useState, useEffect } from 'react';
+import { useState, useEffect, useMemo } from 'react';
export const useSetMessageList = (messages, shouldRender) => {
const [loading, setLoading] = useState(true);
- const [messageList, setMessageList] = useState([]);
- useEffect(() => {
- setLoading(true);
- const filteredMessages = messages.filter((message) =>
- shouldRender(message)
- );
+ const messageList = useMemo(
+ () => messages.filter(shouldRender),
+ [messages, shouldRender]
+ );
- setMessageList(filteredMessages);
+ useEffect(() => {
setLoading(false);
}, [messages, shouldRender]);
diff --git a/packages/react/src/views/MessageAggregators/StarredMessages.js b/packages/react/src/views/MessageAggregators/StarredMessages.js
index 9a79fa0ebe..b7d77b864e 100644
--- a/packages/react/src/views/MessageAggregators/StarredMessages.js
+++ b/packages/react/src/views/MessageAggregators/StarredMessages.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useCallback } from 'react';
import { useComponentOverrides } from '@embeddedchat/ui-elements';
import { useUserStore } from '../../store';
import { MessageAggregator } from './common/MessageAggregator';
@@ -7,15 +7,18 @@ const StarredMessages = () => {
const authenticatedUserId = useUserStore((state) => state.userId);
const { variantOverrides } = useComponentOverrides('StarredMessages');
const viewType = variantOverrides.viewType || 'Sidebar';
+ const shouldRender = useCallback(
+ (msg) =>
+ msg.starred &&
+ msg.starred.some((star) => star._id === authenticatedUserId),
+ [authenticatedUserId]
+ );
return (
- msg.starred &&
- msg.starred.some((star) => star._id === authenticatedUserId)
- }
+ shouldRender={shouldRender}
viewType={viewType}
/>
);
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 9b9c573066..079582e86a 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useMemo } from 'react';
import { isSameDay, format } from 'date-fns';
import { Box, Sidebar, Popup, useTheme } from '@embeddedchat/ui-elements';
import { MessageDivider } from '../../Message/MessageDivider';
@@ -27,7 +27,10 @@ export const MessageAggregator = ({
const setExclusiveState = useSetExclusiveState();
const messages = useMessageStore((state) => state.messages);
const threadMessages = useMessageStore((state) => state.threadMessages) || [];
- const allMessages = [...messages, ...threadMessages];
+ const allMessages = useMemo(
+ () => [...messages, ...threadMessages],
+ [messages, threadMessages]
+ );
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
searchFiltered || allMessages,
From faf9fb76b35bc19bf1f75e56b28b7b24a8a7d30a Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Sat, 2 Nov 2024 21:49:44 +0530
Subject: [PATCH 011/153] fixed markdown rendering in report message (#611)
* fix
* formatting fix
* fix
* Fiexed lint issues
---
.../react/src/views/ReportMessage/MessageReportWindow.js | 8 --------
1 file changed, 8 deletions(-)
diff --git a/packages/react/src/views/ReportMessage/MessageReportWindow.js b/packages/react/src/views/ReportMessage/MessageReportWindow.js
index 74bc1fb814..33957e72ea 100644
--- a/packages/react/src/views/ReportMessage/MessageReportWindow.js
+++ b/packages/react/src/views/ReportMessage/MessageReportWindow.js
@@ -2,17 +2,10 @@ import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Box, Input } from '@embeddedchat/ui-elements';
import ReportWindowButtons from './ReportWindowButtons';
-import { useMessageStore } from '../../store';
import styles from './ReportMessage.styles';
const MessageReportWindow = ({ messageId }) => {
const [reportDescription, setDescription] = useState('');
- const messages = useMessageStore((state) => state.messages) || [];
- const threadMessages = useMessageStore((state) => state.threadMessages) || [];
- const allMessages = [...messages, ...threadMessages];
- const messageText = allMessages.filter(
- (message) => message._id === messageId
- )[0]?.msg;
return (
{
reportDescription={reportDescription}
messageId={messageId}
>
- {JSON.stringify(messageText)}
Date: Mon, 4 Nov 2024 22:20:27 +0530
Subject: [PATCH 012/153] added instruction to replace pr num
---
.github/pull_request_template.md | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 8a4d4f38d1..ccf362d516 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -12,6 +12,4 @@ Fixes # (issue)
## PR Test Details
-**Note**: The PR will be ready for live testing at https://rocketchat.github.io/EmbeddedChat/pulls/pr- after approval.
-
-
+**Note**: The PR will be ready for live testing at https://rocketchat.github.io/EmbeddedChat/pulls/pr- after approval. Contributors are requested to replace `` with the actual PR number.
From 36534fc3fd7e5f7824a1c316878a3c7e54828eed Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 10 Nov 2024 15:36:32 +0530
Subject: [PATCH 013/153] Prevent Quote Message Overflow (#659)
* prevent quote message overflow
* Removed sidebar open checking and added styling to Quote Message Box
---
packages/react/src/views/ChatInput/ChatInput.js | 6 +++++-
.../react/src/views/QuoteMessage/QuoteMessage.styles.js | 6 ++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 99c1c8b4f7..ba9f569b2f 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -423,7 +423,11 @@ const ChatInput = ({ scrollToBottom }) => {
return (
-
+
{(quoteMessage.msg || quoteMessage.attachments) && (
)}
diff --git a/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js b/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js
index 5ffe32dd2e..1b6619ea95 100644
--- a/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js
+++ b/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js
@@ -12,6 +12,8 @@ const getQuoteMessageStyles = (theme) => {
z-index: 1200;
border: 1px solid ${theme.colors.border};
border-radius: ${theme.radius};
+ max-width: 100%;
+ box-sizing: border-box;
`,
avatarContainer: css`
@@ -22,6 +24,10 @@ const getQuoteMessageStyles = (theme) => {
message: css`
padding: 0.25rem;
+ overflow-wrap: break-word;
+ word-break: break-word;
+ white-space: normal;
+ width: 100%;
`,
actionBtn: css`
From e898504343afd7c87dd60afcdb9aaffc033a53ac Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sun, 10 Nov 2024 15:39:38 +0530
Subject: [PATCH 014/153] Trim Whitespaces in Username/Email Fields in
EmbeddedChat Login Form (#657)
* trim whitespaces in username/email fields to prevent login issues
* Remove extra .trim()
---
packages/api/src/EmbeddedChatApi.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 574370a5b1..021a82c4db 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -121,12 +121,12 @@ export default class EmbeddedChatApi {
let credentials;
if (!code) {
credentials = credentials = {
- user: userOrEmail,
+ user: userOrEmail.trim(),
password,
};
} else {
credentials = {
- user: userOrEmail,
+ user: userOrEmail.trim(),
password,
code,
};
From afa6b81bafb150fa960a561b9a28fdb819aa8019 Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sun, 10 Nov 2024 21:30:55 +0530
Subject: [PATCH 015/153] Fix: Display emoji in visual format and enable send
icon on emoji selection (#663)
* Fix: Display emoji in visual format and enable send icon on emoji selection
* Revised code
---
packages/react/src/views/ChatInput/ChatInput.js | 15 +++++++++------
.../views/ChatInput/ChatInputFormattingToolbar.js | 7 ++++++-
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index ba9f569b2f..eae9573aed 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -25,7 +25,6 @@ import useAttachmentWindowStore from '../../store/attachmentwindow';
import MembersList from '../Mentions/MembersList';
import { TypingUsers } from '../TypingUsers';
import createPendingMessage from '../../lib/createPendingMessage';
-import { parseEmoji } from '../../lib/emoji';
import { CommandsList } from '../CommandList';
import useSettingsStore from '../../store/settingsStore';
import ChannelState from '../ChannelState/ChannelState';
@@ -34,6 +33,7 @@ import { getChatInputStyles } from './ChatInput.styles';
import useShowCommands from '../../hooks/useShowCommands';
import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import formatSelection from '../../lib/formatSelection';
+import { parseEmoji } from '../../lib/emoji';
const ChatInput = ({ scrollToBottom }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
@@ -362,14 +362,16 @@ const ChatInput = ({ scrollToBottom }) => {
setData(event.target.files[0]);
};
- const onTextChange = (e) => {
+ const onTextChange = (e, val) => {
sendTypingStart();
- const message = e.target.value;
+ const message = val || e.target.value;
messageRef.current.value = parseEmoji(message);
setDisableButton(!messageRef.current.value.length);
- handleNewLine(e, false);
- searchMentionUser(message);
- showCommands(e);
+ if (e !== null) {
+ handleNewLine(e, false);
+ searchMentionUser(message);
+ showCommands(e);
+ }
};
const handleFocus = () => {
@@ -532,6 +534,7 @@ const ChatInput = ({ scrollToBottom }) => {
)}
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 634b2255af..fd96f50363 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -19,6 +19,7 @@ import formatSelection from '../../lib/formatSelection';
const ChatInputFormattingToolbar = ({
messageRef,
inputRef,
+ triggerButton,
optionConfig = {
surfaceItems: ['emoji', 'formatter', 'audio', 'video', 'file'],
formatters: ['bold', 'italic', 'strike', 'code', 'multiline'],
@@ -46,7 +47,11 @@ const ChatInputFormattingToolbar = ({
const handleEmojiClick = (emojiEvent) => {
const [emoji] = emojiEvent.names;
- messageRef.current.value += ` :${emoji.replace(/[\s-]+/g, '_')}: `;
+ const message = `${messageRef.current.value} :${emoji.replace(
+ /[\s-]+/g,
+ '_'
+ )}: `;
+ triggerButton?.(null, message);
};
const chatToolMap = {
From 75f7760cd0671714250e2002dd5367df60e1f75a Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Mon, 11 Nov 2024 21:11:39 +0530
Subject: [PATCH 016/153] Fix logout issue (#666)
* set messages and avatar url to null on logout
* Fixed linting issues
* Remove unnecessary import
---
packages/react/src/views/ChatHeader/ChatHeader.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 0e46b9ccdd..7c43056a65 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -88,8 +88,9 @@ const ChatHeader = ({
const dispatchToastMessage = useToastBarDispatch();
const getMessagesAndRoles = useFetchChatData(showRoles);
const setMessageLimit = useSettingsStore((state) => state.setMessageLimit);
-
+ const setMessages = useMessageStore((state) => state.setMessages);
const avatarUrl = useUserStore((state) => state.avatarUrl);
+ const setUserAvatarUrl = useUserStore((state) => state.setUserAvatarUrl);
const headerTitle = useMessageStore((state) => state.headerTitle);
const filtered = useMessageStore((state) => state.filtered);
const setFilter = useMessageStore((state) => state.setFilter);
@@ -128,6 +129,9 @@ const ChatHeader = ({
const handleLogout = useCallback(async () => {
try {
await RCInstance.logout();
+ setMessages([]);
+ setUserAvatarUrl(null);
+ useMessageStore.setState({ isMessageLoaded: false });
} catch (e) {
console.error(e);
} finally {
From 8ba15a5f8cc32a6c5887df8aa08374ba4599c0ba Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Fri, 29 Nov 2024 01:00:17 +0530
Subject: [PATCH 017/153] Fix: Prevent repeated API calls in searchMessages
after typing stops (#655)
* Fix: Prevent repeated API calls in searchMessages after typing stops
* Implement Rate Limiter
* Revised debounce
---
.../views/MessageAggregators/SearchMessages.js | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/packages/react/src/views/MessageAggregators/SearchMessages.js b/packages/react/src/views/MessageAggregators/SearchMessages.js
index e627921c80..b4248461c6 100644
--- a/packages/react/src/views/MessageAggregators/SearchMessages.js
+++ b/packages/react/src/views/MessageAggregators/SearchMessages.js
@@ -1,4 +1,4 @@
-import React, { useState, useContext, useEffect } from 'react';
+import React, { useState, useContext, useEffect, useCallback } from 'react';
import debounce from 'lodash/debounce';
import { useComponentOverrides } from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
@@ -15,14 +15,17 @@ const SearchMessages = () => {
setText(e.target.value);
};
- const searchMessages = async () => {
+ const searchMessages = useCallback(async () => {
const { messages } = await RCInstance.getSearchMessages(text);
setMessageList(messages);
- };
+ }, [text, RCInstance]);
- const debouncedSearch = debounce(async () => {
- await searchMessages();
- }, 500);
+ const debouncedSearch = useCallback(
+ debounce(async () => {
+ await searchMessages();
+ }, 500),
+ [searchMessages]
+ );
useEffect(() => {
if (!text.trim()) {
From 38f52a1119e4b2a0b12f60dd59f724b891d0697a Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sun, 15 Dec 2024 15:28:28 +0530
Subject: [PATCH 018/153] Fix code scanning alert no. 13: Incomplete string
escaping or encoding (#684)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
---
packages/ui-elements/tools/icons-generator.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/ui-elements/tools/icons-generator.js b/packages/ui-elements/tools/icons-generator.js
index 7dc17fc93b..538d42f406 100644
--- a/packages/ui-elements/tools/icons-generator.js
+++ b/packages/ui-elements/tools/icons-generator.js
@@ -64,7 +64,7 @@ const camelCase = (name) =>
const codeModifier = (code) => {
let newCode = code.replace(/class=/g, 'className=');
const openingTag = newCode.match(//g)[0];
- const newOpeningTag = openingTag.replace('>', ' {...props}>');
+ const newOpeningTag = openingTag.replace(/>/g, ' {...props}>');
newCode = newCode.replace(openingTag, newOpeningTag);
return newCode;
};
From 8284ffa38dca7cfe00430cc89b25f30bd7e7eece Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:31:51 +0530
Subject: [PATCH 019/153] Fix: Restrict Pin Icon Visibility Based on User
Permissions (#674)
* Fix:Fix: Restrict pin icon visibility based on user permissions
* Restrict pin icon visibility
---
packages/react/src/hooks/useRCAuth.js | 5 +++++
packages/react/src/store/userStore.js | 5 ++++-
packages/react/src/views/Message/Message.js | 7 +++++++
packages/react/src/views/Message/MessageToolbox.js | 5 ++++-
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/hooks/useRCAuth.js b/packages/react/src/hooks/useRCAuth.js
index 83b013353b..6a997cb569 100644
--- a/packages/react/src/hooks/useRCAuth.js
+++ b/packages/react/src/hooks/useRCAuth.js
@@ -20,11 +20,15 @@ export const useRCAuth = () => {
);
const setPassword = useUserStore((state) => state.setPassword);
const setEmailorUser = useUserStore((state) => state.setEmailorUser);
+ const setUserPinPermissions = useUserStore(
+ (state) => state.setUserPinPermissions
+ );
const dispatchToastMessage = useToastBarDispatch();
const handleLogin = async (userOrEmail, password, code) => {
try {
const res = await RCInstance.login(userOrEmail, password, code);
+ const permissions = await RCInstance.permissionInfo();
if (res.error === 'Unauthorized' || res.error === 403) {
dispatchToastMessage({
type: 'error',
@@ -56,6 +60,7 @@ export const useRCAuth = () => {
setIsTotpModalOpen(false);
setEmailorUser(null);
setPassword(null);
+ setUserPinPermissions(permissions.update[150]);
dispatchToastMessage({
type: 'success',
message: 'Successfully logged in',
diff --git a/packages/react/src/store/userStore.js b/packages/react/src/store/userStore.js
index c4128cf468..d3c3aa24c3 100644
--- a/packages/react/src/store/userStore.js
+++ b/packages/react/src/store/userStore.js
@@ -27,8 +27,11 @@ const useUserStore = create((set) => ({
setPassword: (password) => set(() => ({ password })),
emailoruser: null,
setEmailorUser: (emailoruser) => set(() => ({ emailoruser })),
- roles: {},
+ roles: [],
setRoles: (roles) => set((state) => ({ ...state, roles })),
+ userPinPermissions: {},
+ setUserPinPermissions: (userPinPermissions) =>
+ set((state) => ({ ...state, userPinPermissions })),
showCurrentUserInfo: false,
setShowCurrentUserInfo: (showCurrentUserInfo) =>
set(() => ({ showCurrentUserInfo })),
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 8ce3d8bf5c..64d2050f09 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -51,6 +51,10 @@ const Message = ({
const authenticatedUserId = useUserStore((state) => state.userId);
const authenticatedUserUsername = useUserStore((state) => state.username);
+ const userRoles = useUserStore((state) => state.roles);
+ const pinPermissions = useUserStore(
+ (state) => state.userPinPermissions.roles
+ );
const [setMessageToReport, toggleShowReportMessage] = useMessageStore(
(state) => [state.setMessageToReport, state.toggleShowReportMessage]
);
@@ -67,6 +71,7 @@ const Message = ({
const theme = useTheme();
const styles = getMessageStyles(theme);
const bubbleStyles = useBubbleStyles(isMe);
+ const pinRoles = new Set(pinPermissions);
const variantStyles =
!isInSidebar && variantOverrides === 'bubble' ? bubbleStyles : {};
@@ -200,6 +205,8 @@ const Message = ({
message={message}
isEditing={editMessage._id === message._id}
authenticatedUserId={authenticatedUserId}
+ userRoles={userRoles}
+ pinRoles={pinRoles}
handleOpenThread={handleOpenThread}
handleDeleteMessage={handleDeleteMessage}
handleStarMessage={handleStarMessage}
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 248dd35586..55af7f64d5 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -21,6 +21,8 @@ export const MessageToolbox = ({
style = {},
isThreadMessage = false,
authenticatedUserId,
+ userRoles,
+ pinRoles,
handleOpenThread,
handleEmojiClick,
handlePinMessage,
@@ -67,6 +69,7 @@ export const MessageToolbox = ({
setShowDeleteModal(false);
};
+ const isAllowedToPin = userRoles.some((role) => pinRoles.has(role));
const options = useMemo(
() => ({
reply: {
@@ -110,7 +113,7 @@ export const MessageToolbox = ({
id: 'pin',
onClick: () => handlePinMessage(message),
iconName: message.pinned ? 'pin-filled' : 'pin',
- visible: !isThreadMessage,
+ visible: !isThreadMessage && isAllowedToPin,
},
edit: {
label: 'Edit',
From 32e14bca76e10bbbf40899d6cb594eb3fccb0af2 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:38:17 +0530
Subject: [PATCH 020/153] Made message box responsive and fixed alignment
(#664)
---
.../react/src/views/ChatBody/ChatBody.styles.js | 2 +-
.../react/src/views/ChatInput/ChatInput.styles.js | 13 +++++++++++--
.../react/src/views/ChatLayout/ChatLayout.styles.js | 1 +
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/packages/react/src/views/ChatBody/ChatBody.styles.js b/packages/react/src/views/ChatBody/ChatBody.styles.js
index 36fc549b5f..06be313a16 100644
--- a/packages/react/src/views/ChatBody/ChatBody.styles.js
+++ b/packages/react/src/views/ChatBody/ChatBody.styles.js
@@ -9,7 +9,7 @@ export const getChatbodyStyles = () => {
overflow-x: hidden;
display: flex;
flex-direction: column-reverse;
- max-height: 600px;
+ max-height: 100%;
position: relative;
padding-top: 70px;
margin-top: 0.25rem;
diff --git a/packages/react/src/views/ChatInput/ChatInput.styles.js b/packages/react/src/views/ChatInput/ChatInput.styles.js
index 73e91eb971..a1474877f9 100644
--- a/packages/react/src/views/ChatInput/ChatInput.styles.js
+++ b/packages/react/src/views/ChatInput/ChatInput.styles.js
@@ -22,6 +22,9 @@ export const getChatInputStyles = (theme) => {
justify-content: center;
flex-direction: row;
padding: 0.5rem;
+ @media (max-width: 383px) {
+ min-height: 100px;
+ }
`,
iconCursor: css`
@@ -51,6 +54,9 @@ export const getChatInputStyles = (theme) => {
&::placeholder {
padding-left: 5px;
}
+ @media (max-width: 383px) {
+ font-size: 18px;
+ }
`,
};
@@ -68,9 +74,12 @@ export const getChatInputFormattingToolbarStyles = ({ theme, mode }) => {
: lighten(theme.colors.background, 1)};
display: flex;
position: relative;
- flex-direction: row;
- gap: 0.375rem;
+ gap: 0.1rem;
border-radius: 0 0 ${theme.radius} ${theme.radius};
+ @media (max-width: 383px) {
+ display: grid;
+ grid-template-columns: repeat(5, 0.2fr);
+ }
`,
};
return styles;
diff --git a/packages/react/src/views/ChatLayout/ChatLayout.styles.js b/packages/react/src/views/ChatLayout/ChatLayout.styles.js
index 3afa726498..56dd748cbe 100644
--- a/packages/react/src/views/ChatLayout/ChatLayout.styles.js
+++ b/packages/react/src/views/ChatLayout/ChatLayout.styles.js
@@ -12,6 +12,7 @@ const styles = {
flex: 1;
flex-direction: column;
position: relative;
+ min-width: 0;
`,
sidebar: css`
From a6ea2bcbd4295cafe6046bd8be457aa3f1a10868 Mon Sep 17 00:00:00 2001
From: Devansh Kansagra <125076549+devanshkansagra@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:39:38 +0530
Subject: [PATCH 021/153] Fix: Quoting issues (#641)
* fixed recursive quoting issue
* fixed multiple quoting issue
* Removed unwanted comment
* added checks which causing error in deployment
* Resolved the commits
* Fix the issue of not able to send the quoted thread messages
---
packages/react/src/store/messageStore.js | 10 +-
.../src/views/AttachmentHandler/Attachment.js | 53 ++++++
.../AttachmentHandler/AttachmentMetadata.js | 2 +-
.../AttachmentHandler/AudioAttachment.js | 135 ++++++++++++--
.../AttachmentHandler/ImageAttachment.js | 146 +++++++++++++--
.../views/AttachmentHandler/TextAttachment.js | 77 +++++++-
.../AttachmentHandler/VideoAttachment.js | 174 +++++++++++++++---
.../react/src/views/ChatInput/ChatInput.js | 56 ++++--
.../src/views/ChatInput/ChatInput.styles.js | 4 +
.../Message/BubbleVariant/Bubble.styles.js | 6 +-
packages/react/src/views/Message/Message.js | 4 +-
.../src/views/QuoteMessage/QuoteMessage.js | 75 +++++++-
12 files changed, 647 insertions(+), 95 deletions(-)
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index 012a97e1ed..507ba3d141 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -8,7 +8,7 @@ const useMessageStore = create((set, get) => ({
threadMessages: [],
filtered: false,
editMessage: {},
- quoteMessage: {},
+ quoteMessage: [],
messageToReport: NaN,
showReportMessage: false,
isRecordingMessage: false,
@@ -71,7 +71,13 @@ const useMessageStore = create((set, get) => ({
}
},
setEditMessage: (editMessage) => set(() => ({ editMessage })),
- setQuoteMessage: (quoteMessage) => set(() => ({ quoteMessage })),
+ addQuoteMessage: (quoteMessage) =>
+ set((state) => ({ quoteMessage: [...state.quoteMessage, quoteMessage] })),
+ removeQuoteMessage: (quoteMessage) =>
+ set((state) => ({
+ quoteMessage: state.quoteMessage.filter((i) => i !== quoteMessage),
+ })),
+ clearQuoteMessages: () => set({ quoteMessage: [] }),
setMessageToReport: (messageId) =>
set(() => ({ messageToReport: messageId })),
toggleShowReportMessage: () => {
diff --git a/packages/react/src/views/AttachmentHandler/Attachment.js b/packages/react/src/views/AttachmentHandler/Attachment.js
index bc07a740c1..594bfa7d70 100644
--- a/packages/react/src/views/AttachmentHandler/Attachment.js
+++ b/packages/react/src/views/AttachmentHandler/Attachment.js
@@ -8,11 +8,16 @@ import VideoAttachment from './VideoAttachment';
import TextAttachment from './TextAttachment';
const Attachment = ({ attachment, host, type, variantStyles = {} }) => {
+ const author = {
+ authorIcon: attachment?.author_icon,
+ authorName: attachment?.author_name,
+ };
if (attachment && attachment.audio_url) {
return (
);
@@ -22,6 +27,7 @@ const Attachment = ({ attachment, host, type, variantStyles = {} }) => {
);
@@ -31,6 +37,7 @@ const Attachment = ({ attachment, host, type, variantStyles = {} }) => {
);
@@ -40,10 +47,56 @@ const Attachment = ({ attachment, host, type, variantStyles = {} }) => {
);
}
+ if (
+ attachment.attachments &&
+ Array.isArray(attachment.attachments) &&
+ attachment.attachments[0]?.image_url
+ ) {
+ return (
+
+ );
+ }
+ if (
+ attachment.attachments &&
+ Array.isArray(attachment.attachments) &&
+ attachment.attachments[0]?.audio_url
+ ) {
+ return (
+
+ );
+ }
+ if (
+ attachment.attachments &&
+ Array.isArray(attachment.attachments) &&
+ attachment.attachments[0]?.video_url
+ ) {
+ return (
+
+ );
+ }
return (
{
diff --git a/packages/react/src/views/AttachmentHandler/AudioAttachment.js b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
index ce84815828..0f5824aa0f 100644
--- a/packages/react/src/views/AttachmentHandler/AudioAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
@@ -1,18 +1,129 @@
-import React from 'react';
+import React, { useContext } from 'react';
import PropTypes from 'prop-types';
-import { Box } from '@embeddedchat/ui-elements';
+import { css } from '@emotion/react';
+import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import AttachmentMetadata from './AttachmentMetadata';
+import RCContext from '../../context/RCInstance';
-const AudioAttachment = ({ attachment, host, variantStyles }) => (
-
-
-
-
-);
+const AudioAttachment = ({ attachment, host, type, author, variantStyles }) => {
+ const { RCInstance } = useContext(RCContext);
+ const { theme } = useTheme();
+ const getUserAvatarUrl = (icon) => {
+ const instanceHost = RCInstance.getHost();
+ const URL = `${instanceHost}${icon}`;
+ return URL;
+ };
+ const { authorIcon, authorName } = author;
+ return (
+
+
+ {type === 'file' ? (
+ <>
+
+
+ @{authorName}
+
+ >
+ ) : (
+ ''
+ )}
+
+
+
+ {attachment.attachments &&
+ attachment.attachments.map((nestedAttachment, index) => (
+
+
+ {nestedAttachment.type === 'file' ? (
+ <>
+
+
+ @{nestedAttachment.author_name}
+
+ >
+ ) : (
+ ''
+ )}
+
+
+
+
+ ))}
+
+
+ );
+};
export default AudioAttachment;
diff --git a/packages/react/src/views/AttachmentHandler/ImageAttachment.js b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
index 8937782569..b9e6533ad4 100644
--- a/packages/react/src/views/AttachmentHandler/ImageAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
@@ -1,32 +1,81 @@
-import React, { useState } from 'react';
+import React, { useState, useContext } from 'react';
import { css } from '@emotion/react';
import PropTypes from 'prop-types';
-import { Box } from '@embeddedchat/ui-elements';
+import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import AttachmentMetadata from './AttachmentMetadata';
import ImageGallery from '../ImageGallery/ImageGallery';
+import RCContext from '../../context/RCInstance';
-const ImageAttachment = ({ attachment, host, variantStyles = {} }) => {
+const ImageAttachment = ({
+ attachment,
+ host,
+ type,
+ author,
+ variantStyles = {},
+}) => {
+ const { RCInstance } = useContext(RCContext);
const [showGallery, setShowGallery] = useState(false);
+ const getUserAvatarUrl = (icon) => {
+ const instanceHost = RCInstance.getHost();
+ const URL = `${instanceHost}${icon}`;
+ return URL;
+ };
const extractIdFromUrl = (url) => {
const match = url.match(/\/file-upload\/(.*?)\//);
return match ? match[1] : null;
};
+ const { theme } = useTheme();
+
+ const { authorIcon, authorName } = author;
+
return (
-
setShowGallery(true)}
- css={css`
- cursor: pointer;
- border-radius: inherit;
- line-height: 0;
- `}
+ css={[
+ css`
+ cursor: pointer;
+ border-radius: inherit;
+ line-height: 0;
+ padding: 0.5rem;
+ `,
+ (type ? variantStyles.pinnedContainer : '') ||
+ css`
+ ${type === 'file'
+ ? `border: 2px solid ${theme.colors.border};`
+ : ''}
+ `,
+ ]}
>
+ {type === 'file' ? (
+ <>
+
+
+ @{authorName}
+
+ >
+ ) : (
+ ''
+ )}
+
{
borderBottomRightRadius: 'inherit',
}}
/>
+ {attachment.attachments &&
+ attachment.attachments.map((nestedAttachment, index) => (
+
+ setShowGallery(true)}
+ css={[
+ css`
+ cursor: pointer;
+ border-radius: inherit;
+ line-height: 0;
+ padding: 0.5rem;
+ `,
+ (nestedAttachment.attachments[0].type
+ ? variantStyles.pinnedContainer
+ : variantStyles.quoteContainer) ||
+ css`
+ ${nestedAttachment.attachments[0].type === 'file'
+ ? `border: 2px solid ${theme.colors.border};`
+ : ''}
+ `,
+ ]}
+ >
+ {nestedAttachment.type === 'file' ? (
+ <>
+
+
+ @{nestedAttachment.author_name}
+
+ >
+ ) : (
+ ''
+ )}
+
+
+
+ {showGallery && (
+
+ )}
+
+ ))}
{showGallery && (
{
return URL;
};
- let attachmentText = attachment?.text;
- if (attachmentText.includes(')')) {
- attachmentText = attachmentText.split(')')[1] || '';
- }
-
const { theme } = useTheme();
return (
@@ -67,7 +62,77 @@ const TextAttachment = ({ attachment, type, variantStyles = {} }) => {
white-space: pre-line;
`}
>
- {attachmentText}
+ {attachment?.text
+ ? attachment.text[0] === '['
+ ? attachment.text.match(/\n(.*)/)?.[1] || ''
+ : attachment.text
+ : ''}
+ {attachment?.attachments &&
+ attachment.attachments.map((nestedAttachment, index) => (
+
+
+ {nestedAttachment?.author_name && (
+ <>
+
+ @{nestedAttachment?.author_name}
+ >
+ )}
+
+
+ {nestedAttachment?.text
+ ? nestedAttachment.text[0] === '['
+ ? nestedAttachment.text.match(/\n(.*)/)?.[1] || ''
+ : nestedAttachment.text
+ : ''}
+
+
+ ))}
);
diff --git a/packages/react/src/views/AttachmentHandler/VideoAttachment.js b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
index 0472d34c21..06e3453167 100644
--- a/packages/react/src/views/AttachmentHandler/VideoAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
@@ -1,8 +1,9 @@
-import React from 'react';
+import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
-import { Box } from '@embeddedchat/ui-elements';
+import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import AttachmentMetadata from './AttachmentMetadata';
+import RCContext from '../../context/RCInstance';
const userAgentMIMETypeFallback = (type) => {
const userAgent = navigator.userAgent.toLocaleLowerCase();
@@ -14,35 +15,152 @@ const userAgentMIMETypeFallback = (type) => {
return type;
};
-const VideoAttachment = ({ attachment, host, variantStyles = {} }) => (
-
-
-
-
+
+ {attachment.attachments &&
+ attachment.attachments.map((nestedAttachment, index) => (
+
+
+ {nestedAttachment.type === 'file' ? (
+ <>
+
+
+ @{authorName}
+
+ >
+ ) : (
+ ''
+ )}
+
+
+
+
+ ))}
+
-
-);
+ );
+};
export default VideoAttachment;
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index eae9573aed..581cbf0d26 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -90,20 +90,20 @@ const ChatInput = ({ scrollToBottom }) => {
editMessage,
setEditMessage,
quoteMessage,
- setQuoteMessage,
isRecordingMessage,
upsertMessage,
replaceMessage,
+ clearQuoteMessages,
threadId,
} = useMessageStore((state) => ({
editMessage: state.editMessage,
setEditMessage: state.setEditMessage,
quoteMessage: state.quoteMessage,
- setQuoteMessage: state.setQuoteMessage,
isRecordingMessage: state.isRecordingMessage,
upsertMessage: state.upsertMessage,
replaceMessage: state.replaceMessage,
threadId: state.threadMainMessage?._id,
+ clearQuoteMessages: state.clearQuoteMessages,
}));
const setIsLoginModalOpen = useLoginStore(
@@ -255,14 +255,31 @@ const ChatInput = ({ scrollToBottom }) => {
messageRef.current.value = '';
setDisableButton(true);
- const { msg, attachments, _id } = quoteMessage;
let pendingMessage = '';
-
- if (msg || attachments) {
- setQuoteMessage({});
- const msgLink = await getMessageLink(_id);
+ let quotedMessages = '';
+
+ if (quoteMessage.length > 0) {
+ // for (const quote of quoteMessage) {
+ // const { msg, attachments, _id } = quote;
+ // if (msg || attachments) {
+ // const msgLink = await getMessageLink(_id);
+ // quotedMessages += `[ ](${msgLink})`;
+ // }
+ // }
+
+ const quoteArray = await Promise.all(
+ quoteMessage.map(async (quote) => {
+ const { msg, attachments, _id } = quote;
+ if (msg || attachments) {
+ const msgLink = await getMessageLink(_id);
+ quotedMessages += `[ ](${msgLink})`;
+ }
+ return quotedMessages;
+ })
+ );
+ quotedMessages = quoteArray.join('');
pendingMessage = createPendingMessage(
- `[ ](${msgLink})\n ${message}`,
+ `${quotedMessages}\n${message}`,
userInfo
);
} else {
@@ -283,10 +300,9 @@ const ChatInput = ({ scrollToBottom }) => {
ECOptions.enableThreads ? threadId : undefined
);
- if (!res.success) {
- handleSendError('Error sending message, login again');
- } else {
- replaceMessage(pendingMessage._id, res.message);
+ if (res.success) {
+ clearQuoteMessages();
+ replaceMessage(pendingMessage, res.message);
}
};
@@ -425,14 +441,14 @@ const ChatInput = ({ scrollToBottom }) => {
return (
-
- {(quoteMessage.msg || quoteMessage.attachments) && (
-
- )}
+
+
+ {quoteMessage &&
+ quoteMessage.length > 0 &&
+ quoteMessage.map((message, index) => (
+
+ ))}
+
{editMessage.msg || editMessage.attachments || isChannelReadOnly ? (
{
font-size: 18px;
}
`,
+ quoteContainer: css`
+ max-height: 300px;
+ overflow: scroll;
+ `,
};
return styles;
diff --git a/packages/react/src/views/Message/BubbleVariant/Bubble.styles.js b/packages/react/src/views/Message/BubbleVariant/Bubble.styles.js
index 42f978f9eb..5f87c0b5e4 100644
--- a/packages/react/src/views/Message/BubbleVariant/Bubble.styles.js
+++ b/packages/react/src/views/Message/BubbleVariant/Bubble.styles.js
@@ -94,7 +94,7 @@ export const getBubbleStyles = (theme) => {
overflow: hidden;
`,
pinnedContainer: css`
- max-width: 80%;
+ max-width: 100%;
`,
quoteContainer: css`
@@ -112,7 +112,7 @@ export const getBubbleStyles = (theme) => {
`,
attachmentMetaContainer: css`
- padding: 2.5% 2.5% 0;
+ padding: 2.5% 0 0;
`,
emojiPickerStyles: css`
@@ -172,7 +172,7 @@ export const getBubbleStylesMe = (theme) => {
pinnedContainerMe: css`
border-inline-start: none;
- border-inline-end: 3px solid ${theme.colors.border};
+ border-inline-end: none;
`,
textUserInfoMe: css`
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 64d2050f09..7f7fde3752 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -58,7 +58,7 @@ const Message = ({
const [setMessageToReport, toggleShowReportMessage] = useMessageStore(
(state) => [state.setMessageToReport, state.toggleShowReportMessage]
);
- const setQuoteMessage = useMessageStore((state) => state.setQuoteMessage);
+ const addQuoteMessage = useMessageStore((state) => state.addQuoteMessage);
const openThread = useMessageStore((state) => state.openThread);
const dispatchToastMessage = useToastBarDispatch();
@@ -218,7 +218,7 @@ const Message = ({
setEditMessage(message);
}
}}
- handleQuoteMessage={() => setQuoteMessage(message)}
+ handleQuoteMessage={() => addQuoteMessage(message)}
handleEmojiClick={handleEmojiClick}
handlerReportMessage={() => {
setMessageToReport(message._id);
diff --git a/packages/react/src/views/QuoteMessage/QuoteMessage.js b/packages/react/src/views/QuoteMessage/QuoteMessage.js
index fab425ebaa..be715cf0ed 100644
--- a/packages/react/src/views/QuoteMessage/QuoteMessage.js
+++ b/packages/react/src/views/QuoteMessage/QuoteMessage.js
@@ -11,17 +11,21 @@ import {
import RCContext from '../../context/RCInstance';
import { useMessageStore } from '../../store';
import getQuoteMessageStyles from './QuoteMessage.styles';
+import Attachment from '../AttachmentHandler/Attachment';
const QuoteMessage = ({ className = '', style = {}, message }) => {
const { RCInstance } = useContext(RCContext);
+ const instanceHost = RCInstance.getHost();
const getUserAvatarUrl = (username) => {
- const host = RCInstance.getHost();
+ const host = instanceHost;
const URL = `${host}/avatar/${username}`;
return URL;
};
const { theme } = useTheme();
const styles = getQuoteMessageStyles(theme);
- const setQuoteMessage = useMessageStore((state) => state.setQuoteMessage);
+ const removeQuoteMessage = useMessageStore(
+ (state) => state.removeQuoteMessage
+ );
const { classNames, styleOverrides } = useComponentOverrides('QuoteMessage');
return (
@@ -31,7 +35,11 @@ const QuoteMessage = ({ className = '', style = {}, message }) => {
css={styles.messageContainer}
>
- setQuoteMessage({})} size="small">
+ removeQuoteMessage(message)}
+ size="small"
+ >
@@ -45,11 +53,62 @@ const QuoteMessage = ({ className = '', style = {}, message }) => {
{format(new Date(message.ts), 'h:mm a')}
- {message.msg
- ? message.msg
- : `${message.file?.name} (${
- message.file?.size ? (message.file.size / 1024).toFixed(2) : 0
- } kB)`}
+ {message.file ? (
+ message.file.type.startsWith('image/') ? (
+
+

+
{`${message.file.name} (${(message.file.size / 1024).toFixed(
+ 2
+ )} kB)`}
+
+ ) : message.file.type.startsWith('video/') ? (
+
+ ) : message.file.type.startsWith('audio/') ? (
+
+ ) : (
+
+ {message.msg
+ ? message.msg
+ : `${message.file?.name} (${
+ message.file?.size
+ ? (message.file.size / 1024).toFixed(2)
+ : 0
+ } kB)`}
+
+ )
+ ) : message?.msg[0] === '[' ? (
+ message?.msg.match(/\n(.*)/)[1]
+ ) : (
+ message?.msg
+ )}
+ {message.attachments &&
+ message.attachments.length > 0 &&
+ message.msg &&
+ message.msg[0] === '[' &&
+ message.attachments.map((attachment, index) => (
+
+ ))}
);
From 28a82023953ea9316b1687574dcbe97647a992ed Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:45:08 +0530
Subject: [PATCH 022/153] Feat: Added Scroll-to-Message Functionality (#667)
* Added go to Message Feature
* fix linting issues
* Implement jump to message functionality
* Fix linting
* Append msg to URL
* Remove appending in URL
* Fix popup mode issue
---
.../common/MessageAggregator.js | 64 +++++++++++++++----
1 file changed, 50 insertions(+), 14 deletions(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 079582e86a..58fccff3c4 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -1,10 +1,17 @@
import React, { useState, useMemo } from 'react';
import { isSameDay, format } from 'date-fns';
-import { Box, Sidebar, Popup, useTheme } from '@embeddedchat/ui-elements';
+import {
+ Box,
+ Sidebar,
+ Popup,
+ useTheme,
+ ActionButton,
+ Icon,
+} from '@embeddedchat/ui-elements';
import { MessageDivider } from '../../Message/MessageDivider';
import Message from '../../Message/Message';
import getMessageAggregatorStyles from './MessageAggregator.styles';
-import { useMessageStore } from '../../../store';
+import { useMessageStore, useSidebarStore } from '../../../store';
import { useSetMessageList } from '../../../hooks/useSetMessageList';
import LoadingIndicator from './LoadingIndicator';
import NoMessagesIndicator from './NoMessageIndicator';
@@ -37,6 +44,17 @@ export const MessageAggregator = ({
shouldRender
);
+ const setShowSidebar = useSidebarStore((state) => state.setShowSidebar);
+ const setJumpToMessage = (msgId) => {
+ if (msgId) {
+ const element = document.getElementById(`ec-message-body-${msgId}`);
+ if (element) {
+ setShowSidebar(false);
+ element.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ }
+ }
+ };
+
const isMessageNewDay = (current, previous) =>
!previous ||
!shouldRender(previous) ||
@@ -90,20 +108,38 @@ export const MessageAggregator = ({
fileMessage={msg}
/>
) : (
-
+ >
+
+
+ setJumpToMessage(msg._id)}
+ css={{
+ position: 'relative',
+ zIndex: 10,
+ }}
+ >
+
+
+
)}
);
From f64a3a6525436636abf75d1cffc4463096d36ac6 Mon Sep 17 00:00:00 2001
From: Rahul Singh Thakur <65606499+Barrylimarti@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:48:45 +0530
Subject: [PATCH 023/153] Fix: Sidebar starred messages fetched by api to
include thread messages. (#669)
* fetch starred message api called
* starred messages fetching from api
* ran prettier
* fixed linting errors
---
packages/react/src/hooks/useFetchChatData.js | 23 +++++++++++++-
.../react/src/store/starredMessageStore.js | 2 ++
packages/react/src/views/ChatBody/ChatBody.js | 2 +-
.../react/src/views/ChatHeader/ChatHeader.js | 2 +-
.../react/src/views/ChatLayout/ChatLayout.js | 30 +++++++++++++++++--
packages/react/src/views/Message/Message.js | 4 ++-
.../MessageAggregators/StarredMessages.js | 8 +++--
.../common/MessageAggregator.js | 5 ++--
8 files changed, 65 insertions(+), 11 deletions(-)
diff --git a/packages/react/src/hooks/useFetchChatData.js b/packages/react/src/hooks/useFetchChatData.js
index 1d08f0eaf4..99c48aa1e4 100644
--- a/packages/react/src/hooks/useFetchChatData.js
+++ b/packages/react/src/hooks/useFetchChatData.js
@@ -5,6 +5,7 @@ import {
useChannelStore,
useMemberStore,
useMessageStore,
+ useStarredMessageStore,
} from '../store';
const useFetchChatData = (showRoles) => {
@@ -13,6 +14,9 @@ const useFetchChatData = (showRoles) => {
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
const setMessages = useMessageStore((state) => state.setMessages);
const setAdmins = useMemberStore((state) => state.setAdmins);
+ const setStarredMessages = useStarredMessageStore(
+ (state) => state.setStarredMessages
+ );
const isUserAuthenticated = useUserStore(
(state) => state.isUserAuthenticated
);
@@ -80,7 +84,24 @@ const useFetchChatData = (showRoles) => {
]
);
- return getMessagesAndRoles;
+ const getStarredMessages = useCallback(
+ async (anonymousMode) => {
+ if (isUserAuthenticated) {
+ try {
+ if (!isUserAuthenticated && !anonymousMode) {
+ return;
+ }
+ const { messages } = await RCInstance.getStarredMessages();
+ setStarredMessages(messages);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ },
+ [isUserAuthenticated, RCInstance, setStarredMessages]
+ );
+
+ return { getMessagesAndRoles, getStarredMessages };
};
export default useFetchChatData;
diff --git a/packages/react/src/store/starredMessageStore.js b/packages/react/src/store/starredMessageStore.js
index a564df3c41..989ec8b6fb 100644
--- a/packages/react/src/store/starredMessageStore.js
+++ b/packages/react/src/store/starredMessageStore.js
@@ -3,6 +3,8 @@ import { create } from 'zustand';
const useStarredMessageStore = create((set) => ({
showStarred: false,
setShowStarred: (showStarred) => set(() => ({ showStarred })),
+ starredMessages: [],
+ setStarredMessages: (messages) => set(() => ({ starredMessages: messages })),
}));
export default useStarredMessageStore;
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index e5a6bd1a33..a582244d0f 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -69,7 +69,7 @@ const ChatBody = ({
const username = useUserStore((state) => state.username);
- const getMessagesAndRoles = useFetchChatData(showRoles);
+ const { getMessagesAndRoles } = useFetchChatData(showRoles);
const getThreadMessages = useCallback(async () => {
if (isUserAuthenticated && threadMainMessage?._id) {
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 7c43056a65..99babdc51a 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -86,7 +86,7 @@ const ChatHeader = ({
);
const dispatchToastMessage = useToastBarDispatch();
- const getMessagesAndRoles = useFetchChatData(showRoles);
+ const { getMessagesAndRoles } = useFetchChatData(showRoles);
const setMessageLimit = useSettingsStore((state) => state.setMessageLimit);
const setMessages = useMessageStore((state) => state.setMessages);
const avatarUrl = useUserStore((state) => state.avatarUrl);
diff --git a/packages/react/src/views/ChatLayout/ChatLayout.js b/packages/react/src/views/ChatLayout/ChatLayout.js
index 6243dc0cc8..ee6b0c1b94 100644
--- a/packages/react/src/views/ChatLayout/ChatLayout.js
+++ b/packages/react/src/views/ChatLayout/ChatLayout.js
@@ -1,4 +1,4 @@
-import React, { useRef } from 'react';
+import React, { useEffect, useRef, useCallback, useState } from 'react';
import { Box, useComponentOverrides } from '@embeddedchat/ui-elements';
import styles from './ChatLayout.styles';
import {
@@ -36,9 +36,15 @@ import useUiKitStore from '../../store/uiKitStore';
const ChatLayout = () => {
const messageListRef = useRef(null);
const { classNames, styleOverrides } = useComponentOverrides('ChatBody');
- const { ECOptions } = useRCContext();
+ const { RCInstance, ECOptions } = useRCContext();
const anonymousMode = ECOptions?.anonymousMode;
const showRoles = ECOptions?.anonymousMode;
+ const setStarredMessages = useStarredMessageStore(
+ (state) => state.setStarredMessages
+ );
+ const starredMessages = useStarredMessageStore(
+ (state) => state.starredMessages
+ );
const showSidebar = useSidebarStore((state) => state.showSidebar);
const showMentions = useMentionsStore((state) => state.showMentions);
const showAllFiles = useFileStore((state) => state.showAllFiles);
@@ -57,6 +63,9 @@ const ChatLayout = () => {
const attachmentWindowOpen = useAttachmentWindowStore(
(state) => state.attachmentWindowOpen
);
+ const isUserAuthenticated = useUserStore(
+ (state) => state.isUserAuthenticated
+ );
const { data, handleDrag, handleDragDrop } = useDropBox();
const { uiKitContextualBarOpen, uiKitContextualBarData } = useUiKitStore(
(state) => ({
@@ -72,7 +81,22 @@ const ChatLayout = () => {
});
}
};
-
+ const getStarredMessages = useCallback(async () => {
+ if (isUserAuthenticated) {
+ try {
+ if (!isUserAuthenticated && !anonymousMode) {
+ return;
+ }
+ const { messages } = await RCInstance.getStarredMessages();
+ setStarredMessages(messages);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }, [isUserAuthenticated, anonymousMode, RCInstance]);
+ useEffect(() => {
+ getStarredMessages();
+ }, [showSidebar]);
return (
state.addQuoteMessage);
const openThread = useMessageStore((state) => state.openThread);
-
+ const { getStarredMessages } = useFetchChatData();
const dispatchToastMessage = useToastBarDispatch();
const { editMessage, setEditMessage } = useMessageStore((state) => ({
editMessage: state.editMessage,
@@ -92,6 +93,7 @@ const Message = ({
message: 'Message unstarred',
});
}
+ getStarredMessages();
};
const handlePinMessage = async (msg) => {
diff --git a/packages/react/src/views/MessageAggregators/StarredMessages.js b/packages/react/src/views/MessageAggregators/StarredMessages.js
index b7d77b864e..5ced944f06 100644
--- a/packages/react/src/views/MessageAggregators/StarredMessages.js
+++ b/packages/react/src/views/MessageAggregators/StarredMessages.js
@@ -1,12 +1,15 @@
-import React, { useCallback } from 'react';
+import React, { useCallback, useEffect } from 'react';
import { useComponentOverrides } from '@embeddedchat/ui-elements';
-import { useUserStore } from '../../store';
+import { useStarredMessageStore, useUserStore } from '../../store';
import { MessageAggregator } from './common/MessageAggregator';
const StarredMessages = () => {
const authenticatedUserId = useUserStore((state) => state.userId);
const { variantOverrides } = useComponentOverrides('StarredMessages');
const viewType = variantOverrides.viewType || 'Sidebar';
+ const starredMessages = useStarredMessageStore(
+ (state) => state.starredMessages
+ );
const shouldRender = useCallback(
(msg) =>
msg.starred &&
@@ -18,6 +21,7 @@ const StarredMessages = () => {
title="Starred Messages"
iconName="star"
noMessageInfo="No Starred Messages"
+ fetchedMessageList={starredMessages}
shouldRender={shouldRender}
viewType={viewType}
/>
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 58fccff3c4..3f4f62e730 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -23,6 +23,7 @@ export const MessageAggregator = ({
iconName,
noMessageInfo,
shouldRender,
+ fetchedMessageList,
searchProps,
searchFiltered,
fetching,
@@ -40,7 +41,7 @@ export const MessageAggregator = ({
);
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
- searchFiltered || allMessages,
+ fetchedMessageList || searchFiltered || allMessages,
shouldRender
);
@@ -57,7 +58,7 @@ export const MessageAggregator = ({
const isMessageNewDay = (current, previous) =>
!previous ||
- !shouldRender(previous) ||
+ shouldRender(previous) ||
!isSameDay(new Date(current.ts), new Date(previous.ts));
const noMessages = messageList?.length === 0 || !messageRendered;
From 10584052690572433dfae0103229189379e8b7af Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Tue, 17 Dec 2024 09:27:43 +0530
Subject: [PATCH 024/153] fix: ensure pin permission changes reflect without
requiring user logout (#688)
---
packages/react/src/views/EmbeddedChat.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/packages/react/src/views/EmbeddedChat.js b/packages/react/src/views/EmbeddedChat.js
index 2dc8379879..a7e258b442 100644
--- a/packages/react/src/views/EmbeddedChat.js
+++ b/packages/react/src/views/EmbeddedChat.js
@@ -83,6 +83,9 @@ const EmbeddedChat = (props) => {
}));
const setIsLoginIn = useLoginStore((state) => state.setIsLoginIn);
+ const setUserPinPermissions = useUserStore(
+ (state) => state.setUserPinPermissions
+ );
if (isClosable && !setClosableState) {
throw Error(
@@ -125,6 +128,8 @@ const EmbeddedChat = (props) => {
setIsLoginIn(true);
try {
await RCInstance.autoLogin(auth);
+ const permissions = await RCInstance.permissionInfo();
+ setUserPinPermissions(permissions.update[150]);
} catch (error) {
console.error(error);
} finally {
From 9a3b7ac93c3a2233ab7ceb2d49d205317cde8b16 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 22 Dec 2024 13:57:01 +0530
Subject: [PATCH 025/153] Fixed UI issues for Sidebar (#634)
* Fixed UI issues for Sidebar
* Fixed sidebar height issue
* Removed unnecessary spacing
* Fixed reply in thread issue
* Adjusted dynamic header visibility
* Revert zIndex changes
* Linting fix
* Run prettier
* Remove zIndex
* Adjusted zIndex for ViewComponent
* Fix sidebar width
* Remove global css for sidebar
---------
Co-authored-by: Zishan Ahmad
---
packages/react/src/views/ChatHeader/ChatHeader.js | 4 +++-
packages/react/src/views/GlobalStyles.js | 12 +++++++++++-
packages/react/src/views/Message/Message.js | 5 +++--
packages/react/src/views/Message/Message.styles.js | 3 +++
.../MessageAggregators/common/MessageAggregator.js | 9 ++++++++-
.../src/views/RoomInformation/RoomInformation.js | 1 +
packages/react/src/views/RoomMembers/RoomMember.js | 1 +
7 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 99babdc51a..0107399771 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -21,6 +21,7 @@ import {
usePinnedMessageStore,
useStarredMessageStore,
useFileStore,
+ useSidebarStore,
} from '../../store';
import { DynamicHeader } from '../DynamicHeader';
import useFetchChatData from '../../hooks/useFetchChatData';
@@ -84,7 +85,7 @@ const ChatHeader = ({
const setIsUserAuthenticated = useUserStore(
(state) => state.setIsUserAuthenticated
);
-
+ const setShowSidebar = useSidebarStore((state) => state.setShowSidebar);
const dispatchToastMessage = useToastBarDispatch();
const { getMessagesAndRoles } = useFetchChatData(showRoles);
const setMessageLimit = useSettingsStore((state) => state.setMessageLimit);
@@ -130,6 +131,7 @@ const ChatHeader = ({
try {
await RCInstance.logout();
setMessages([]);
+ setShowSidebar(false);
setUserAvatarUrl(null);
useMessageStore.setState({ isMessageLoaded: false });
} catch (e) {
diff --git a/packages/react/src/views/GlobalStyles.js b/packages/react/src/views/GlobalStyles.js
index b26977e635..c9c821feff 100644
--- a/packages/react/src/views/GlobalStyles.js
+++ b/packages/react/src/views/GlobalStyles.js
@@ -8,7 +8,6 @@ const getGlobalStyles = (theme) => css`
margin: 0;
padding: 0;
}
-
.ec-embedded-chat body {
font-family: ${theme.typography.default.fontFamily};
font-size: ${theme.typography.default.fontSize}px;
@@ -36,6 +35,17 @@ const getGlobalStyles = (theme) => css`
.ec-embedded-chat ::-webkit-scrollbar-button {
display: none;
}
+ @media (max-width: 780px) {
+ .ec-sidebar {
+ position: absolute;
+ width: 100% !important;
+ height: calc(100% - 56.39px) !important;
+ min-width: 250px !important;
+ left: 0;
+ bottom: 0;
+ background: ${theme.colors.background}!important;
+ }
+ }
`;
const GlobalStyles = () => {
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index e460adad0d..b587d09e11 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -11,7 +11,7 @@ import {
import { Attachments } from '../AttachmentHandler';
import { Markdown } from '../Markdown';
import MessageHeader from './MessageHeader';
-import { useMessageStore, useUserStore } from '../../store';
+import { useMessageStore, useUserStore, useSidebarStore } from '../../store';
import RCContext from '../../context/RCInstance';
import { MessageBody } from './MessageBody';
import { MessageReactions } from './MessageReactions';
@@ -49,7 +49,7 @@ const Message = ({
const { RCInstance, ECOptions } = useContext(RCContext);
showAvatar = ECOptions?.showAvatar && showAvatar;
-
+ const { showSidebar, setShowSidebar } = useSidebarStore();
const authenticatedUserId = useUserStore((state) => state.userId);
const authenticatedUserUsername = useUserStore((state) => state.username);
const userRoles = useUserStore((state) => state.roles);
@@ -137,6 +137,7 @@ const Message = ({
const handleOpenThread = (msg) => async () => {
openThread(msg);
+ setShowSidebar(false);
};
const isStarred = message.starred?.find((u) => u._id === authenticatedUserId);
diff --git a/packages/react/src/views/Message/Message.styles.js b/packages/react/src/views/Message/Message.styles.js
index b6b978fb4c..9f9358fd92 100644
--- a/packages/react/src/views/Message/Message.styles.js
+++ b/packages/react/src/views/Message/Message.styles.js
@@ -81,6 +81,9 @@ export const getMessageDividerStyles = (theme) => {
margin-bottom: 0.75rem;
padding-left: 1.25rem;
padding-right: 1.25rem;
+ @media (max-width: 780px) {
+ z-index: 1;
+ }
`,
dividerContent: css`
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 3f4f62e730..6e1786a339 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -70,7 +70,11 @@ export const MessageAggregator = ({
iconName={iconName}
searchProps={searchProps}
onClose={() => setExclusiveState(null)}
- style={{ padding: 0 }}
+ style={{
+ width: '400px',
+ padding: 0,
+ zIndex: window.innerWidth <= 780 ? 1 : null,
+ }}
{...(viewType === 'Popup'
? {
isPopupHeader: true,
@@ -126,6 +130,9 @@ export const MessageAggregator = ({
isInSidebar
style={{
flex: 1,
+ paddingLeft: 3,
+ paddingRight: 2,
+ minWidth: 0,
}}
/>
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.js b/packages/react/src/views/RoomInformation/RoomInformation.js
index 504b0f4ba8..3cfdefad08 100644
--- a/packages/react/src/views/RoomInformation/RoomInformation.js
+++ b/packages/react/src/views/RoomInformation/RoomInformation.js
@@ -30,6 +30,7 @@ const Roominfo = () => {
title="Room Information"
iconName="info"
onClose={() => setExclusiveState(null)}
+ style={{ width: '400px', zIndex: window.innerWidth <= 780 ? 1 : null }}
{...(viewType === 'Popup'
? {
isPopupHeader: true,
diff --git a/packages/react/src/views/RoomMembers/RoomMember.js b/packages/react/src/views/RoomMembers/RoomMember.js
index c52f48c9dd..85b268b07a 100644
--- a/packages/react/src/views/RoomMembers/RoomMember.js
+++ b/packages/react/src/views/RoomMembers/RoomMember.js
@@ -55,6 +55,7 @@ const RoomMembers = ({ members }) => {
title="Members"
iconName="members"
onClose={() => setExclusiveState(null)}
+ style={{ width: '400px', zIndex: window.innerWidth <= 780 ? 1 : null }}
{...(viewType === 'Popup'
? {
isPopupHeader: true,
From 3d6700c2f93cc9bb9eb4bd54fdfec4009befca6b Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sun, 22 Dec 2024 14:21:20 +0530
Subject: [PATCH 026/153] fix(permissions): ensure admin-granted edit message
permissions apply in EmbeddedChat (#702)
---
packages/react/src/hooks/useRCAuth.js | 11 ++++++++++-
packages/react/src/store/messageStore.js | 3 +++
packages/react/src/views/EmbeddedChat.js | 6 +++++-
packages/react/src/views/Message/Message.js | 5 +++++
packages/react/src/views/Message/MessageToolbox.js | 8 +++++++-
5 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/packages/react/src/hooks/useRCAuth.js b/packages/react/src/hooks/useRCAuth.js
index 6a997cb569..c0b1d3a3b4 100644
--- a/packages/react/src/hooks/useRCAuth.js
+++ b/packages/react/src/hooks/useRCAuth.js
@@ -1,7 +1,12 @@
import { useContext } from 'react';
import { useToastBarDispatch } from '@embeddedchat/ui-elements';
import RCContext from '../context/RCInstance';
-import { useUserStore, totpModalStore, useLoginStore } from '../store';
+import {
+ useUserStore,
+ totpModalStore,
+ useLoginStore,
+ useMessageStore,
+} from '../store';
export const useRCAuth = () => {
const { RCInstance } = useContext(RCContext);
@@ -23,6 +28,9 @@ export const useRCAuth = () => {
const setUserPinPermissions = useUserStore(
(state) => state.setUserPinPermissions
);
+ const setEditMessagePermissions = useMessageStore(
+ (state) => state.setEditMessagePermissions
+ );
const dispatchToastMessage = useToastBarDispatch();
const handleLogin = async (userOrEmail, password, code) => {
@@ -61,6 +69,7 @@ export const useRCAuth = () => {
setEmailorUser(null);
setPassword(null);
setUserPinPermissions(permissions.update[150]);
+ setEditMessagePermissions(permissions.update[28]);
dispatchToastMessage({
type: 'success',
message: 'Successfully logged in',
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index 507ba3d141..676258c1c4 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -71,6 +71,9 @@ const useMessageStore = create((set, get) => ({
}
},
setEditMessage: (editMessage) => set(() => ({ editMessage })),
+ editMessagePermissions: {},
+ setEditMessagePermissions: (editMessagePermissions) =>
+ set((state) => ({ ...state, editMessagePermissions })),
addQuoteMessage: (quoteMessage) =>
set((state) => ({ quoteMessage: [...state.quoteMessage, quoteMessage] })),
removeQuoteMessage: (quoteMessage) =>
diff --git a/packages/react/src/views/EmbeddedChat.js b/packages/react/src/views/EmbeddedChat.js
index a7e258b442..00557f289c 100644
--- a/packages/react/src/views/EmbeddedChat.js
+++ b/packages/react/src/views/EmbeddedChat.js
@@ -18,7 +18,7 @@ import {
import { ChatLayout } from './ChatLayout';
import { ChatHeader } from './ChatHeader';
import { RCInstanceProvider } from '../context/RCInstance';
-import { useUserStore, useLoginStore } from '../store';
+import { useUserStore, useLoginStore, useMessageStore } from '../store';
import DefaultTheme from '../theme/DefaultTheme';
import { getTokenStorage } from '../lib/auth';
import { styles } from './EmbeddedChat.styles';
@@ -87,6 +87,9 @@ const EmbeddedChat = (props) => {
(state) => state.setUserPinPermissions
);
+ const setEditMessagePermissions = useMessageStore(
+ (state) => state.setEditMessagePermissions
+ );
if (isClosable && !setClosableState) {
throw Error(
'Please provide a setClosableState to props when isClosable = true'
@@ -130,6 +133,7 @@ const EmbeddedChat = (props) => {
await RCInstance.autoLogin(auth);
const permissions = await RCInstance.permissionInfo();
setUserPinPermissions(permissions.update[150]);
+ setEditMessagePermissions(permissions.update[28]);
} catch (error) {
console.error(error);
} finally {
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index b587d09e11..aafb5642b5 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -56,6 +56,9 @@ const Message = ({
const pinPermissions = useUserStore(
(state) => state.userPinPermissions.roles
);
+ const editMessagePermissions = useMessageStore(
+ (state) => state.editMessagePermissions.roles
+ );
const [setMessageToReport, toggleShowReportMessage] = useMessageStore(
(state) => [state.setMessageToReport, state.toggleShowReportMessage]
);
@@ -73,6 +76,7 @@ const Message = ({
const styles = getMessageStyles(theme);
const bubbleStyles = useBubbleStyles(isMe);
const pinRoles = new Set(pinPermissions);
+ const editMessageRoles = new Set(editMessagePermissions);
const variantStyles =
!isInSidebar && variantOverrides === 'bubble' ? bubbleStyles : {};
@@ -210,6 +214,7 @@ const Message = ({
authenticatedUserId={authenticatedUserId}
userRoles={userRoles}
pinRoles={pinRoles}
+ editMessageRoles={editMessageRoles}
handleOpenThread={handleOpenThread}
handleDeleteMessage={handleDeleteMessage}
handleStarMessage={handleStarMessage}
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 55af7f64d5..61765c8dd9 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -23,6 +23,7 @@ export const MessageToolbox = ({
authenticatedUserId,
userRoles,
pinRoles,
+ editMessageRoles,
handleOpenThread,
handleEmojiClick,
handlePinMessage,
@@ -70,6 +71,11 @@ export const MessageToolbox = ({
};
const isAllowedToPin = userRoles.some((role) => pinRoles.has(role));
+ const isAllowedToEditMessage = userRoles.some((role) =>
+ editMessageRoles.has(role)
+ )
+ ? true
+ : message.u._id === authenticatedUserId;
const options = useMemo(
() => ({
reply: {
@@ -120,7 +126,7 @@ export const MessageToolbox = ({
id: 'edit',
onClick: () => handleEditMessage(message),
iconName: 'edit',
- visible: message.u._id === authenticatedUserId,
+ visible: isAllowedToEditMessage,
color: isEditing ? 'secondary' : 'default',
ghost: !isEditing,
},
From 0d7ff8d496326394a21191127b1f8579b209ec54 Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Sun, 22 Dec 2024 14:38:04 +0530
Subject: [PATCH 027/153] fixed all markdown issues (#614)
* fix mardown
* fix conflicts
* fix formatting issues
* fixed lint issues
* changes
* prettier
* fix quote
* fixed
* removed markdown from passed prop
---------
Co-authored-by: Zishan Ahmad
---
packages/react/src/views/ChatInput/ChatInput.js | 1 +
.../react/src/views/Message/MessageToolbox.js | 4 ++--
.../src/views/QuoteMessage/QuoteMessage.js | 17 +++++++++--------
3 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 581cbf0d26..86b4b5082a 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -34,6 +34,7 @@ import useShowCommands from '../../hooks/useShowCommands';
import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import formatSelection from '../../lib/formatSelection';
import { parseEmoji } from '../../lib/emoji';
+import { Markdown } from '../Markdown';
const ChatInput = ({ scrollToBottom }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 61765c8dd9..0ed468bd7a 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -10,9 +10,9 @@ import {
useTheme,
} from '@embeddedchat/ui-elements';
import { EmojiPicker } from '../EmojiPicker';
-import { parseEmoji } from '../../lib/emoji';
import { getMessageToolboxStyles } from './Message.styles';
import SurfaceMenu from '../SurfaceMenu/SurfaceMenu';
+import { Markdown } from '../Markdown';
export const MessageToolbox = ({
className = '',
@@ -249,7 +249,7 @@ export const MessageToolbox = ({
padding: '0 0.5rem 0.5rem',
}}
>
- {parseEmoji(message.msg)}
+
+ {currentUserInfo?.statusText && (
+
+ {currentUserInfo?.statusText}
+
+ )}
+ {currentUserInfo?.nickname && (
+
+ )}
{currentUserInfo?.roles?.length && (
{
))}
}
- isAdmin={isAdmin}
+ isAdmin={isAllowedToViewFullInfo}
authenticatedUserId={authenticatedUserId}
currentUserInfo={currentUserInfo}
/>
@@ -121,7 +145,7 @@ const UserInformation = () => {
@@ -132,17 +156,26 @@ const UserInformation = () => {
? 'Never'
: formatTimestamp(currentUserInfo.lastLogin)
}
- isAdmin={isAdmin}
+ isAdmin={isAllowedToViewFullInfo}
authenticatedUserId={authenticatedUserId}
currentUserInfo={currentUserInfo}
/>
+ {currentUserInfo?.bio && (
+
+ )}
(
@@ -158,14 +191,14 @@ const UserInformation = () => {
))}
- isAdmin={isAdmin}
+ isAdmin={isAllowedToViewFullInfo}
authenticatedUserId={authenticatedUserId}
currentUserInfo={currentUserInfo}
/>
From f6eaf878afd12d074ec002ef05fd24db2c1e152c Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Wed, 1 Jan 2025 18:47:35 +0530
Subject: [PATCH 035/153] Fix: Editing of Audio, Video and File Message (#697)
* updated handleEditMessage functionality, added valdation for audio, video and file message
* I have hidden the edit option for the audio/video message, and reverted previous approach of showing popup message
* fix: apply Prettier formatting
* Update visibility logic for 'Edit' button
* wrapped logic in the variable 'isVisibleForMessageType' for this check and used it
---
packages/react/src/views/Message/MessageToolbox.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index a3e2c1ec71..710be2b5a2 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -75,11 +75,17 @@ export const MessageToolbox = ({
};
const isAllowedToPin = userRoles.some((role) => pinRoles.has(role));
+
const isAllowedToEditMessage = userRoles.some((role) =>
editMessageRoles.has(role)
)
? true
: message.u._id === authenticatedUserId;
+
+ const isVisibleForMessageType =
+ message.files?.[0].type !== 'audio/mpeg' &&
+ message.files?.[0].type !== 'video/mp4';
+
const options = useMemo(
() => ({
reply: {
@@ -130,7 +136,7 @@ export const MessageToolbox = ({
id: 'edit',
onClick: () => handleEditMessage(message),
iconName: 'edit',
- visible: isAllowedToEditMessage,
+ visible: isAllowedToEditMessage && isVisibleForMessageType,
color: isEditing ? 'secondary' : 'default',
ghost: !isEditing,
},
From f3b33bc20c5de1d3b71d92aee11a66a73ce5ffad Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Wed, 1 Jan 2025 18:52:10 +0530
Subject: [PATCH 036/153] Fix UI Not Updating Immediately After
Pinning/Unpinning Messages (#654)
* pin
* removed comment
---
packages/react/src/views/Message/Message.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index a17a3c3a3c..6aed12ef0c 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -102,10 +102,12 @@ const Message = ({
const handlePinMessage = async (msg) => {
const isPinned = msg.pinned;
+ msg.pinned = !isPinned;
const pinOrUnpin = isPinned
? await RCInstance.unpinMessage(msg._id)
: await RCInstance.pinMessage(msg._id);
if (pinOrUnpin.error) {
+ msg.pinned = isPinned;
dispatchToastMessage({
type: 'error',
message: 'Error pinning message',
From de1036c181e856f3d1858d69332237099ac2416d Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Wed, 1 Jan 2025 18:59:15 +0530
Subject: [PATCH 037/153] fix: image gallery showing error (#759)
---
packages/api/src/EmbeddedChatApi.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index b9a8cef326..c2fdabb694 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -714,7 +714,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(
- `${this.host}/api/v1/channels.images?roomId=${this.rid}`,
+ `${this.host}/api/v1/rooms.images?roomId=${this.rid}`,
{
headers: {
"Content-Type": "application/json",
From d920d596f02a0f4d10261d57fad81daa86788e93 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Wed, 1 Jan 2025 19:10:42 +0530
Subject: [PATCH 038/153] Feat: add announcement , display room avatar , make
room name clickable. (#734)
* Added room announcement feature , display avatar and make room name clickable
* remove showChannelAvatar from ECOptions
* Add padding
* Add padding to modal
* Remove text underline in announcement in normal view
* add showAnnouncement dependency to useEffect
* Run prettier
* replace channelInfo.description
---
packages/react/src/views/ChatBody/ChatBody.js | 75 +++++++++++++++++--
.../src/views/ChatBody/ChatBody.styles.js | 20 ++++-
.../react/src/views/ChatHeader/ChatHeader.js | 49 +++++++++---
.../src/views/ChatHeader/ChatHeader.styles.js | 11 ++-
packages/react/src/views/EmbeddedChat.js | 4 +
.../views/RoomInformation/RoomInformation.js | 52 ++++++-------
.../RoomInformation/RoomInformation.styles.js | 25 +++++++
7 files changed, 193 insertions(+), 43 deletions(-)
create mode 100644 packages/react/src/views/RoomInformation/RoomInformation.styles.js
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index a582244d0f..721c2d2dc1 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -1,11 +1,19 @@
/* eslint-disable no-shadow */
-import React, { useCallback, useContext, useEffect, useState } from 'react';
+import React, {
+ useCallback,
+ useContext,
+ useEffect,
+ useState,
+ useRef,
+} from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import {
Box,
Throbber,
useComponentOverrides,
+ Modal,
+ useTheme,
} from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
import {
@@ -33,21 +41,23 @@ const ChatBody = ({
scrollToBottom,
}) => {
const { classNames, styleOverrides } = useComponentOverrides('ChatBody');
-
- const styles = getChatbodyStyles();
+ const { theme, mode } = useTheme();
+ const styles = getChatbodyStyles(theme, mode);
const [scrollPosition, setScrollPosition] = useState(0);
const [popupVisible, setPopupVisible] = useState(false);
const [, setIsUserScrolledUp] = useState(false);
const [otherUserMessage, setOtherUserMessage] = useState(false);
-
+ const [isOverflowing, setIsOverflowing] = useState(false);
const { RCInstance, ECOptions } = useContext(RCContext);
+ const showAnnouncement = ECOptions?.showAnnouncement;
const messages = useMessageStore((state) => state.messages);
const threadMessages = useMessageStore((state) => state.threadMessages);
-
+ const [isModalOpen, setModalOpen] = useState(false);
const setThreadMessages = useMessageStore((state) => state.setThreadMessages);
const upsertMessage = useMessageStore((state) => state.upsertMessage);
const removeMessage = useMessageStore((state) => state.removeMessage);
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
+ const channelInfo = useChannelStore((state) => state.channelInfo);
const isLoginIn = useLoginStore((state) => state.isLoginIn);
const [isThreadOpen, threadMainMessage] = useMessageStore((state) => [
@@ -182,7 +192,24 @@ const ChatBody = ({
const showNewMessagesPopup = () => {
setPopupVisible(true);
};
+ const announcementRef = useRef(null);
+
+ const toggleModal = () => {
+ setModalOpen(!isModalOpen);
+ };
+
+ const checkOverflow = () => {
+ if (announcementRef.current) {
+ setIsOverflowing(
+ announcementRef.current.scrollWidth >
+ announcementRef.current.clientWidth
+ );
+ }
+ };
+ useEffect(() => {
+ checkOverflow();
+ }, [channelInfo.announcement, showAnnouncement]);
useEffect(() => {
const currentRef = messageListRef.current;
currentRef.addEventListener('scroll', handleScroll);
@@ -204,6 +231,44 @@ const ChatBody = ({
return (
<>
+ {channelInfo.announcement && showAnnouncement && (
+
+
+ {channelInfo.announcement}
+
+
+ )}
+ {isModalOpen && (
+
+
+ Announcement
+
+
+
+ {channelInfo.announcement}
+
+
+ )}
{
+export const getChatbodyStyles = (theme, mode) => {
const styles = {
chatbodyContainer: css`
flex: 1;
@@ -14,6 +15,23 @@ export const getChatbodyStyles = () => {
padding-top: 70px;
margin-top: 0.25rem;
`,
+ announcementStyles: css`
+ display: flex;
+ justify-content: center;
+ padding: 7px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ background-color: ${mode === 'light'
+ ? lighten(theme.colors.info, 0.78)
+ : darken(theme.colors.primary, 0.7)};
+ `,
+ announcementTextBox: css`
+ max-width: 80%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ `,
};
return styles;
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 0107399771..817ff40975 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -1,4 +1,5 @@
import React, { useCallback, useEffect, useMemo } from 'react';
+import { css } from '@emotion/react';
import PropTypes from 'prop-types';
import {
Box,
@@ -8,6 +9,7 @@ import {
useToastBarDispatch,
useComponentOverrides,
useTheme,
+ Avatar,
} from '@embeddedchat/ui-elements';
import { useRCContext } from '../../context/RCInstance';
import {
@@ -115,7 +117,10 @@ const ChatHeader = ({
);
const setShowAllFiles = useFileStore((state) => state.setShowAllFiles);
const setShowMentions = useMentionsStore((state) => state.setShowMentions);
-
+ const getChannelAvatarURL = (channelname) => {
+ const host = RCInstance.getHost();
+ return `${host}/avatar/${channelname}`;
+ };
const handleGoBack = async () => {
if (isUserAuthenticated) {
getMessagesAndRoles();
@@ -347,7 +352,6 @@ const ChatHeader = ({
>
-
{isUserAuthenticated ? (
<>
@@ -355,17 +359,40 @@ const ChatHeader = ({
level={3}
className="ec-chat-header--channelName"
css={styles.clearSpacing}
+ style={{
+ display: 'flex',
+ alignItems: 'center',
+ gap: '0.2rem',
+ }}
>
- {channelInfo.name || channelName || 'channelName'}
+
+
+ setExclusiveState(setShowChannelinfo)}
+ >
+
+
+ {channelInfo.name || channelName || 'channelName'}
+
+
+ {fullScreen && (
+
+ {channelInfo.topic || ''}
+
+ )}
+
- {fullScreen && (
-
- {channelInfo.description || ''}
-
- )}
>
) : (
{
margin: 0;
padding: 0;
`,
-
chatHeaderChild: css`
${rowCentreAlign}
padding: 0 0.75rem;
@@ -43,6 +42,16 @@ const getChatHeaderStyles = ({ theme, mode }) => {
position:relative;
gap: 0.5rem;
`,
+ channelName: css`
+ display: flex;
+ align-items: center;
+ gap: 0.1rem;
+ cursor: pointer;
+ `,
+ channelTopic: css`
+ opacity: 0.8rem;
+ font-size: 1rem;
+ `,
};
return styles;
};
diff --git a/packages/react/src/views/EmbeddedChat.js b/packages/react/src/views/EmbeddedChat.js
index 00557f289c..17b1ff1a41 100644
--- a/packages/react/src/views/EmbeddedChat.js
+++ b/packages/react/src/views/EmbeddedChat.js
@@ -44,6 +44,7 @@ const EmbeddedChat = (props) => {
toastBarPosition = 'bottom right',
showRoles = false,
showAvatar = true,
+ showAnnouncement = true,
showUsername = false,
showName = true,
enableThreads = false,
@@ -204,6 +205,7 @@ const EmbeddedChat = (props) => {
showName,
showRoles,
showAvatar,
+ showAnnouncement,
showUsername,
hideHeader,
anonymousMode,
@@ -219,6 +221,7 @@ const EmbeddedChat = (props) => {
showName,
showRoles,
showAvatar,
+ showAnnouncement,
showUsername,
hideHeader,
anonymousMode,
@@ -281,6 +284,7 @@ EmbeddedChat.propTypes = {
toastBarPosition: PropTypes.string,
showRoles: PropTypes.bool,
showAvatar: PropTypes.bool,
+ showAnnouncement: PropTypes.bool,
enableThreads: PropTypes.bool,
theme: PropTypes.object,
auth: PropTypes.oneOfType([
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.js b/packages/react/src/views/RoomInformation/RoomInformation.js
index 3cfdefad08..b4e26764c9 100644
--- a/packages/react/src/views/RoomInformation/RoomInformation.js
+++ b/packages/react/src/views/RoomInformation/RoomInformation.js
@@ -9,11 +9,12 @@ import {
} from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
import { useChannelStore } from '../../store';
+import getRoomInformationStyles from './RoomInformation.styles';
import useSetExclusiveState from '../../hooks/useSetExclusiveState';
const Roominfo = () => {
const { RCInstance } = useContext(RCContext);
-
+ const styles = getRoomInformationStyles();
const channelInfo = useChannelStore((state) => state.channelInfo);
const { variantOverrides } = useComponentOverrides('RoomMember');
const viewType = variantOverrides.viewType || 'Sidebar';
@@ -44,34 +45,35 @@ const Roominfo = () => {
overflow: auto;
`}
>
-
-
- # {channelInfo.name}
-
-
- Description
-
-
- {channelInfo.description}
-
+
+
+
+ # {channelInfo.name}
+ {channelInfo.description && (
+ <>
+ Description
+ {channelInfo.description}
+ >
+ )}
+ {channelInfo.topic && (
+ <>
+ Topic
+ {channelInfo.topic}
+ >
+ )}
+ {channelInfo.announcement && (
+ <>
+ Announcement
+ {channelInfo.announcement}
+ >
+ )}
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.styles.js b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
new file mode 100644
index 0000000000..9ab039b94a
--- /dev/null
+++ b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
@@ -0,0 +1,25 @@
+import { css } from '@emotion/react';
+
+const getRoomInformationStyles = () => {
+ const styles = {
+ infoContainer: css`
+ margin: 16px;
+ display: flex;
+ flex-direction: column;
+ gap: 0.1rem;
+ `,
+ infoHeader: css`
+ margin-block: 5px;
+ font-weight: 900;
+ `,
+ info: css`
+ word-wrap: break-word;
+ overflow-wrap: anywhere;
+ white-space: normal;
+ `,
+ };
+
+ return styles;
+};
+
+export default getRoomInformationStyles;
From 1c01bbdc444f35422422bae2dd3521685fa2095e Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Wed, 1 Jan 2025 19:11:04 +0530
Subject: [PATCH 039/153] fix: user action messages (#746)
* fix: user action messages
* remove showUsername
---
packages/react/src/views/Message/Message.js | 5 ++++-
packages/react/src/views/Message/MessageHeader.js | 12 ++++++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 6aed12ef0c..140cbdc963 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -207,7 +207,10 @@ const Message = ({
isPinned={isPinned}
/>
)}
-
+
{shouldShowHeader && (
0 ? message.msg : '(none)'
+ }`;
+ case 'room_changed_description':
+ return `changed description to: ${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ }`;
+ case 'room_changed_topic':
+ return `changed topic to: ${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ }`;
default:
return '';
}
From 051dfe377bbf12655de0978b5cbf276df7094fa2 Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Wed, 1 Jan 2025 19:13:45 +0530
Subject: [PATCH 040/153] Display user roles (Admin, Leader, Moderator, Owner)
next to message headers (#738)
---
packages/react/src/views/ChatLayout/ChatLayout.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/react/src/views/ChatLayout/ChatLayout.js b/packages/react/src/views/ChatLayout/ChatLayout.js
index ee6b0c1b94..60c935a360 100644
--- a/packages/react/src/views/ChatLayout/ChatLayout.js
+++ b/packages/react/src/views/ChatLayout/ChatLayout.js
@@ -38,7 +38,7 @@ const ChatLayout = () => {
const { classNames, styleOverrides } = useComponentOverrides('ChatBody');
const { RCInstance, ECOptions } = useRCContext();
const anonymousMode = ECOptions?.anonymousMode;
- const showRoles = ECOptions?.anonymousMode;
+ const showRoles = ECOptions?.showRoles;
const setStarredMessages = useStarredMessageStore(
(state) => state.setStarredMessages
);
From 470588888738fbb07d1e96cb64f80e7e285aac60 Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Wed, 1 Jan 2025 19:24:22 +0530
Subject: [PATCH 041/153] feat: add password visibility toggle feature in API
development portal (#706)
* feat: add password visibility toggle feature in API development portal
* Simplify changes
---------
Co-authored-by: Zishan Ahmad
---
packages/api/playground/index.html | 11 +++++++++++
packages/api/playground/playground.js | 19 +++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/packages/api/playground/index.html b/packages/api/playground/index.html
index 6091350192..d850068e98 100644
--- a/packages/api/playground/index.html
+++ b/packages/api/playground/index.html
@@ -24,6 +24,14 @@
.playground-output #output{
white-space: pre-wrap;
}
+ #togglePassword {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ vertical-align: middle;
+ width: 50px;
+ }
@@ -43,6 +51,9 @@
+
+ Show
+
Sign in
{
`}
>
{attachment.title}
diff --git a/packages/react/src/views/AttachmentHandler/Attachments.js b/packages/react/src/views/AttachmentHandler/Attachments.js
index 35010476a4..f558ad5ec0 100644
--- a/packages/react/src/views/AttachmentHandler/Attachments.js
+++ b/packages/react/src/views/AttachmentHandler/Attachments.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import Attachment from './Attachment';
import RCContext from '../../context/RCInstance';
-const Attachments = ({ attachments, type, variantStyles = {} }) => {
+const Attachments = ({ attachments, type, variantStyles = {}, msg }) => {
const { RCInstance } = useContext(RCContext);
let host = RCInstance.getHost();
host = host.replace(/\/$/, '');
@@ -15,6 +15,7 @@ const Attachments = ({ attachments, type, variantStyles = {} }) => {
host={host}
variantStyles={variantStyles}
type={type}
+ msg={msg}
/>
));
};
diff --git a/packages/react/src/views/AttachmentHandler/AudioAttachment.js b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
index 0f5824aa0f..b88d0a41da 100644
--- a/packages/react/src/views/AttachmentHandler/AudioAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
@@ -5,7 +5,14 @@ import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import AttachmentMetadata from './AttachmentMetadata';
import RCContext from '../../context/RCInstance';
-const AudioAttachment = ({ attachment, host, type, author, variantStyles }) => {
+const AudioAttachment = ({
+ attachment,
+ host,
+ type,
+ author,
+ variantStyles,
+ msg,
+}) => {
const { RCInstance } = useContext(RCContext);
const { theme } = useTheme();
const getUserAvatarUrl = (icon) => {
@@ -58,6 +65,7 @@ const AudioAttachment = ({ attachment, host, type, author, variantStyles }) => {
attachment={attachment}
url={host + (attachment.title_url || attachment.audio_url)}
variantStyles={variantStyles}
+ msg={msg}
/>
diff --git a/packages/react/src/views/AttachmentHandler/ImageAttachment.js b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
index b9e6533ad4..04a2addc49 100644
--- a/packages/react/src/views/AttachmentHandler/ImageAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
@@ -12,6 +12,7 @@ const ImageAttachment = ({
type,
author,
variantStyles = {},
+ msg,
}) => {
const { RCInstance } = useContext(RCContext);
const [showGallery, setShowGallery] = useState(false);
@@ -75,6 +76,7 @@ const ImageAttachment = ({
attachment={attachment}
url={host + (attachment.title_link || attachment.image_url)}
variantStyles={variantStyles}
+ msg={msg}
/>
{
const { RCInstance } = useContext(RCContext);
const { theme } = useTheme();
@@ -74,6 +75,7 @@ const VideoAttachment = ({
attachment={attachment}
url={host + (attachment.title_url || attachment.video_url)}
variantStyles={variantStyles}
+ msg={msg}
/>
@@ -101,14 +126,32 @@ const AttachmentPreview = () => {
>
File description
- {
- handleFileDescription(e);
- }}
- value={fileDescription}
- css={styles.input}
- placeholder="Description"
- />
+
+
+ {showMembersList && (
+
+ )}
+
+ {
+ handleFileDescription(e);
+ }}
+ css={styles.input}
+ placeholder="Description"
+ ref={messageRef}
+ />
+
diff --git a/packages/react/src/views/AttachmentPreview/AttachmentPreview.styles.js b/packages/react/src/views/AttachmentPreview/AttachmentPreview.styles.js
index 44729be847..45f8cf455a 100644
--- a/packages/react/src/views/AttachmentPreview/AttachmentPreview.styles.js
+++ b/packages/react/src/views/AttachmentPreview/AttachmentPreview.styles.js
@@ -11,7 +11,7 @@ const getAttachmentPreviewStyles = () => {
`,
input: css`
- width: 95.5%;
+ width: 100%;
`,
modalContent: css`
@@ -19,6 +19,22 @@ const getAttachmentPreviewStyles = () => {
overflow-x: hidden;
max-height: 350px;
`,
+
+ fileDescription: css`
+ width: 100%;
+ position: relative;
+ z-index: 1300;
+ `,
+
+ mentionListContainer: css`
+ position: absolute;
+ top: -100px;
+ width: 100%;
+ max-height: 100px;
+ overflow-y: auto;
+ background: white;
+ z-index: 1400;
+ `,
};
return styles;
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 86b4b5082a..91fc98deca 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -469,18 +469,23 @@ const ChatInput = ({ scrollToBottom }) => {
}
/>
) : null}
-
- {showMembersList && (
-
- )}
+
+ {showMembersList && (
+
+ )}
+
{showCommandList && (
{
+const Markdown = ({ body, md, isReaction = false }) => {
const members = useMemberStore((state) => state.members);
const username = useUserStore((state) => state.username);
const value = useMemo(() => ({ members, username }), [members, username]);
@@ -23,12 +23,12 @@ const Markdown = ({ body, isReaction = false }) => {
);
}
- if (!body || !body.md) return <>>;
+ if (!body || !md) return <>>;
return (
-
+
);
diff --git a/packages/react/src/views/Mentions/MembersList.styles.js b/packages/react/src/views/Mentions/MembersList.styles.js
index e288cae04d..03bc8f4018 100644
--- a/packages/react/src/views/Mentions/MembersList.styles.js
+++ b/packages/react/src/views/Mentions/MembersList.styles.js
@@ -3,7 +3,7 @@ import { css } from '@emotion/react';
const getMemberListStyles = (theme) => {
const styles = {
main: css`
- margin: 0.2rem 2rem;
+ margin: 0.2rem 0rem;
display: block;
overflow: auto;
max-height: 10rem;
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 140cbdc963..2a56b20b76 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -233,14 +233,19 @@ const Message = ({
>
{message.attachments && message.attachments.length > 0 ? (
<>
-
+
>
) : (
-
+
)}
{message.blocks && (
From 3e1360e3302e918a430c053364fda1fe41e155e9 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 11:17:00 +0530
Subject: [PATCH 044/153] Fix: Capitalize the first letter of user roles for
improved UI (#798)
---
packages/react/src/views/Message/MessageHeader.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/Message/MessageHeader.js b/packages/react/src/views/Message/MessageHeader.js
index 594c435113..89206256ea 100644
--- a/packages/react/src/views/Message/MessageHeader.js
+++ b/packages/react/src/views/Message/MessageHeader.js
@@ -127,7 +127,7 @@ const MessageHeader = ({
css={styles.userRole}
className={appendClassNames('ec-message-user-role')}
>
- admin
+ Admin
)}
@@ -138,7 +138,7 @@ const MessageHeader = ({
css={styles.userRole}
className={appendClassNames('ec-message-user-role')}
>
- {role}
+ {role.charAt(0).toUpperCase() + role.slice(1)}
))}
>
From 843adf0836cbb8c6996e805839f4e330e63b7b16 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 11:25:24 +0530
Subject: [PATCH 045/153] Fix bug: Display user roles in MessageAggregator when
showRoles is true (#790)
---
.../src/views/MessageAggregators/common/MessageAggregator.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index c70f3d73a5..241c0aa576 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -17,6 +17,7 @@ import LoadingIndicator from './LoadingIndicator';
import NoMessagesIndicator from './NoMessageIndicator';
import FileDisplay from '../../FileMessage/FileMessage';
import useSetExclusiveState from '../../../hooks/useSetExclusiveState';
+import { useRCContext } from '../../../context/RCInstance';
export const MessageAggregator = ({
title,
@@ -33,6 +34,8 @@ export const MessageAggregator = ({
const { theme } = useTheme();
const styles = getMessageAggregatorStyles(theme);
const setExclusiveState = useSetExclusiveState();
+ const { ECOptions } = useRCContext();
+ const showRoles = ECOptions?.showRoles;
const messages = useMessageStore((state) => state.messages);
const threadMessages = useMessageStore((state) => state.threadMessages) || [];
const allMessages = useMemo(
@@ -126,7 +129,7 @@ export const MessageAggregator = ({
type="default"
showAvatar
showToolbox={false}
- showRoles={false}
+ showRoles={showRoles}
isInSidebar
style={{
flex: 1,
From 73f8fc08041f9190e541709f178a594f7543dc54 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 15:42:49 +0530
Subject: [PATCH 046/153] Fix: Disable hover effect for User Action Messages
(#795)
---
packages/react/src/views/Message/Message.js | 18 ++++++++++++++++++
.../react/src/views/Message/Message.styles.js | 9 +--------
2 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 2a56b20b76..03c558c761 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -7,6 +7,8 @@ import {
useComponentOverrides,
appendClassNames,
useTheme,
+ lighten,
+ darken,
} from '@embeddedchat/ui-elements';
import { Attachments } from '../AttachmentHandler';
import { Markdown } from '../Markdown';
@@ -72,8 +74,23 @@ const Message = ({
}));
const isMe = message.u._id === authenticatedUserId;
+
const theme = useTheme();
+ const { mode } = useTheme();
const styles = getMessageStyles(theme);
+ const hasType = Boolean(message.t);
+
+ const hoverStyle = hasType
+ ? {}
+ : {
+ '&:hover': {
+ backgroundColor:
+ mode === 'light'
+ ? darken(theme.theme.colors.background, 0.03)
+ : lighten(theme.theme.colors.background, 1),
+ },
+ };
+
const bubbleStyles = useBubbleStyles(isMe);
const pinRoles = new Set(pinPermissions);
const editMessageRoles = new Set(editMessagePermissions);
@@ -195,6 +212,7 @@ const Message = ({
className={appendClassNames('ec-message', classNames)}
css={[
variantStyles.messageParent || styles.main,
+ hoverStyle,
editMessage._id === message._id && styles.messageEditing,
]}
style={styleOverrides}
diff --git a/packages/react/src/views/Message/Message.styles.js b/packages/react/src/views/Message/Message.styles.js
index 9f9358fd92..8c380d241b 100644
--- a/packages/react/src/views/Message/Message.styles.js
+++ b/packages/react/src/views/Message/Message.styles.js
@@ -1,7 +1,6 @@
import { css } from '@emotion/react';
-import { lighten, darken } from '@embeddedchat/ui-elements';
-export const getMessageStyles = ({ theme, mode }) => {
+export const getMessageStyles = ({ theme }) => {
const styles = {
main: css`
display: flex;
@@ -12,12 +11,6 @@ export const getMessageStyles = ({ theme, mode }) => {
padding-left: 2.25rem;
padding-right: 2.25rem;
color: ${theme.colors.foreground};
-
- &:hover {
- background-color: ${mode === 'light'
- ? darken(theme.colors.background, 0.03)
- : lighten(theme.colors.background, 1)};
- }
`,
messageEditing: css`
background-color: ${theme.colors.secondary};
From dd0657f299412a71c6a9950aeda91240ad1c368c Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sun, 5 Jan 2025 15:44:55 +0530
Subject: [PATCH 047/153] fix: jump to message highlights the element (#748)
* add highlight color
* lint
* consume theme
---
.../views/MessageAggregators/common/MessageAggregator.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 241c0aa576..3411d54107 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -54,7 +54,11 @@ export const MessageAggregator = ({
const element = document.getElementById(`ec-message-body-${msgId}`);
if (element) {
setShowSidebar(false);
- element.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
+ element.style.backgroundColor = theme.colors.warning;
+ setTimeout(() => {
+ element.style.backgroundColor = '';
+ }, 1000);
}
}
};
From bd6cefb81da9d8b3fb5d1a30453364065fdb29b5 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 15:45:42 +0530
Subject: [PATCH 048/153] Fix: The 'Copy' option functionality is now working
for File messages (#716)
* Fix: 'Copy' option functionality is not working for File messages
* Updated logic with copy file name in case of description not present
---
packages/react/src/views/Message/Message.js | 30 ++++++++++++---------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 03c558c761..fa8c864fec 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -138,20 +138,24 @@ const Message = ({
};
const handleCopyMessage = async (msg) => {
- navigator.clipboard
- .writeText(msg.msg)
- .then(() => {
- dispatchToastMessage({
- type: 'success',
- message: 'Message copied successfully',
- });
- })
- .catch(() => {
- dispatchToastMessage({
- type: 'error',
- message: 'Error in copying message',
- });
+ const textToCopy =
+ msg.msg ||
+ (msg.attachments && msg.attachments[0]
+ ? msg.attachments[0].description || msg.attachments[0].title
+ : '');
+
+ try {
+ await navigator.clipboard.writeText(textToCopy);
+ dispatchToastMessage({
+ type: 'success',
+ message: 'Message copied successfully',
});
+ } catch (error) {
+ dispatchToastMessage({
+ type: 'error',
+ message: 'Error in copying message',
+ });
+ }
};
const getMessageLink = async (id) => {
From 12cefd6a031645ac77673484ad5ba70dd90ee586 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 5 Jan 2025 15:56:08 +0530
Subject: [PATCH 049/153] feat: Add Syntax Highlighting to Multiline Code
Blocks using react-syntax-highlighter (#764)
* add code syntax highlighting
* Run prettier
* remove unecessary space in package.json
* Make multiline code occupy full width
* use react-syntax-highlighter
* Remove theme state and useEffect
---
packages/markups/package.json | 3 +-
packages/markups/src/elements/CodeBlock.js | 19 +++++--
packages/markups/src/elements/CodeElement.js | 14 +++--
.../markups/src/elements/elements.styles.js | 57 +++++++++++++------
yarn.lock | 24 ++++++++
5 files changed, 89 insertions(+), 28 deletions(-)
diff --git a/packages/markups/package.json b/packages/markups/package.json
index 3b09bc97fc..2c617f5266 100644
--- a/packages/markups/package.json
+++ b/packages/markups/package.json
@@ -76,6 +76,7 @@
"@emotion/react": "11.7.1",
"@rollup/plugin-json": "^6.0.0",
"emoji-toolkit": "^7.0.1",
- "prop-types": "^15.8.1"
+ "prop-types": "^15.8.1",
+ "react-syntax-highlighter": "^15.6.1"
}
}
diff --git a/packages/markups/src/elements/CodeBlock.js b/packages/markups/src/elements/CodeBlock.js
index b8f5acf133..54bad69fcb 100644
--- a/packages/markups/src/elements/CodeBlock.js
+++ b/packages/markups/src/elements/CodeBlock.js
@@ -1,9 +1,13 @@
-import React, { useMemo } from 'react';
+import React, { useMemo, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
-import { Box } from '@embeddedchat/ui-elements';
-import { CodeBlockStyles as styles } from './elements.styles';
+import { Box, useTheme } from '@embeddedchat/ui-elements';
+import SyntaxHighlighter from 'react-syntax-highlighter';
+import { vs, monokai } from 'react-syntax-highlighter/dist/esm/styles/hljs';
+import { CodeBlockStyles } from './elements.styles';
const CodeBlock = ({ lines }) => {
+ const { mode } = useTheme();
+ const styles = CodeBlockStyles();
const code = useMemo(
() => lines.map((line) => line.value.value).join('\n'),
[lines]
@@ -14,7 +18,13 @@ const CodeBlock = ({ lines }) => {
```
- {code}
+
+ {code}
+
```
@@ -23,7 +33,6 @@ const CodeBlock = ({ lines }) => {
};
export default CodeBlock;
-
CodeBlock.propTypes = {
lines: PropTypes.any,
};
diff --git a/packages/markups/src/elements/CodeElement.js b/packages/markups/src/elements/CodeElement.js
index 043f5a2a00..8a2483f17f 100644
--- a/packages/markups/src/elements/CodeElement.js
+++ b/packages/markups/src/elements/CodeElement.js
@@ -1,12 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
import PlainSpan from './PlainSpan';
+import { InlineElementsStyles } from './elements.styles';
-const CodeElement = ({ contents }) => (
-
-
-
-);
+const CodeElement = ({ contents }) => {
+ const styles = InlineElementsStyles();
+ return (
+
+
+
+ );
+};
export default CodeElement;
diff --git a/packages/markups/src/elements/elements.styles.js b/packages/markups/src/elements/elements.styles.js
index aa44d77dd1..2f1f2fb295 100644
--- a/packages/markups/src/elements/elements.styles.js
+++ b/packages/markups/src/elements/elements.styles.js
@@ -1,23 +1,46 @@
import { css } from '@emotion/react';
-import { useTheme } from '@embeddedchat/ui-elements';
+import { useTheme, darken } from '@embeddedchat/ui-elements';
-export const CodeBlockStyles = {
- copyonly: css`
- display: none;
- width: 100%;
- height: 0;
- user-select: none;
- vertical-align: baseline;
- font-size: 0;
- -moz-box-orient: vertical;
- `,
+export const InlineElementsStyles = () => {
+ const { theme } = useTheme();
+ const styles = {
+ inlineElement: css`
+ font-weight: 600;
+ font-size: 0.75rem;
+ width: fit-content;
+ padding: 3px;
+ background-color: ${theme.colors.border};
+ border-radius: 6px;
+ `,
+ };
+ return styles;
+};
+export const CodeBlockStyles = () => {
+ const { theme } = useTheme();
+ const styles = {
+ copyonly: css`
+ display: none;
+ width: 100%;
+ height: 0;
+ user-select: none;
+ vertical-align: baseline;
+ font-size: 0;
+ -moz-box-orient: vertical;
+ `,
- prestyle: css`
- display: inline-block;
- max-width: 100%;
- overflow-x: auto;
- white-space: pre-wrap;
- `,
+ prestyle: css`
+ display: inline-block;
+ width: 100%;
+ overflow-x: auto;
+ white-space: pre-wrap;
+ `,
+ codeBlock: css`
+ background-color: ${darken(theme.colors.accent, 0.01)} !important;
+ border-radius: ${theme.radius};
+ font-weight: 600;
+ `,
+ };
+ return styles;
};
export const ColorElementStyles = {
diff --git a/yarn.lock b/yarn.lock
index 39464bc873..585c7d5679 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2366,6 +2366,7 @@ __metadata:
prop-types: ^15.8.1
react: ^17.0.2
react-dom: ^17.0.2
+ react-syntax-highlighter: ^15.6.1
rimraf: ^5.0.1
rollup: ^2.70.1
rollup-plugin-analyzer: ^4.0.0
@@ -18694,6 +18695,13 @@ __metadata:
languageName: node
linkType: hard
+"highlightjs-vue@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "highlightjs-vue@npm:1.0.0"
+ checksum: 895f2dd22c93a441aca7df8d21f18c00697537675af18832e50810a071715f79e45eda677e6244855f325234c6a06f7bd76f8f20bd602040fc350c80ac7725e4
+ languageName: node
+ linkType: hard
+
"hmac-drbg@npm:^1.0.1":
version: 1.0.1
resolution: "hmac-drbg@npm:1.0.1"
@@ -27213,6 +27221,22 @@ __metadata:
languageName: node
linkType: hard
+"react-syntax-highlighter@npm:^15.6.1":
+ version: 15.6.1
+ resolution: "react-syntax-highlighter@npm:15.6.1"
+ dependencies:
+ "@babel/runtime": ^7.3.1
+ highlight.js: ^10.4.1
+ highlightjs-vue: ^1.0.0
+ lowlight: ^1.17.0
+ prismjs: ^1.27.0
+ refractor: ^3.6.0
+ peerDependencies:
+ react: ">= 0.14.0"
+ checksum: 417b6f1f2e0c1e00dcc12d34da457b94c7419345306a951d0a8d2d031a0c964179d6b700137870ad1397572cbc3a4454e94de7bbef914a81674edae2098f02dc
+ languageName: node
+ linkType: hard
+
"react@npm:18.2.0, react@npm:^18.2.0":
version: 18.2.0
resolution: "react@npm:18.2.0"
From 9352c030224059a865a7c0da1905e3940824ce86 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 16:17:56 +0530
Subject: [PATCH 050/153] Feat: Added 'Collapse & Uncollapse' Functionality for
Audio, Video Messages & Image attachment (#772)
* BUG: Fix extra top space for audio and video messages to improve UI consistency
* Fix: Add padding for audio and video messages in nested attachments and quotes
* added conditional CSS handling the description present or absent case
* Same logic for conditional CSS but written in better way
* Feat: Add 'Collapse & Uncollapse' functionality for Audio and Video messages
* Feat: Add 'Collapse & Uncollapse' functionality
* Feat: Add 'Collapse & Uncollapse' functionality
* Added Collapse & Uncollapse Functionality for Image Attachment
* Using chevron-down, chevron-left instead of arrow-down, arrow-right
---
.../AttachmentHandler/AttachmentMetadata.js | 19 +++++++++-
.../AttachmentHandler/AudioAttachment.js | 14 ++++++-
.../AttachmentHandler/ImageAttachment.js | 30 ++++++++++-----
.../AttachmentHandler/VideoAttachment.js | 38 ++++++++++++-------
4 files changed, 74 insertions(+), 27 deletions(-)
diff --git a/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js b/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
index 5bd249ce5e..390cab7b71 100644
--- a/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
+++ b/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
@@ -3,7 +3,14 @@ import { css } from '@emotion/react';
import { ActionButton, Box } from '@embeddedchat/ui-elements';
import { Markdown } from '../Markdown';
-const AttachmentMetadata = ({ attachment, url, variantStyles = {}, msg }) => {
+const AttachmentMetadata = ({
+ attachment,
+ url,
+ variantStyles = {},
+ msg,
+ onExpandCollapseClick,
+ isExpanded,
+}) => {
const handleDownload = async () => {
try {
const response = await fetch(url);
@@ -78,6 +85,16 @@ const AttachmentMetadata = ({ attachment, url, variantStyles = {}, msg }) => {
>
{attachment.title}
+
{
+ setIsExpanded((prevState) => !prevState);
+ };
+
return (
-
+ {isExpanded && (
+
+ )}
{attachment.attachments &&
attachment.attachments.map((nestedAttachment, index) => (
diff --git a/packages/react/src/views/AttachmentHandler/ImageAttachment.js b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
index 04a2addc49..5f95829df0 100644
--- a/packages/react/src/views/AttachmentHandler/ImageAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
@@ -30,10 +30,14 @@ const ImageAttachment = ({
const { authorIcon, authorName } = author;
+ const [isExpanded, setIsExpanded] = useState(true);
+ const toggleExpanded = () => {
+ setIsExpanded((prevState) => !prevState);
+ };
+
return (
setShowGallery(true)}
css={[
css`
cursor: pointer;
@@ -77,16 +81,22 @@ const ImageAttachment = ({
url={host + (attachment.title_link || attachment.image_url)}
variantStyles={variantStyles}
msg={msg}
+ onExpandCollapseClick={toggleExpanded}
+ isExpanded={isExpanded}
/>
-
+ {isExpanded && (
+ setShowGallery(true)}>
+
+
+ )}
{attachment.attachments &&
attachment.attachments.map((nestedAttachment, index) => (
diff --git a/packages/react/src/views/AttachmentHandler/VideoAttachment.js b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
index 0b364b1a2d..4407481ee4 100644
--- a/packages/react/src/views/AttachmentHandler/VideoAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
@@ -1,4 +1,4 @@
-import React, { useContext } from 'react';
+import React, { useState, useContext } from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
@@ -31,6 +31,12 @@ const VideoAttachment = ({
return URL;
};
const { authorIcon, authorName } = author;
+
+ const [isExpanded, setIsExpanded] = useState(true);
+ const toggleExpanded = () => {
+ setIsExpanded((prevState) => !prevState);
+ };
+
return (
-
+ {isExpanded && (
+
+ )}
{attachment.attachments &&
attachment.attachments.map((nestedAttachment, index) => (
From ad7fefd70556d6f7d97dda26d24d45bb733b3a5a Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Sun, 5 Jan 2025 16:25:06 +0530
Subject: [PATCH 051/153] fix (#704)
---
packages/react/src/views/Message/MessageToolbox.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 710be2b5a2..f276ef82cf 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -129,7 +129,7 @@ export const MessageToolbox = ({
id: 'pin',
onClick: () => handlePinMessage(message),
iconName: message.pinned ? 'pin-filled' : 'pin',
- visible: !isThreadMessage && isAllowedToPin,
+ visible: isAllowedToPin,
},
edit: {
label: 'Edit',
From 836a83ee8125c33cf412d0d77d6db0003140e3fb Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 16:38:31 +0530
Subject: [PATCH 052/153] Attachmentwindow for audio & video messages (#770)
---
.../views/ChatInput/AudioMessageRecorder.js | 29 +++++++------------
.../views/ChatInput/VideoMessageRecoder.js | 28 ++++++------------
2 files changed, 19 insertions(+), 38 deletions(-)
diff --git a/packages/react/src/views/ChatInput/AudioMessageRecorder.js b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
index caef86e700..1d3af014fc 100644
--- a/packages/react/src/views/ChatInput/AudioMessageRecorder.js
+++ b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
@@ -1,15 +1,9 @@
-import React, {
- useState,
- useEffect,
- useCallback,
- useContext,
- useRef,
-} from 'react';
+import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Box, Icon, ActionButton, useTheme } from '@embeddedchat/ui-elements';
import { useMediaRecorder } from '../../hooks/useMediaRecorder';
-import RCContext from '../../context/RCInstance';
import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
+import useAttachmentWindowStore from '../../store/attachmentwindow';
const AudioMessageRecorder = () => {
const videoRef = useRef(null);
@@ -19,13 +13,17 @@ const AudioMessageRecorder = () => {
(state) => state.toogleRecordingMessage
);
- const { RCInstance, ECOptions } = useContext(RCContext);
+ const { toggle, setData } = useAttachmentWindowStore((state) => ({
+ toggle: state.toggle,
+ setData: state.setData,
+ }));
+
const [state, setRecordState] = useState('idle');
const [time, setTime] = useState('00:00');
const [recordingInterval, setRecordingInterval] = useState(null);
const [file, setFile] = useState(null);
const [isRecorded, setIsRecorded] = useState(false);
- const threadId = useMessageStore((_state) => _state.threadMainMessage?._id);
+
const onStop = (audioChunks) => {
const audioBlob = new Blob(audioChunks, { type: 'audio/mpeg' });
const fileName = 'Audio record.mp3';
@@ -120,16 +118,9 @@ const AudioMessageRecorder = () => {
}, [handleMount]);
useEffect(() => {
- const sendRecording = async () => {
- await RCInstance.sendAttachment(
- file,
- undefined,
- undefined,
- ECOptions.enableThreads ? threadId : undefined
- );
- };
if (isRecorded && file) {
- sendRecording();
+ toggle();
+ setData(file);
setIsRecorded(false);
}
if (file) {
diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
index 4d5b00810d..2fbe2bb149 100644
--- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js
+++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
@@ -1,10 +1,4 @@
-import React, {
- useState,
- useEffect,
- useCallback,
- useContext,
- useRef,
-} from 'react';
+import React, { useState, useEffect, useCallback, useRef } from 'react';
import { css } from '@emotion/react';
import {
Box,
@@ -14,9 +8,9 @@ import {
useTheme,
} from '@embeddedchat/ui-elements';
import { useMediaRecorder } from '../../hooks/useMediaRecorder';
-import RCContext from '../../context/RCInstance';
import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
+import useAttachmentWindowStore from '../../store/attachmentwindow';
const VideoMessageRecorder = () => {
const videoRef = useRef(null);
@@ -27,13 +21,16 @@ const VideoMessageRecorder = () => {
(state) => state.toogleRecordingMessage
);
- const { RCInstance, ECOptions } = useContext(RCContext);
+ const { toggle, setData } = useAttachmentWindowStore((state) => ({
+ toggle: state.toggle,
+ setData: state.setData,
+ }));
+
const [state, setRecordState] = useState('idle');
const [time, setTime] = useState('00:00');
const [recordingInterval, setRecordingInterval] = useState(null);
const [file, setFile] = useState(null);
const [isRecorded, setIsRecorded] = useState(false);
- const threadId = useMessageStore((_state) => _state.threadMainMessage?._id);
const onStop = (videoChunks) => {
const videoBlob = new Blob(videoChunks, { type: 'video/mp4' });
@@ -135,16 +132,9 @@ const VideoMessageRecorder = () => {
}, [handleMount]);
useEffect(() => {
- const sendRecording = async () => {
- await RCInstance.sendAttachment(
- file,
- undefined,
- undefined,
- ECOptions.enableThreads ? threadId : undefined
- );
- };
if (isRecorded && file) {
- sendRecording();
+ toggle();
+ setData(file);
setIsRecorded(false);
}
if (file) {
From a8f3226186369d3f9eb435d98e85911737b45738 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 21:28:08 +0530
Subject: [PATCH 053/153] Fix: Prevent click actions when disabled (#736)
---
.../react/src/views/ChatInput/AudioMessageRecorder.js | 10 ++++++++--
.../src/views/ChatInput/ChatInputFormattingToolbar.js | 11 ++++++++---
.../react/src/views/ChatInput/VideoMessageRecoder.js | 10 ++++++++--
3 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/packages/react/src/views/ChatInput/AudioMessageRecorder.js b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
index 1d3af014fc..8f2287569b 100644
--- a/packages/react/src/views/ChatInput/AudioMessageRecorder.js
+++ b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
@@ -5,7 +5,7 @@ import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
import useAttachmentWindowStore from '../../store/attachmentwindow';
-const AudioMessageRecorder = () => {
+const AudioMessageRecorder = ({ disabled }) => {
const videoRef = useRef(null);
const { theme } = useTheme();
const styles = getCommonRecorderStyles(theme);
@@ -47,6 +47,7 @@ const AudioMessageRecorder = () => {
};
const handleRecordButtonClick = () => {
+ if (disabled) return;
setRecordState('recording');
try {
start();
@@ -130,7 +131,12 @@ const AudioMessageRecorder = () => {
if (state === 'idle') {
return (
-
+
);
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 851034833d..0097471058 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -80,6 +80,7 @@ const ChatInputFormattingToolbar = ({
ghost
disabled={isRecordingMessage}
onClick={() => {
+ if (isRecordingMessage) return;
setEmojiOpen(true);
}}
>
@@ -89,12 +90,12 @@ const ChatInputFormattingToolbar = ({
),
audio: (
-
+
),
video: (
-
+
),
file: (
@@ -103,7 +104,10 @@ const ChatInputFormattingToolbar = ({
square
ghost
disabled={isRecordingMessage}
- onClick={handleClickToOpenFiles}
+ onClick={() => {
+ if (isRecordingMessage) return;
+ handleClickToOpenFiles();
+ }}
>
@@ -132,6 +136,7 @@ const ChatInputFormattingToolbar = ({
disabled={isRecordingMessage}
ghost
onClick={() => {
+ if (isRecordingMessage) return;
formatSelection(messageRef, item.pattern);
}}
>
diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
index 2fbe2bb149..911df74c69 100644
--- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js
+++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
@@ -12,7 +12,7 @@ import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
import useAttachmentWindowStore from '../../store/attachmentwindow';
-const VideoMessageRecorder = () => {
+const VideoMessageRecorder = ({ disabled }) => {
const videoRef = useRef(null);
const { theme } = useTheme();
const styles = getCommonRecorderStyles(theme);
@@ -55,6 +55,7 @@ const VideoMessageRecorder = () => {
};
const handleRecordButtonClick = () => {
+ if (disabled) return;
setRecordState('recording');
try {
start(videoRef.current);
@@ -145,7 +146,12 @@ const VideoMessageRecorder = () => {
return (
<>
{state === 'idle' && (
-
+
)}
From f0a94a7d155a5087d71dcaed03ffa9425f0ae78d Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Wed, 8 Jan 2025 20:34:50 +0530
Subject: [PATCH 054/153] Feat: Add cursor pointer on scrollbar thumb hover
(#835)
---
packages/react/src/views/GlobalStyles.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/react/src/views/GlobalStyles.js b/packages/react/src/views/GlobalStyles.js
index c9c821feff..ca4d72fa97 100644
--- a/packages/react/src/views/GlobalStyles.js
+++ b/packages/react/src/views/GlobalStyles.js
@@ -30,6 +30,7 @@ const getGlobalStyles = (theme) => css`
.ec-embedded-chat ::-webkit-scrollbar-thumb:hover {
background: ${theme.colors.primary};
+ cursor: pointer;
}
.ec-embedded-chat ::-webkit-scrollbar-button {
From 4d80839c275d921e44ea8e33c757af96dc28e6b7 Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Wed, 8 Jan 2025 21:22:29 +0530
Subject: [PATCH 055/153] Fix arrow redirection for thread messages in starred
message modal (#833)
* fix redirection
* fix
---
.../common/MessageAggregator.js | 56 +++++++++++++++----
1 file changed, 46 insertions(+), 10 deletions(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 3411d54107..d6ec35541a 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -1,5 +1,5 @@
import React, { useState, useMemo } from 'react';
-import { isSameDay, format } from 'date-fns';
+import { isSameDay, format, set } from 'date-fns';
import {
Box,
Sidebar,
@@ -49,16 +49,52 @@ export const MessageAggregator = ({
);
const setShowSidebar = useSidebarStore((state) => state.setShowSidebar);
- const setJumpToMessage = (msgId) => {
+ const openThread = useMessageStore((state) => state.openThread);
+ const closeThread = useMessageStore((state) => state.closeThread);
+
+ const setJumpToMessage = (msg) => {
+ if (!msg || !msg._id) {
+ console.error('Invalid message object:', msg);
+ return;
+ }
+ const { _id: msgId, tmid: threadId } = msg;
if (msgId) {
- const element = document.getElementById(`ec-message-body-${msgId}`);
- if (element) {
- setShowSidebar(false);
- element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
- element.style.backgroundColor = theme.colors.warning;
+ let element;
+ if (threadId) {
+ const parentMessage = messages.find((m) => m._id === threadId);
+ if (parentMessage) {
+ closeThread();
+ setTimeout(() => {
+ openThread(parentMessage);
+ setShowSidebar(false);
+ setTimeout(() => {
+ element = document.getElementById(`ec-message-body-${msgId}`);
+ if (element) {
+ element.scrollIntoView({
+ behavior: 'smooth',
+ block: 'nearest',
+ });
+ element.style.backgroundColor = theme.colors.warning;
+ setTimeout(() => {
+ element.style.backgroundColor = '';
+ }, 1000);
+ }
+ }, 300);
+ }, 300);
+ }
+ } else {
+ closeThread();
setTimeout(() => {
- element.style.backgroundColor = '';
- }, 1000);
+ element = document.getElementById(`ec-message-body-${msgId}`);
+ if (element) {
+ setShowSidebar(false);
+ element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
+ element.style.backgroundColor = theme.colors.warning;
+ setTimeout(() => {
+ element.style.backgroundColor = '';
+ }, 1000);
+ }
+ }, 300);
}
}
};
@@ -146,7 +182,7 @@ export const MessageAggregator = ({
setJumpToMessage(msg._id)}
+ onClick={() => setJumpToMessage(msg)}
css={{
position: 'relative',
zIndex: 10,
From 7ef302e4d9b7a289d36392903eb6314ec9cdb472 Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sat, 11 Jan 2025 16:39:31 +0530
Subject: [PATCH 056/153] fix: ensure Admin role tag is visible to all users in
channel messages (#784)
---
packages/api/src/EmbeddedChatApi.ts | 35 ++++++++++++++++++++
packages/react/src/hooks/useFetchChatData.js | 8 ++---
2 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index c2fdabb694..408f811c5a 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -605,6 +605,41 @@ export default class EmbeddedChatApi {
}
}
+ async getUserRoles() {
+ try {
+ const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
+ const response = await fetch(
+ `${this.host}/api/v1/method.call/getUserRoles`,
+ {
+ body: JSON.stringify({
+ message: JSON.stringify({
+ msg: "method",
+ id: null,
+ method: "getUserRoles",
+ params: [],
+ }),
+ }),
+ headers: {
+ "Content-Type": "application/json",
+ "X-Auth-Token": authToken,
+ "X-User-Id": userId,
+ },
+ method: "POST",
+ }
+ );
+
+ const result = await response.json();
+
+ if (result.success && result.message) {
+ const parsedMessage = JSON.parse(result.message);
+ return parsedMessage;
+ }
+ return null;
+ } catch (err) {
+ console.error(err);
+ }
+ }
+
async sendTypingStatus(username: string, typing: boolean) {
try {
this.rcClient.methodCall(
diff --git a/packages/react/src/hooks/useFetchChatData.js b/packages/react/src/hooks/useFetchChatData.js
index 9eb04e9bee..583ad431e5 100644
--- a/packages/react/src/hooks/useFetchChatData.js
+++ b/packages/react/src/hooks/useFetchChatData.js
@@ -55,10 +55,10 @@ const useFetchChatData = (showRoles) => {
if (showRoles) {
const { roles } = await RCInstance.getChannelRoles(isChannelPrivate);
- const fetchedAdmins = await RCInstance.getUsersInRole('admin');
- const adminUsernames = fetchedAdmins?.users?.map(
- (user) => user.username
- );
+ const fetchedRoles = await RCInstance.getUserRoles();
+ const fetchedAdmins = fetchedRoles?.result;
+
+ const adminUsernames = fetchedAdmins?.map((user) => user.username);
setAdmins(adminUsernames);
const rolesObj =
From a593589b906a4b1ef80353cef408d00d9a978546 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 16:50:24 +0530
Subject: [PATCH 057/153] Fix announcement issue (#851)
---
packages/react/src/views/ChatHeader/ChatHeader.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 817ff40975..7e4864adae 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -136,6 +136,7 @@ const ChatHeader = ({
try {
await RCInstance.logout();
setMessages([]);
+ setChannelInfo({});
setShowSidebar(false);
setUserAvatarUrl(null);
useMessageStore.setState({ isMessageLoaded: false });
From 7e3105a8d70986810a9b795798215bb1eb095617 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 16:53:40 +0530
Subject: [PATCH 058/153] Fix: Prevent Quoting the Same Message Multiple Times
(#800)
* fix multiple quote messages addition and deletion
* revert removeQuoteMessage
---
packages/react/src/store/messageStore.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index 676258c1c4..69d1d2b73f 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -75,11 +75,17 @@ const useMessageStore = create((set, get) => ({
setEditMessagePermissions: (editMessagePermissions) =>
set((state) => ({ ...state, editMessagePermissions })),
addQuoteMessage: (quoteMessage) =>
- set((state) => ({ quoteMessage: [...state.quoteMessage, quoteMessage] })),
+ set((state) => {
+ const updatedQuoteMessages = state.quoteMessage.filter(
+ (msg) => msg._id !== quoteMessage._id
+ );
+ return { quoteMessage: [...updatedQuoteMessages, quoteMessage] };
+ }),
removeQuoteMessage: (quoteMessage) =>
set((state) => ({
quoteMessage: state.quoteMessage.filter((i) => i !== quoteMessage),
})),
+
clearQuoteMessages: () => set({ quoteMessage: [] }),
setMessageToReport: (messageId) =>
set(() => ({ messageToReport: messageId })),
From 2f833441a10643b19f12cf1c235b952ba0e654db Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 16:54:12 +0530
Subject: [PATCH 059/153] fix delete modal content and markdown issues (#774)
Co-authored-by: Zishan Ahmad
---
.../views/AttachmentHandler/TextAttachment.js | 37 ++++++++---
.../react/src/views/Message/MessageToolbox.js | 64 +++++++++++++++++--
.../src/views/QuoteMessage/QuoteMessage.js | 4 +-
3 files changed, 87 insertions(+), 18 deletions(-)
diff --git a/packages/react/src/views/AttachmentHandler/TextAttachment.js b/packages/react/src/views/AttachmentHandler/TextAttachment.js
index bc79b8c5c4..b8477cd8bb 100644
--- a/packages/react/src/views/AttachmentHandler/TextAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/TextAttachment.js
@@ -3,6 +3,7 @@ import { css } from '@emotion/react';
import PropTypes from 'prop-types';
import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
+import { Markdown } from '../Markdown';
const TextAttachment = ({ attachment, type, variantStyles = {} }) => {
const { RCInstance } = useContext(RCContext);
@@ -62,11 +63,19 @@ const TextAttachment = ({ attachment, type, variantStyles = {} }) => {
white-space: pre-line;
`}
>
- {attachment?.text
- ? attachment.text[0] === '['
- ? attachment.text.match(/\n(.*)/)?.[1] || ''
- : attachment.text
- : ''}
+ {attachment?.text ? (
+ attachment.text[0] === '[' ? (
+ attachment.text.match(/\n(.*)/)?.[1] || ''
+ ) : (
+
+ )
+ ) : (
+ ''
+ )}
{attachment?.attachments &&
attachment.attachments.map((nestedAttachment, index) => (
{
white-space: pre-line;
`}
>
- {nestedAttachment?.text
- ? nestedAttachment.text[0] === '['
- ? nestedAttachment.text.match(/\n(.*)/)?.[1] || ''
- : nestedAttachment.text
- : ''}
+ {nestedAttachment?.text ? (
+ nestedAttachment.text[0] === '[' ? (
+ nestedAttachment.text.match(/\n(.*)/)?.[1] || ''
+ ) : (
+
+ )
+ ) : (
+ ''
+ )}
))}
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index f276ef82cf..34752872eb 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -1,4 +1,4 @@
-import React, { useState, useMemo } from 'react';
+import React, { useState, useContext, useMemo } from 'react';
import {
Box,
Modal,
@@ -9,10 +9,12 @@ import {
appendClassNames,
useTheme,
} from '@embeddedchat/ui-elements';
+import RCContext from '../../context/RCInstance';
import { EmojiPicker } from '../EmojiPicker';
import { getMessageToolboxStyles } from './Message.styles';
import SurfaceMenu from '../SurfaceMenu/SurfaceMenu';
import { Markdown } from '../Markdown';
+import Attachment from '../AttachmentHandler/Attachment';
export const MessageToolbox = ({
className = '',
@@ -59,6 +61,8 @@ export const MessageToolbox = ({
className,
style
);
+ const { RCInstance } = useContext(RCContext);
+ const instanceHost = RCInstance.getHost();
const { theme } = useTheme();
const styles = getMessageToolboxStyles(theme);
const surfaceItems =
@@ -269,13 +273,61 @@ export const MessageToolbox = ({
-
+ {message.file ? (
+ message.file.type.startsWith('image/') ? (
+
+

+
{`${message.file.name} (${(
+ message.file.size / 1024
+ ).toFixed(2)} kB)`}
+
+ ) : message.file.type.startsWith('video/') ? (
+
+ ) : message.file.type.startsWith('audio/') ? (
+
+ ) : (
+
+ )
+ ) : (
+
+ )}
+ {message.attachments &&
+ message.attachments.length > 0 &&
+ message.msg &&
+ message.msg[0] === '[' &&
+ message.attachments.map((attachment, index) => (
+
+ ))}
diff --git a/packages/react/src/views/QuoteMessage/QuoteMessage.js b/packages/react/src/views/QuoteMessage/QuoteMessage.js
index 2a402da43a..7fd9634e04 100644
--- a/packages/react/src/views/QuoteMessage/QuoteMessage.js
+++ b/packages/react/src/views/QuoteMessage/QuoteMessage.js
@@ -85,7 +85,7 @@ const QuoteMessage = ({ className = '', style = {}, message }) => {
) : (
{message.msg ? (
-
+
) : (
`${message.file?.name} (${
message.file?.size ? (message.file.size / 1024).toFixed(2) : 0
@@ -96,7 +96,7 @@ const QuoteMessage = ({ className = '', style = {}, message }) => {
) : message?.msg[0] === '[' ? (
message?.msg.match(/\n(.*)/)[1]
) : (
-
+
)}
{message.attachments &&
message.attachments.length > 0 &&
From dc2c2dd58430773fa599a94656980fc30a46ccdf Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 17:03:10 +0530
Subject: [PATCH 060/153] fix: thread message issue (#860)
* fix thread message issue
* Fix aggregator issue
---
packages/api/src/EmbeddedChatApi.ts | 26 ++--
packages/react/src/views/ChatBody/ChatBody.js | 2 +-
.../common/MessageAggregator.js | 113 +++++++++---------
.../src/views/MessageList/MessageList.js | 6 +-
4 files changed, 80 insertions(+), 67 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 408f811c5a..2f843a1cd8 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -553,15 +553,23 @@ export default class EmbeddedChatApi {
}
async getThreadMessages(tmid: string, isChannelPrivate = false) {
- return this.getMessages(
- false,
- {
- query: {
- tmid,
- },
- },
- isChannelPrivate
- );
+ try {
+ const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
+ const messages = await fetch(
+ `${this.host}/api/v1/chat.getThreadMessages?roomId=${this.rid}&tmid=${tmid}`,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Auth-Token": authToken,
+ "X-User-Id": userId,
+ },
+ method: "GET",
+ }
+ );
+ return await messages.json();
+ } catch (err) {
+ console.log(err);
+ }
}
async getChannelRoles(isChannelPrivate = false) {
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index 721c2d2dc1..940b63e9bb 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -91,7 +91,7 @@ const ChatBody = ({
threadMainMessage._id,
isChannelPrivate
);
- setThreadMessages(messages);
+ setThreadMessages(messages.reverse());
} catch (e) {
console.error(e);
}
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index d6ec35541a..56d52a08c3 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -39,9 +39,10 @@ export const MessageAggregator = ({
const messages = useMessageStore((state) => state.messages);
const threadMessages = useMessageStore((state) => state.threadMessages) || [];
const allMessages = useMemo(
- () => [...messages, ...threadMessages],
+ () => [...messages, ...[...threadMessages].reverse()],
[messages, threadMessages]
);
+
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
fetchedMessageList || searchFiltered || allMessages,
@@ -137,65 +138,67 @@ export const MessageAggregator = ({
)}
- {messageList.map((msg, index, arr) => {
- const newDay = isMessageNewDay(msg, arr[index - 1]);
- if (!messageRendered && shouldRender(msg)) {
- setMessageRendered(true);
- }
+ {[...new Map(messageList.map((msg) => [msg._id, msg])).values()].map(
+ (msg, index, arr) => {
+ const newDay = isMessageNewDay(msg, arr[index - 1]);
+ if (!messageRendered && shouldRender(msg)) {
+ setMessageRendered(true);
+ }
- return (
-
- {type === 'message' && newDay && (
-
- {format(new Date(msg.ts), 'MMMM d, yyyy')}
-
- )}
- {type === 'file' ? (
-
- ) : (
-
-
+ {type === 'message' && newDay && (
+
+ {format(new Date(msg.ts), 'MMMM d, yyyy')}
+
+ )}
+ {type === 'file' ? (
+
-
- setJumpToMessage(msg)}
- css={{
- position: 'relative',
- zIndex: 10,
- marginRight: '5px',
+ ) : (
+
-
-
-
- )}
-
- );
- })}
+
+
+ setJumpToMessage(msg)}
+ css={{
+ position: 'relative',
+ zIndex: 10,
+ marginRight: '5px',
+ }}
+ >
+
+
+
+ )}
+
+ );
+ }
+ )}
)}
diff --git a/packages/react/src/views/MessageList/MessageList.js b/packages/react/src/views/MessageList/MessageList.js
index 14521affd0..29a489be0e 100644
--- a/packages/react/src/views/MessageList/MessageList.js
+++ b/packages/react/src/views/MessageList/MessageList.js
@@ -17,9 +17,11 @@ const MessageList = ({ messages }) => {
const isMessageNewDay = (current, previous) =>
!previous || !isSameDay(new Date(current.ts), new Date(previous.ts));
+ const filteredMessages = messages.filter((msg) => !msg.tmid);
+
return (
<>
- {messages.length === 0 ? (
+ {filteredMessages.length === 0 ? (
{
) : (
<>
- {messages.map((msg, index, arr) => {
+ {filteredMessages.map((msg, index, arr) => {
const prev = arr[index + 1];
const next = arr[index - 1];
From 8b05419c9f880ea316006bf949c303da595f9351 Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sat, 11 Jan 2025 17:06:35 +0530
Subject: [PATCH 061/153] Fix: Add channel-name in msgBox (#857)
* add channel-name in msgBox
* fix
---
packages/react/src/views/ChatInput/ChatInput.js | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 91fc98deca..aca2de0ac7 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -75,10 +75,13 @@ const ChatInput = ({ scrollToBottom }) => {
name: state.name,
}));
- const { isChannelPrivate, isChannelReadOnly } = useChannelStore((state) => ({
- isChannelPrivate: state.isChannelPrivate,
- isChannelReadOnly: state.isChannelReadOnly,
- }));
+ const { isChannelPrivate, isChannelReadOnly, channelInfo } = useChannelStore(
+ (state) => ({
+ isChannelPrivate: state.isChannelPrivate,
+ isChannelReadOnly: state.isChannelReadOnly,
+ channelInfo: state.channelInfo,
+ })
+ );
const { members, setMembersHandler } = useMemberStore((state) => ({
members: state.members,
@@ -514,7 +517,7 @@ const ChatInput = ({ scrollToBottom }) => {
disabled={!isUserAuthenticated || !canSendMsg || isRecordingMessage}
placeholder={
isUserAuthenticated && canSendMsg
- ? 'Message'
+ ? `Message #${channelInfo.name}`
: isUserAuthenticated
? 'This room is read only'
: 'Sign in to chat'
From 727800ae4b70457d7fee2fe54ba32dd9071901c4 Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sat, 11 Jan 2025 17:07:43 +0530
Subject: [PATCH 062/153] Feat: Add icon showing private channel (#867)
* add lock icon
* add icon
* add lock file
* fix size of headerIcon
---
.../react/src/views/ChatHeader/ChatHeader.js | 8 ++++++--
.../src/views/RoomInformation/RoomInformation.js | 15 ++++++++++++++-
.../RoomInformation/RoomInformation.styles.js | 2 ++
.../src/components/Icon/icons/HashLock.js | 16 ++++++++++++++++
.../src/components/Icon/icons/Lock.js | 15 +++++++++++++++
.../src/components/Icon/icons/index.js | 4 ++++
packages/ui-elements/tools/icons-generator.js | 2 ++
7 files changed, 59 insertions(+), 3 deletions(-)
create mode 100644 packages/ui-elements/src/components/Icon/icons/HashLock.js
create mode 100644 packages/ui-elements/src/components/Icon/icons/Lock.js
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 7e4864adae..5f2dbf43ee 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -377,10 +377,14 @@ const ChatHeader = ({
onClick={() => setExclusiveState(setShowChannelinfo)}
>
-
+
{channelInfo.name || channelName || 'channelName'}
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.js b/packages/react/src/views/RoomInformation/RoomInformation.js
index b4e26764c9..ea1d5c7313 100644
--- a/packages/react/src/views/RoomInformation/RoomInformation.js
+++ b/packages/react/src/views/RoomInformation/RoomInformation.js
@@ -6,6 +6,7 @@ import {
Sidebar,
Popup,
useComponentOverrides,
+ Icon,
} from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
import { useChannelStore } from '../../store';
@@ -16,6 +17,7 @@ const Roominfo = () => {
const { RCInstance } = useContext(RCContext);
const styles = getRoomInformationStyles();
const channelInfo = useChannelStore((state) => state.channelInfo);
+ const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
const { variantOverrides } = useComponentOverrides('RoomMember');
const viewType = variantOverrides.viewType || 'Sidebar';
const setExclusiveState = useSetExclusiveState();
@@ -55,7 +57,18 @@ const Roominfo = () => {
- # {channelInfo.name}
+
+
+ {channelInfo.name}
+
{channelInfo.description && (
<>
Description
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.styles.js b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
index 9ab039b94a..5925297dcf 100644
--- a/packages/react/src/views/RoomInformation/RoomInformation.styles.js
+++ b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
@@ -16,6 +16,8 @@ const getRoomInformationStyles = () => {
word-wrap: break-word;
overflow-wrap: anywhere;
white-space: normal;
+ opacity: 0.7;
+ font-size: 0.9rem;
`,
};
diff --git a/packages/ui-elements/src/components/Icon/icons/HashLock.js b/packages/ui-elements/src/components/Icon/icons/HashLock.js
new file mode 100644
index 0000000000..d44f815849
--- /dev/null
+++ b/packages/ui-elements/src/components/Icon/icons/HashLock.js
@@ -0,0 +1,16 @@
+import React from 'react';
+
+const HashLock = (props) => (
+
+);
+
+export default HashLock;
diff --git a/packages/ui-elements/src/components/Icon/icons/Lock.js b/packages/ui-elements/src/components/Icon/icons/Lock.js
new file mode 100644
index 0000000000..00c234f3a5
--- /dev/null
+++ b/packages/ui-elements/src/components/Icon/icons/Lock.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+const Lock = (props) => (
+
+);
+
+export default Lock;
diff --git a/packages/ui-elements/src/components/Icon/icons/index.js b/packages/ui-elements/src/components/Icon/icons/index.js
index 77cd6a4511..3e23f0667d 100644
--- a/packages/ui-elements/src/components/Icon/icons/index.js
+++ b/packages/ui-elements/src/components/Icon/icons/index.js
@@ -4,6 +4,8 @@ import Star from './Star';
import Pin from './Pin';
import ReplyDirectly from './ReplyDirectly';
import Hash from './Hash';
+import HashLock from './HashLock';
+import Lock from './Lock';
import Computer from './Computer';
import Cross from './Cross';
import Mic from './Mic';
@@ -69,6 +71,8 @@ const icons = {
pin: Pin,
'reply-directly': ReplyDirectly,
hash: Hash,
+ hash_lock: HashLock,
+ lock: Lock,
computer: Computer,
cross: Cross,
copy: Copy,
diff --git a/packages/ui-elements/tools/icons-generator.js b/packages/ui-elements/tools/icons-generator.js
index 538d42f406..4b2b2e6ca1 100644
--- a/packages/ui-elements/tools/icons-generator.js
+++ b/packages/ui-elements/tools/icons-generator.js
@@ -8,6 +8,8 @@ const iconsList = [
'star',
'reply-directly',
'hash',
+ 'hash_lock',
+ 'lock',
'computer',
'cross',
'mic',
From b8890044cac148b39695864e0981ffe4ec7268a5 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 21:56:13 +0530
Subject: [PATCH 063/153] fix: video modal responsiveness (#726)
* video modal fix
* Make video modal occupy full space
* make the video modal occupy full size only for smaller screens
* change screen width upper-bound from 500px to 768px
---
packages/react/src/views/ChatInput/ChatInput.styles.js | 8 ++++++++
.../react/src/views/ChatInput/VideoMessageRecoder.js | 9 ++++-----
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.styles.js b/packages/react/src/views/ChatInput/ChatInput.styles.js
index 7aa85e40f1..21e7a24736 100644
--- a/packages/react/src/views/ChatInput/ChatInput.styles.js
+++ b/packages/react/src/views/ChatInput/ChatInput.styles.js
@@ -112,6 +112,14 @@ export const getCommonRecorderStyles = (theme) => {
display: flex;
margin: auto;
`,
+ modal: {
+ '@media(max-width: 768px)': {
+ height: '100%',
+ width: '100%',
+ maxHeight: '100%',
+ maxWidth: '100%',
+ },
+ },
};
return styles;
diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
index 911df74c69..91783d676a 100644
--- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js
+++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
@@ -164,10 +164,7 @@ const VideoMessageRecorder = ({ disabled }) => {
);
};
diff --git a/packages/ui-elements/src/components/StaticSelect/StaticSelect.styles.js b/packages/ui-elements/src/components/StaticSelect/StaticSelect.styles.js
index 3374417f64..e42215564b 100644
--- a/packages/ui-elements/src/components/StaticSelect/StaticSelect.styles.js
+++ b/packages/ui-elements/src/components/StaticSelect/StaticSelect.styles.js
@@ -38,6 +38,15 @@ const getStaticSelectStyles = (theme) => {
cursor: not-allowed !important;
color: ${theme.colors.mutedForeground};
`,
+
+ fileTypeSelect: css`
+ position: absolute;
+ z-index: 10;
+ top: 100%;
+ left: 0;
+ width: 100%;
+ background-color: white;
+ `,
};
return styles;
From bcc7e95e5b9c2f2474fef558652adfec17557565 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sat, 11 Jan 2025 21:58:25 +0530
Subject: [PATCH 065/153] Feat: Added 'Mentions you' and 'Mentions user'
tooltips for mentioned users & underline on hover (#859)
* Feat: Added Tooltip for Send button & Arrow-back button
* removed tooltip for send button & changed label to Jump to message
* Removed gap between tooltip and tooltipArrow for left position
* Added tooltip styles positioning for left, right positions
* Dynamic Positioning for Tooltip with readable code
* Feat: Add 'Mentions you' and 'Mentions user' tooltips for mentioned users & underline on hover
* Update Tooltip.styles.js
* Update Tooltip.js
* Update MessageAggregator.js
* Added tooltip for all and here mentions
---------
Co-authored-by: Zishan Ahmad
---
packages/markups/src/elements/CodeBlock.js | 2 +-
.../markups/src/elements/elements.styles.js | 7 ++++
packages/markups/src/mentions/UserMention.js | 35 ++++++++++++-------
3 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/packages/markups/src/elements/CodeBlock.js b/packages/markups/src/elements/CodeBlock.js
index 54bad69fcb..d2d93901ee 100644
--- a/packages/markups/src/elements/CodeBlock.js
+++ b/packages/markups/src/elements/CodeBlock.js
@@ -1,4 +1,4 @@
-import React, { useMemo, useEffect, useState } from 'react';
+import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { Box, useTheme } from '@embeddedchat/ui-elements';
import SyntaxHighlighter from 'react-syntax-highlighter';
diff --git a/packages/markups/src/elements/elements.styles.js b/packages/markups/src/elements/elements.styles.js
index 2f1f2fb295..31497a6517 100644
--- a/packages/markups/src/elements/elements.styles.js
+++ b/packages/markups/src/elements/elements.styles.js
@@ -99,6 +99,13 @@ const useMentionStyles = (contents, username) => {
cursor: pointer;
padding: 1.5px;
border-radius: 3px;
+
+ &:hover {
+ text-decoration: underline;
+ text-decoration-color: ${contents.value === username
+ ? theme.colors.destructiveForeground
+ : theme.colors.mutedForeground};
+ }
`,
};
diff --git a/packages/markups/src/mentions/UserMention.js b/packages/markups/src/mentions/UserMention.js
index c860a4d70d..45615e4a1a 100644
--- a/packages/markups/src/mentions/UserMention.js
+++ b/packages/markups/src/mentions/UserMention.js
@@ -1,6 +1,6 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
-import { Box } from '@embeddedchat/ui-elements';
+import { Box, Tooltip } from '@embeddedchat/ui-elements';
import { useUserStore } from '@embeddedchat/react/src/store';
import useSetExclusiveState from '@embeddedchat/react/src/hooks/useSetExclusiveState';
import RCContext from '@embeddedchat/react/src/context/RCInstance';
@@ -27,7 +27,9 @@ const UserMention = ({ contents }) => {
};
const hasMember = (user) => {
- if (user === 'all' || user === 'here') return true;
+ if (user === 'all' || user === 'here') {
+ return true;
+ }
let found = false;
Object.keys(members).forEach((ele) => {
if (members[ele].username === user) {
@@ -39,20 +41,27 @@ const UserMention = ({ contents }) => {
const styles = useMentionStyles(contents, username);
+ const handleClick = () => {
+ if (!['here', 'all'].includes(contents.value)) {
+ handleUserInfo(contents.value);
+ }
+ };
+
+ const tooltipMap = {
+ all: 'Mentions all the room members',
+ here: 'Mentions online room members',
+ [username]: 'Mentions you',
+ };
+ const tooltipText = tooltipMap[contents.value] || 'Mentions user';
+
return (
<>
{hasMember(contents.value) ? (
- handleUserInfo(contents.value)
- }
- >
- {contents.value}
-
+
+
+ {contents.value}
+
+
) : (
`@${contents.value}`
)}
From 8f3bb40f65f4dc46e87839ca56cf9bb8f9bb9415 Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sat, 11 Jan 2025 22:10:47 +0530
Subject: [PATCH 066/153] fix: handleNewLine function to properly add new line
in desired location (#838)
* fix shift+enter in messageBox
* lint
---
packages/react/src/views/ChatInput/ChatInput.js | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index aca2de0ac7..33f40d7af3 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -34,7 +34,6 @@ import useShowCommands from '../../hooks/useShowCommands';
import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import formatSelection from '../../lib/formatSelection';
import { parseEmoji } from '../../lib/emoji';
-import { Markdown } from '../Markdown';
const ChatInput = ({ scrollToBottom }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
@@ -172,7 +171,15 @@ const ChatInput = ({ scrollToBottom }) => {
};
const handleNewLine = (e, addLine = true) => {
- if (addLine) messageRef.current.value += '\n';
+ if (addLine) {
+ const { selectionStart, selectionEnd, value } = messageRef.current;
+ messageRef.current.value = `${value.substring(
+ 0,
+ selectionStart
+ )}\n${value.substring(selectionEnd)}`;
+ messageRef.current.selectionStart = messageRef.current.selectionEnd;
+ messageRef.current.selectionEnd = selectionStart + 1;
+ }
e.target.style.height = 'auto';
if (e.target.scrollHeight <= 150) {
From 577a1f05cecd900e51e85db20a64c8b65b95bd9b Mon Sep 17 00:00:00 2001
From: AYUSHKUMAR_21JE0209
<103947228+AyushKumar123456789@users.noreply.github.com>
Date: Mon, 27 Jan 2025 21:41:54 +0530
Subject: [PATCH 067/153] fix:Message notification for avatar change, channel
to team change and team to channel change. (#919)
---
.../react/src/views/Message/MessageHeader.js | 20 ++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/packages/react/src/views/Message/MessageHeader.js b/packages/react/src/views/Message/MessageHeader.js
index 89206256ea..eaaaa54cd0 100644
--- a/packages/react/src/views/Message/MessageHeader.js
+++ b/packages/react/src/views/Message/MessageHeader.js
@@ -68,18 +68,32 @@ const MessageHeader = ({
return 'unarchived room';
case 'room-allowed-reacting':
return 'allowed reactions';
+ case 'room_changed_avatar':
+ return `changed room avatar`;
case 'room_changed_announcement':
- return `changed announcement to: ${
+ return `changed room announcement to: ${
message?.msg && message.msg.length > 0 ? message.msg : '(none)'
}`;
case 'room_changed_description':
- return `changed description to: ${
+ return `changed room description to: ${
message?.msg && message.msg.length > 0 ? message.msg : '(none)'
}`;
case 'room_changed_topic':
- return `changed topic to: ${
+ return `changed room topic to: ${
message?.msg && message.msg.length > 0 ? message.msg : '(none)'
}`;
+ case 'r':
+ return `changed room name to ${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ }`;
+ case 'user-converted-to-team':
+ return `converted #${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ } to team`;
+ case 'user-converted-to-channel':
+ return `converted #${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ } to channel`;
default:
return '';
}
From db8eb49f40c6eb46cf66f7c5e6947e303036306a Mon Sep 17 00:00:00 2001
From: AYUSHKUMAR_21JE0209
<103947228+AyushKumar123456789@users.noreply.github.com>
Date: Mon, 27 Jan 2025 22:16:59 +0530
Subject: [PATCH 068/153] Fix:Formattin toolbar tooltip names according to
rocket.chat (#879)
---
packages/react/src/lib/textFormat.js | 14 +++++++++-----
.../views/ChatInput/ChatInputFormattingToolbar.js | 6 +++++-
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/packages/react/src/lib/textFormat.js b/packages/react/src/lib/textFormat.js
index 10ceb7f33c..a1978c0033 100644
--- a/packages/react/src/lib/textFormat.js
+++ b/packages/react/src/lib/textFormat.js
@@ -1,7 +1,11 @@
export const formatter = [
- { name: 'bold', pattern: '*{{text}}*' },
- { name: 'italic', pattern: '_{{text}}_' },
- { name: 'strike', pattern: '~{{text}}~' },
- { name: 'code', pattern: '`{{text}}`' },
- { name: 'multiline', pattern: '```\n{{text}}\n``` ' },
+ { name: 'bold', pattern: '*{{text}}*', tooltip: 'Bold' },
+ { name: 'italic', pattern: '_{{text}}_', tooltip: 'Italic' },
+ { name: 'strike', pattern: '~{{text}}~', tooltip: 'Strikethrough' },
+ { name: 'code', pattern: '`{{text}}`', tooltip: 'Inline code' },
+ {
+ name: 'multiline',
+ pattern: '```\n{{text}}\n```',
+ tooltip: 'Multi-line code',
+ },
];
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 0097471058..4c72bc4dc6 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -130,7 +130,11 @@ const ChatInputFormattingToolbar = ({
formatter: formatters
.map((name) => formatter.find((item) => item.name === name))
.map((item) => (
-
+
Date: Mon, 27 Jan 2025 22:28:21 +0530
Subject: [PATCH 069/153] Add hover effect to Members section (#847)
---
.../src/views/RoomMembers/RoomMemberItem.js | 7 ++--
.../views/RoomMembers/RoomMembers.styles.js | 36 ++++++++++++-------
2 files changed, 28 insertions(+), 15 deletions(-)
diff --git a/packages/react/src/views/RoomMembers/RoomMemberItem.js b/packages/react/src/views/RoomMembers/RoomMemberItem.js
index 0c38355eb9..f5ff504035 100644
--- a/packages/react/src/views/RoomMembers/RoomMemberItem.js
+++ b/packages/react/src/views/RoomMembers/RoomMemberItem.js
@@ -1,9 +1,9 @@
import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
-import { Box, Icon, Avatar } from '@embeddedchat/ui-elements';
+import { Box, Icon, Avatar, useTheme } from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
-import { RoomMemberItemStyles as styles } from './RoomMembers.styles';
+import { RoomMemberItemStyles } from './RoomMembers.styles';
import useSetExclusiveState from '../../hooks/useSetExclusiveState';
import { useUserStore } from '../../store';
@@ -11,6 +11,9 @@ const RoomMemberItem = ({ user, host }) => {
const { RCInstance } = useContext(RCContext);
const [userStatus, setUserStatus] = useState('');
const avatarUrl = new URL(`avatar/${user.username}`, host).toString();
+ const { theme } = useTheme();
+ const { mode } = useTheme();
+ const styles = RoomMemberItemStyles(theme, mode);
useEffect(() => {
const getStatus = async () => {
diff --git a/packages/react/src/views/RoomMembers/RoomMembers.styles.js b/packages/react/src/views/RoomMembers/RoomMembers.styles.js
index ac9df00bf0..415940c2f4 100644
--- a/packages/react/src/views/RoomMembers/RoomMembers.styles.js
+++ b/packages/react/src/views/RoomMembers/RoomMembers.styles.js
@@ -1,4 +1,5 @@
import { css } from '@emotion/react';
+import { lighten, darken } from '@embeddedchat/ui-elements';
export const getRoomMemberStyles = (theme) => {
const styles = {
@@ -49,20 +50,29 @@ export const getRoomMemberStyles = (theme) => {
return styles;
};
-export const RoomMemberItemStyles = {
- container: css`
- width: 100%;
- padding-bottom: 8px;
- padding-top: 8px;
- display: flex;
- align-items: center;
- `,
+export const RoomMemberItemStyles = (theme, mode) => {
+ const styles = {
+ container: css`
+ width: 100%;
+ padding-bottom: 8px;
+ padding-top: 8px;
+ display: flex;
+ align-items: center;
- icon: css`
- padding: 0.125em;
- margin-right: 0.5rem;
- align-self: center;
- `,
+ &:hover {
+ background-color: ${mode === 'light'
+ ? darken(theme.colors.background, 0.03)
+ : lighten(theme.colors.background, 1)};
+ }
+ `,
+
+ icon: css`
+ padding: 0.125em;
+ margin-right: 0.5rem;
+ align-self: center;
+ `,
+ };
+ return styles;
};
export const InviteMemberStyles = {
From dd4195ae3a2c80fc22271c540b5f842d17c8e395 Mon Sep 17 00:00:00 2001
From: AYUSHKUMAR_21JE0209
<103947228+AyushKumar123456789@users.noreply.github.com>
Date: Mon, 27 Jan 2025 22:40:34 +0530
Subject: [PATCH 070/153] fix : Add Hover Effect to FileMessage Component
(#845)
* feat: Enhance FileMessage component with hover effect based on theme
* fixed linting
---
.../src/views/FileMessage/FileMessage.js | 20 +++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/FileMessage/FileMessage.js b/packages/react/src/views/FileMessage/FileMessage.js
index a074e981ef..4944005c0d 100644
--- a/packages/react/src/views/FileMessage/FileMessage.js
+++ b/packages/react/src/views/FileMessage/FileMessage.js
@@ -1,4 +1,4 @@
-import React, { useState, useCallback, memo } from 'react';
+import React, { useState, useCallback, memo, useContext } from 'react';
import PropTypes from 'prop-types';
import {
Box,
@@ -9,6 +9,9 @@ import {
useToastBarDispatch,
useComponentOverrides,
appendClassNames,
+ useTheme,
+ lighten,
+ darken,
} from '@embeddedchat/ui-elements';
import FilePreviewContainer from './FilePreviewContainer';
import FileBodyContainer from '../Message/MessageBodyContainer';
@@ -26,6 +29,19 @@ const FileMessage = ({ fileMessage }) => {
const { RCInstance } = useRCContext();
const messages = useMessageStore((state) => state.messages);
+ const theme = useTheme();
+ const { mode } = theme;
+ const messageStyles = styles.message;
+
+ const hoverStyle = {
+ '&:hover': {
+ backgroundColor:
+ mode === 'light'
+ ? darken(theme.theme.colors.background, 0.03)
+ : lighten(theme.theme.colors.background, 1),
+ },
+ };
+
const [fileToDelete, setFileToDelete] = useState({});
const downloadFile = useCallback((url, title) => {
@@ -69,7 +85,7 @@ const FileMessage = ({ fileMessage }) => {
From eb0854f5e16bd636236bae6a6cfcedeae85cd7d2 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Mon, 27 Jan 2025 22:46:53 +0530
Subject: [PATCH 071/153] Feat: Show 'Edit Message' Button for all message
types (#826)
* Feat: Conditionally show 'Edit Message' button based on attachment description
* Edit option visible to all message types
---
packages/react/src/views/Message/MessageToolbox.js | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 34752872eb..0208ff663d 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -86,10 +86,6 @@ export const MessageToolbox = ({
? true
: message.u._id === authenticatedUserId;
- const isVisibleForMessageType =
- message.files?.[0].type !== 'audio/mpeg' &&
- message.files?.[0].type !== 'video/mp4';
-
const options = useMemo(
() => ({
reply: {
@@ -140,7 +136,7 @@ export const MessageToolbox = ({
id: 'edit',
onClick: () => handleEditMessage(message),
iconName: 'edit',
- visible: isAllowedToEditMessage && isVisibleForMessageType,
+ visible: isAllowedToEditMessage,
color: isEditing ? 'secondary' : 'default',
ghost: !isEditing,
},
From 93198dc79f9b6bac0483e49252694cd4ce053d79 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Mon, 27 Jan 2025 22:48:55 +0530
Subject: [PATCH 072/153] Fix attachment and avatar responsiveness in messages
(#922)
---
.../src/views/AttachmentHandler/AudioAttachment.js | 6 +++++-
.../src/views/AttachmentHandler/VideoAttachment.js | 3 ++-
packages/react/src/views/Message/Message.styles.js | 3 +++
.../react/src/views/Message/MessageAvatarContainer.js | 10 +++++++++-
4 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/packages/react/src/views/AttachmentHandler/AudioAttachment.js b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
index 8e3ce527a4..5caf16e760 100644
--- a/packages/react/src/views/AttachmentHandler/AudioAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
@@ -76,7 +76,11 @@ const AudioAttachment = ({
isExpanded={isExpanded}
/>
{isExpanded && (
-
+
)}
{attachment.attachments &&
diff --git a/packages/react/src/views/AttachmentHandler/VideoAttachment.js b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
index 4407481ee4..5c29bc507b 100644
--- a/packages/react/src/views/AttachmentHandler/VideoAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
@@ -87,11 +87,12 @@ const VideoAttachment = ({
/>
{isExpanded && (
))}
From 9d84f49d6783f0210a5c534553e7edfb468da83d Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Mon, 27 Jan 2025 23:04:04 +0530
Subject: [PATCH 074/153] feat: Add 'Cancel Recording' and 'Finish Recording'
tooltips for audio/video buttons (#812)
---
.../views/ChatInput/AudioMessageRecorder.js | 42 ++++++++++++-------
.../ChatInput/ChatInputFormattingToolbar.js | 12 +-----
.../views/ChatInput/VideoMessageRecoder.js | 35 +++++++++-------
3 files changed, 50 insertions(+), 39 deletions(-)
diff --git a/packages/react/src/views/ChatInput/AudioMessageRecorder.js b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
index 8f2287569b..9ff497a30f 100644
--- a/packages/react/src/views/ChatInput/AudioMessageRecorder.js
+++ b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
@@ -1,5 +1,11 @@
import React, { useState, useEffect, useCallback, useRef } from 'react';
-import { Box, Icon, ActionButton, useTheme } from '@embeddedchat/ui-elements';
+import {
+ Box,
+ Icon,
+ ActionButton,
+ Tooltip,
+ useTheme,
+} from '@embeddedchat/ui-elements';
import { useMediaRecorder } from '../../hooks/useMediaRecorder';
import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
@@ -131,14 +137,16 @@ const AudioMessageRecorder = ({ disabled }) => {
if (state === 'idle') {
return (
-
-
-
+
+
+
+
+
);
}
@@ -146,18 +154,22 @@ const AudioMessageRecorder = ({ disabled }) => {
{state === 'recording' && (
<>
-
-
-
+
+
+
+
+
{time}
-
-
-
+
+
+
+
+
>
)}
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 4c72bc4dc6..523b9ef976 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -88,16 +88,8 @@ const ChatInputFormattingToolbar = ({
),
- audio: (
-
-
-
- ),
- video: (
-
-
-
- ),
+ audio: ,
+ video: ,
file: (
{
return (
<>
{state === 'idle' && (
-
-
-
+
+
+
+
+
)}
{state === 'recording' && (
@@ -178,16 +181,20 @@ const VideoMessageRecorder = ({ disabled }) => {
`}
/>
-
-
-
+
+
+
+
+
{time}
-
-
-
+
+
+
+
+
>
From bde1a165d67184aff0928ea35dca9e1e470e0c2c Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Thu, 30 Jan 2025 22:59:53 +0530
Subject: [PATCH 075/153] feat: implement loading of older messages
functionality (#810)
* feat: implement loading of older messages functionality
* Fix lint error
* Globalize messages offset
* ensure loader appears far from date header
---
packages/api/src/EmbeddedChatApi.ts | 41 ++++++++++
packages/react/src/hooks/useFetchChatData.js | 4 +-
packages/react/src/store/messageStore.js | 20 +++--
packages/react/src/views/ChatBody/ChatBody.js | 74 ++++++++++++++++-
.../src/views/ChatBody/ChatBody.styles.js | 2 +-
packages/react/src/views/Message/Message.js | 10 +--
.../src/views/MessageList/MessageList.js | 82 ++++++++++++++-----
7 files changed, 197 insertions(+), 36 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 3a1c3b5f9e..44cff0eaf4 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -552,6 +552,47 @@ export default class EmbeddedChatApi {
}
}
+ async getOlderMessages(
+ anonymousMode = false,
+ options: {
+ query?: object | undefined;
+ field?: object | undefined;
+ offset?: number;
+ } = {
+ query: undefined,
+ field: undefined,
+ offset: 50,
+ },
+ isChannelPrivate = false
+ ) {
+ const roomType = isChannelPrivate ? "groups" : "channels";
+ const endp = anonymousMode ? "anonymousread" : "messages";
+ const query = options?.query
+ ? `&query=${JSON.stringify(options.query)}`
+ : "";
+ const field = options?.field
+ ? `&field=${JSON.stringify(options.field)}`
+ : "";
+ const offset = options?.offset ? options.offset : 0;
+ try {
+ const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
+ const messages = await fetch(
+ `${this.host}/api/v1/${roomType}.${endp}?roomId=${this.rid}${query}${field}&offset=${offset}`,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Auth-Token": authToken,
+ "X-User-Id": userId,
+ },
+ method: "GET",
+ }
+ );
+ return await messages.json();
+ } catch (err) {
+ console.log(err);
+ }
+ }
+
async getThreadMessages(tmid: string, isChannelPrivate = false) {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
diff --git a/packages/react/src/hooks/useFetchChatData.js b/packages/react/src/hooks/useFetchChatData.js
index 583ad431e5..7f5b491252 100644
--- a/packages/react/src/hooks/useFetchChatData.js
+++ b/packages/react/src/hooks/useFetchChatData.js
@@ -13,6 +13,7 @@ const useFetchChatData = (showRoles) => {
const setMemberRoles = useMemberStore((state) => state.setMemberRoles);
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
const setMessages = useMessageStore((state) => state.setMessages);
+ const setMessagesOffset = useMessageStore((state) => state.setMessagesOffset);
const setAdmins = useMemberStore((state) => state.setAdmins);
const setStarredMessages = useStarredMessageStore(
(state) => state.setStarredMessages
@@ -31,7 +32,7 @@ const useFetchChatData = (showRoles) => {
return;
}
- const { messages } = await RCInstance.getMessages(
+ const { messages, count } = await RCInstance.getMessages(
anonymousMode,
ECOptions?.enableThreads
? {
@@ -47,6 +48,7 @@ const useFetchChatData = (showRoles) => {
if (messages) {
setMessages(messages.filter((message) => message._hidden !== true));
+ setMessagesOffset(count);
}
if (!isUserAuthenticated) {
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index 69d1d2b73f..a9a7265c86 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -8,6 +8,7 @@ const useMessageStore = create((set, get) => ({
threadMessages: [],
filtered: false,
editMessage: {},
+ messagesOffset: 0,
quoteMessage: [],
messageToReport: NaN,
showReportMessage: false,
@@ -16,11 +17,19 @@ const useMessageStore = create((set, get) => ({
threadMainMessage: null,
headerTitle: null,
setFilter: (filter) => set(() => ({ filtered: filter })),
- setMessages: (messages) =>
- set(() => ({
- messages,
- isMessageLoaded: true,
- })),
+ setMessages: (newMessages, append = false) =>
+ set((state) => {
+ const allMessages = append
+ ? [...state.messages, ...newMessages]
+ : newMessages;
+ const uniqueMessages = Array.from(
+ new Map(allMessages.map((msg) => [msg._id, msg])).values()
+ );
+ return {
+ messages: uniqueMessages,
+ isMessageLoaded: true,
+ };
+ }),
upsertMessage: (message, enableThreads = false) => {
if (message.tmid && enableThreads) {
if (get().threadMainMessage?._id === message.tmid) {
@@ -71,6 +80,7 @@ const useMessageStore = create((set, get) => ({
}
},
setEditMessage: (editMessage) => set(() => ({ editMessage })),
+ setMessagesOffset: (newOffset) => set(() => ({ messagesOffset: newOffset })),
editMessagePermissions: {},
setEditMessagePermissions: (editMessagePermissions) =>
set((state) => ({ ...state, editMessagePermissions })),
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index 940b63e9bb..8d7c3ac978 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -51,14 +51,19 @@ const ChatBody = ({
const { RCInstance, ECOptions } = useContext(RCContext);
const showAnnouncement = ECOptions?.showAnnouncement;
const messages = useMessageStore((state) => state.messages);
+ const offset = useMessageStore((state) => state.messagesOffset);
+ const setMessagesOffset = useMessageStore((state) => state.setMessagesOffset);
const threadMessages = useMessageStore((state) => state.threadMessages);
const [isModalOpen, setModalOpen] = useState(false);
const setThreadMessages = useMessageStore((state) => state.setThreadMessages);
const upsertMessage = useMessageStore((state) => state.upsertMessage);
+ const [loadingOlderMessages, setLoadingOlderMessages] = useState(false);
+ const [hasMoreMessages, setHasMoreMessages] = useState(true);
const removeMessage = useMessageStore((state) => state.removeMessage);
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
const channelInfo = useChannelStore((state) => state.channelInfo);
const isLoginIn = useLoginStore((state) => state.isLoginIn);
+ const setMessages = useMessageStore((state) => state.setMessages);
const [isThreadOpen, threadMainMessage] = useMessageStore((state) => [
state.isThreadOpen,
@@ -153,6 +158,7 @@ const ChatBody = ({
RCInstance.auth.onAuthChange((user) => {
if (user) {
getMessagesAndRoles();
+ setHasMoreMessages(true);
} else {
getMessagesAndRoles(anonymousMode);
}
@@ -166,13 +172,57 @@ const ChatBody = ({
setPopupVisible(false);
};
- const handleScroll = useCallback(() => {
+ const handleScroll = useCallback(async () => {
if (messageListRef && messageListRef.current) {
setScrollPosition(messageListRef.current.scrollTop);
setIsUserScrolledUp(
messageListRef.current.scrollTop + messageListRef.current.clientHeight <
messageListRef.current.scrollHeight
);
+
+ if (
+ messageListRef.current.scrollTop === 0 &&
+ !loadingOlderMessages &&
+ hasMoreMessages
+ ) {
+ setLoadingOlderMessages(true);
+
+ try {
+ const olderMessages = await RCInstance.getOlderMessages(
+ anonymousMode,
+ ECOptions?.enableThreads
+ ? {
+ query: {
+ tmid: {
+ $exists: false,
+ },
+ },
+ offset,
+ }
+ : undefined,
+ anonymousMode ? false : isChannelPrivate
+ );
+ const messageList = messageListRef.current;
+ if (olderMessages?.messages?.length) {
+ const previousScrollHeight = messageList.scrollHeight;
+
+ setMessages(olderMessages.messages, true);
+ setMessagesOffset(offset + olderMessages.messages.length);
+
+ requestAnimationFrame(() => {
+ const newScrollHeight = messageList.scrollHeight;
+ messageList.scrollTop = newScrollHeight - previousScrollHeight;
+ });
+ } else {
+ setHasMoreMessages(false);
+ }
+ } catch (error) {
+ console.error('Error fetching older messages:', error);
+ setHasMoreMessages(false);
+ } finally {
+ setLoadingOlderMessages(false);
+ }
+ }
}
const isAtBottom = messageListRef?.current?.scrollTop === 0;
@@ -183,6 +233,15 @@ const ChatBody = ({
}
}, [
messageListRef,
+ offset,
+ setMessagesOffset,
+ setMessages,
+ anonymousMode,
+ hasMoreMessages,
+ RCInstance,
+ isChannelPrivate,
+ ECOptions?.enableThreads,
+ loadingOlderMessages,
setScrollPosition,
setIsUserScrolledUp,
setPopupVisible,
@@ -207,6 +266,12 @@ const ChatBody = ({
}
};
+ useEffect(() => {
+ if (messageListRef.current) {
+ messageListRef.current.scrollTop = messageListRef.current.scrollHeight;
+ }
+ }, [messages]);
+
useEffect(() => {
checkOverflow();
}, [channelInfo.announcement, showAnnouncement]);
@@ -292,7 +357,12 @@ const ChatBody = ({
threadMessages={threadMessages}
/>
) : (
-
+
)}
diff --git a/packages/react/src/views/ChatBody/ChatBody.styles.js b/packages/react/src/views/ChatBody/ChatBody.styles.js
index f7824d924f..20deecd1f5 100644
--- a/packages/react/src/views/ChatBody/ChatBody.styles.js
+++ b/packages/react/src/views/ChatBody/ChatBody.styles.js
@@ -9,7 +9,7 @@ export const getChatbodyStyles = (theme, mode) => {
overflow: auto;
overflow-x: hidden;
display: flex;
- flex-direction: column-reverse;
+ flex-direction: column;
max-height: 100%;
position: relative;
padding-top: 70px;
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index fa8c864fec..dd8cf8d09d 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -212,6 +212,11 @@ const Message = ({
return (
<>
+ {newDay && (
+
+ {format(new Date(message.ts), 'MMMM d, yyyy')}
+
+ )}
- {newDay && (
-
- {format(new Date(message.ts), 'MMMM d, yyyy')}
-
- )}
>
);
};
diff --git a/packages/react/src/views/MessageList/MessageList.js b/packages/react/src/views/MessageList/MessageList.js
index 29a489be0e..6a13952165 100644
--- a/packages/react/src/views/MessageList/MessageList.js
+++ b/packages/react/src/views/MessageList/MessageList.js
@@ -2,17 +2,24 @@ import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import { isSameDay } from 'date-fns';
-import { Box, Icon } from '@embeddedchat/ui-elements';
+import { Box, Icon, Throbber, useTheme } from '@embeddedchat/ui-elements';
import { useMessageStore } from '../../store';
import MessageReportWindow from '../ReportMessage/MessageReportWindow';
import isMessageSequential from '../../lib/isMessageSequential';
import { Message } from '../Message';
import isMessageLastSequential from '../../lib/isMessageLastSequential';
+import { MessageBody } from '../Message/MessageBody';
-const MessageList = ({ messages }) => {
+const MessageList = ({
+ messages,
+ loadingOlderMessages,
+ isUserAuthenticated,
+ hasMoreMessages,
+}) => {
const showReportMessage = useMessageStore((state) => state.showReportMessage);
const messageToReport = useMessageStore((state) => state.messageToReport);
const isMessageLoaded = useMessageStore((state) => state.isMessageLoaded);
+ const { theme } = useTheme();
const isMessageNewDay = (current, previous) =>
!previous || !isSameDay(new Date(current.ts), new Date(previous.ts));
@@ -37,28 +44,59 @@ const MessageList = ({ messages }) => {
) : (
<>
- {filteredMessages.map((msg, index, arr) => {
- const prev = arr[index + 1];
- const next = arr[index - 1];
+ {!hasMoreMessages && isUserAuthenticated && (
+
+ Start of conversation
+
+ )}
+ {loadingOlderMessages && isUserAuthenticated && (
+
+
+
+ )}
+ {messages
+ .slice()
+ .reverse()
+ .map((msg, index, arr) => {
+ const prev = arr[index - 1];
+ const next = arr[index + 1];
- if (!msg) return null;
- const newDay = isMessageNewDay(msg, prev);
- const sequential = isMessageSequential(msg, prev, 300);
- const lastSequential =
- sequential && isMessageLastSequential(msg, next);
+ if (!msg) return null;
+ const newDay = isMessageNewDay(msg, prev);
+ const sequential = isMessageSequential(msg, prev, 300);
+ const lastSequential =
+ sequential && isMessageLastSequential(msg, next);
- return (
-
- );
- })}
+ return (
+
+ );
+ })}
{showReportMessage && (
)}
From 2004d448cde695fa923f3f78cee1bc68ab18612c Mon Sep 17 00:00:00 2001
From: AYUSHKUMAR_21JE0209
<103947228+AyushKumar123456789@users.noreply.github.com>
Date: Thu, 30 Jan 2025 23:36:52 +0530
Subject: [PATCH 076/153] feat : added icon to show Update ChannelHeader and
RoomInfo UI for (Channels Converted to Teams). (#926)
* feat : added icon to show channel is team now
* Fixed prettier
---------
Co-authored-by: Zishan Ahmad
---
packages/react/src/store/channelStore.js | 2 ++
packages/react/src/views/ChatHeader/ChatHeader.js | 11 ++++++++++-
.../src/views/RoomInformation/RoomInformation.js | 8 +++++---
.../ui-elements/src/components/Icon/icons/Team.js | 15 +++++++++++++++
.../src/components/Icon/icons/index.js | 2 ++
packages/ui-elements/tools/icons-generator.js | 1 +
6 files changed, 35 insertions(+), 4 deletions(-)
create mode 100644 packages/ui-elements/src/components/Icon/icons/Team.js
diff --git a/packages/react/src/store/channelStore.js b/packages/react/src/store/channelStore.js
index 2ba08bddb4..f3acbb914f 100644
--- a/packages/react/src/store/channelStore.js
+++ b/packages/react/src/store/channelStore.js
@@ -4,10 +4,12 @@ const useChannelStore = create((set) => ({
showChannelinfo: false,
isChannelPrivate: false,
isChannelReadOnly: false,
+ isRoomTeam: false,
setShowChannelinfo: (showChannelinfo) => set(() => ({ showChannelinfo })),
channelInfo: {},
setChannelInfo: (channelInfo) => set(() => ({ channelInfo })),
setIsChannelPrivate: (isChannelPrivate) => set(() => ({ isChannelPrivate })),
+ setIsRoomTeam: (isRoomTeam) => set(() => ({ isRoomTeam })),
setIsChannelReadOnly: (isChannelReadOnly) =>
set(() => ({ isChannelReadOnly })),
}));
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 5f2dbf43ee..0971ce7c77 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -73,6 +73,8 @@ const ChatHeader = ({
const setIsChannelPrivate = useChannelStore(
(state) => state.setIsChannelPrivate
);
+ const isRoomTeam = useChannelStore((state) => state.isRoomTeam);
+ const setIsRoomTeam = useChannelStore((state) => state.setIsRoomTeam);
const setIsChannelReadOnly = useChannelStore(
(state) => state.setIsChannelReadOnly
);
@@ -177,6 +179,7 @@ const ChatHeader = ({
if (res.success) {
setChannelInfo(res.room);
if (res.room.t === 'p') setIsChannelPrivate(true);
+ if (res.room?.teamMain) setIsRoomTeam(true);
if (res.room.ro) {
setIsChannelReadOnly(true);
setMessageAllowed();
@@ -377,7 +380,13 @@ const ChatHeader = ({
onClick={() => setExclusiveState(setShowChannelinfo)}
>
{
const styles = getRoomInformationStyles();
const channelInfo = useChannelStore((state) => state.channelInfo);
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
+ const isRoomTeam = useChannelStore((state) => state.isRoomTeam);
const { variantOverrides } = useComponentOverrides('RoomMember');
const viewType = variantOverrides.viewType || 'Sidebar';
const setExclusiveState = useSetExclusiveState();
@@ -30,7 +31,7 @@ const Roominfo = () => {
return (
setExclusiveState(null)}
style={{ width: '400px', zIndex: window.innerWidth <= 780 ? 1 : null }}
@@ -59,12 +60,13 @@ const Roominfo = () => {
{channelInfo.name}
diff --git a/packages/ui-elements/src/components/Icon/icons/Team.js b/packages/ui-elements/src/components/Icon/icons/Team.js
new file mode 100644
index 0000000000..4602e9703c
--- /dev/null
+++ b/packages/ui-elements/src/components/Icon/icons/Team.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+const Team = (props) => (
+
+);
+
+export default Team;
diff --git a/packages/ui-elements/src/components/Icon/icons/index.js b/packages/ui-elements/src/components/Icon/icons/index.js
index 3e23f0667d..234251edab 100644
--- a/packages/ui-elements/src/components/Icon/icons/index.js
+++ b/packages/ui-elements/src/components/Icon/icons/index.js
@@ -63,6 +63,7 @@ import Arc from './Arc';
import Avatar from './Avatar';
import FormatText from './FormatText';
import Cog from './Cog';
+import Team from './Team';
const icons = {
file: File,
@@ -76,6 +77,7 @@ const icons = {
computer: Computer,
cross: Cross,
copy: Copy,
+ team: Team,
mic: Mic,
'video-recorder': VideoRecorder,
'disabled-recorder': DisabledRecorder,
diff --git a/packages/ui-elements/tools/icons-generator.js b/packages/ui-elements/tools/icons-generator.js
index 4b2b2e6ca1..d12396c2b1 100644
--- a/packages/ui-elements/tools/icons-generator.js
+++ b/packages/ui-elements/tools/icons-generator.js
@@ -13,6 +13,7 @@ const iconsList = [
'computer',
'cross',
'mic',
+ 'team',
'circle-cross',
'circle-check',
'send',
From 016e985acaf856aff7e627eb18bd2108542678c2 Mon Sep 17 00:00:00 2001
From: Stpriyasharma <155813664+Stpriyasharma@users.noreply.github.com>
Date: Fri, 31 Jan 2025 00:50:48 +0530
Subject: [PATCH 077/153] chore: Feat + Fix: added searchbar + emoji name and
fixed emoji picker position (#930)
* added searchbar + emoji name and fixed emoji picker position
* added theme background to emojiPicker
* changes
* changes
* fixed format err
---------
Co-authored-by: Zishan Ahmad
---
packages/react/src/views/EmojiPicker/EmojiPicker.js | 11 +++++------
.../react/src/views/EmojiPicker/EmojiPicker.styles.js | 10 ++++------
2 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/packages/react/src/views/EmojiPicker/EmojiPicker.js b/packages/react/src/views/EmojiPicker/EmojiPicker.js
index bc56649fdf..6501eb8320 100644
--- a/packages/react/src/views/EmojiPicker/EmojiPicker.js
+++ b/packages/react/src/views/EmojiPicker/EmojiPicker.js
@@ -17,11 +17,10 @@ const CustomEmojiPicker = ({
}) => {
const theme = useTheme();
const styles = getEmojiPickerStyles(theme);
-
const previewConfig = {
defaultEmoji: '1f60d',
defaultCaption: 'None',
- showPreview: false,
+ showPreview: true,
};
return (
@@ -32,13 +31,13 @@ const CustomEmojiPicker = ({
height="auto"
width="auto"
>
-
+
diff --git a/packages/react/src/views/EmojiPicker/EmojiPicker.styles.js b/packages/react/src/views/EmojiPicker/EmojiPicker.styles.js
index 457c3984c5..72350e13ee 100644
--- a/packages/react/src/views/EmojiPicker/EmojiPicker.styles.js
+++ b/packages/react/src/views/EmojiPicker/EmojiPicker.styles.js
@@ -14,7 +14,7 @@ const getEmojiPickerStyles = ({ theme, mode }) => {
--epr-picker-border-color: ${theme.colors.border};
--epr-category-label-bg-color: ${theme.colors.background};
--epr-category-icon-active-color: ${theme.colors.secondary};
- --epr-emoji-size: 20px;
+ --epr-emoji-size: 25px;
--epr-category-navigation-button-size: 20px;
--epr-emoji-gap: 10px;
@@ -38,7 +38,7 @@ const getEmojiPickerStyles = ({ theme, mode }) => {
--epr-search-bar-inner-padding: var(--epr-horizontal-padding);
--epr-emoji-variation-picker-height: 45px;
--epr-emoji-variation-picker-bg-color: var(--epr-bg-color);
- --epr-preview-height: 70px;
+ --epr-preview-height: 65px;
--epr-preview-text-size: 14px;
--epr-preview-text-padding: 0 var(--epr-horizontal-padding);
--epr-preview-border-color: var(--epr-picker-border-color);
@@ -49,9 +49,7 @@ const getEmojiPickerStyles = ({ theme, mode }) => {
--epr-category-label-height: 40px;
--epr-emoji-padding: 5px;
- --epr-emoji-fullsize: calc(
- var(--epr-emoji-size) + var(--epr-emoji-padding) * 2
- );
+
--epr-emoji-hover-color: var(--epr-hover-bg-color);
--epr-emoji-variation-indicator-color: var(--epr-picker-border-color);
--epr-emoji-variation-indicator-color-hover: var(--epr-text-color);
@@ -60,11 +58,11 @@ const getEmojiPickerStyles = ({ theme, mode }) => {
--epr-category-label-z-index: 2;
--epr-skin-variation-picker-z-index: 5;
--epr-preview-z-index: 6;
+ --epr-search-input-bg-color: ${calculatedColors};
/* Use these properties of color if needed ->
--epr-shadow: 'theme-color';
- --epr-search-input-bg-color: 'theme-color';
--epr-skin-tone-picker-menu-color: 'theme-color';
--epr-dark: 'theme-color'
--epr-dark-emoji-variation-picker-bg-color: var(--epr-dark);
From b501f7632c98b03b40c1a2907d0a112bb4102967 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Fri, 31 Jan 2025 01:00:09 +0530
Subject: [PATCH 078/153] fix: ChatInput Formatter Tool UI for small screens
(#693)
* Fix chatFormatter Toolbar UI
* make message box and popover menu occupy full width
* make message composer configurable
* zIndex fix
* resolve conflict
* Place popoverMenu icon to the extreme right
* feat: Add 'Cancel Recording' and 'Finish Recording' tooltips for audio/video buttons (#812)
* fix message box width and minor UI issues for chatinput formatters
* remove redundant tooltip
* remove audio from pop over menu
* run prettier
* fix audio issue
* change font size for chat input
---------
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
---
.../views/ChatInput/AudioMessageRecorder.js | 15 +-
.../react/src/views/ChatInput/ChatInput.js | 2 +-
.../src/views/ChatInput/ChatInput.styles.js | 31 +-
.../ChatInput/ChatInputFormattingToolbar.js | 277 ++++++++++++++----
.../views/ChatInput/VideoMessageRecoder.js | 34 ++-
.../views/QuoteMessage/QuoteMessage.styles.js | 5 +
6 files changed, 296 insertions(+), 68 deletions(-)
diff --git a/packages/react/src/views/ChatInput/AudioMessageRecorder.js b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
index 9ff497a30f..53dbddf4bd 100644
--- a/packages/react/src/views/ChatInput/AudioMessageRecorder.js
+++ b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
@@ -11,7 +11,8 @@ import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
import useAttachmentWindowStore from '../../store/attachmentwindow';
-const AudioMessageRecorder = ({ disabled }) => {
+const AudioMessageRecorder = (props) => {
+ const { disabled, displayName, popOverItemStyles } = props;
const videoRef = useRef(null);
const { theme } = useTheme();
const styles = getCommonRecorderStyles(theme);
@@ -136,7 +137,17 @@ const AudioMessageRecorder = ({ disabled }) => {
}, [isRecorded, file]);
if (state === 'idle') {
- return (
+ return displayName ? (
+
+
+ {displayName}
+
+ ) : (
{
disabled={!isUserAuthenticated || !canSendMsg || isRecordingMessage}
placeholder={
isUserAuthenticated && canSendMsg
- ? `Message #${channelInfo.name}`
+ ? `Message ${channelInfo.name ? `#${channelInfo.name}` : ''}`
: isUserAuthenticated
? 'This room is read only'
: 'Sign in to chat'
diff --git a/packages/react/src/views/ChatInput/ChatInput.styles.js b/packages/react/src/views/ChatInput/ChatInput.styles.js
index 21e7a24736..b193d06922 100644
--- a/packages/react/src/views/ChatInput/ChatInput.styles.js
+++ b/packages/react/src/views/ChatInput/ChatInput.styles.js
@@ -10,6 +10,10 @@ export const getChatInputStyles = (theme) => {
&.focused {
border: ${`1.5px solid ${theme.colors.ring}`};
}
+ @media (max-width: 500px) {
+ margin: 0;
+ width: 100%;
+ }
`,
editMessage: css`
@@ -80,10 +84,27 @@ export const getChatInputFormattingToolbarStyles = ({ theme, mode }) => {
position: relative;
gap: 0.1rem;
border-radius: 0 0 ${theme.radius} ${theme.radius};
- @media (max-width: 383px) {
- display: grid;
- grid-template-columns: repeat(5, 0.2fr);
- }
+ `,
+ popOverStyles: css`
+ position: absolute;
+ bottom: 3rem;
+ left: 0;
+ width: 100%;
+ background: ${theme.colors.background};
+ box-shadow: 0 -8px 10px ${mode === 'light' ? darken(theme.colors.background, 0.1) : lighten(theme.colors.background, 1)};
+ border-radius: 8px;
+ padding: 1rem;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ z-index: 1300;
+ `,
+ popOverItemStyles: css`
+ display: flex;
+ gap: 0.5rem;
+ align-items: center;
+ cursor: pointer;
+ padding: 0.5rem;
`,
};
return styles;
@@ -101,8 +122,8 @@ export const getCommonRecorderStyles = (theme) => {
`,
controller: css`
- display: flex;
gap: 0.15rem;
+ display: inline-flex;
`,
timer: css`
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 523b9ef976..5d8c20a600 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useRef, useEffect } from 'react';
import { css } from '@emotion/react';
import {
Box,
@@ -24,6 +24,8 @@ const ChatInputFormattingToolbar = ({
optionConfig = {
surfaceItems: ['emoji', 'formatter', 'link', 'audio', 'video', 'file'],
formatters: ['bold', 'italic', 'strike', 'code', 'multiline'],
+ smallScreenSurfaceItems: ['emoji', 'video', 'audio', 'file'],
+ popOverItems: ['formatter', 'link'],
},
}) => {
const { classNames, styleOverrides, configOverrides } = useComponentOverrides(
@@ -35,18 +37,27 @@ const ChatInputFormattingToolbar = ({
configOverrides.optionConfig?.surfaceItems || optionConfig.surfaceItems;
const formatters =
configOverrides.optionConfig?.formatters || optionConfig.formatters;
-
+ const smallScreenSurfaceItems =
+ configOverrides.optionConfig?.smallScreenSurfaceItems ||
+ optionConfig.smallScreenSurfaceItems;
+ const popOverItems =
+ configOverrides.optionConfig?.popOverItems || optionConfig.popOverItems;
const isRecordingMessage = useMessageStore(
(state) => state.isRecordingMessage
);
const [isEmojiOpen, setEmojiOpen] = useState(false);
const [isInsertLinkOpen, setInsertLinkOpen] = useState(false);
+ const [isPopoverOpen, setPopoverOpen] = useState(false);
+ const popoverRef = useRef(null);
const handleClickToOpenFiles = () => {
inputRef.current.click();
};
-
+ const handleFormatterClick = (item) => {
+ formatSelection(messageRef, item.pattern);
+ setPopoverOpen(false);
+ };
const handleEmojiClick = (emojiEvent) => {
const [emoji] = emojiEvent.names;
const message = `${messageRef.current.value} :${emoji.replace(
@@ -73,77 +84,158 @@ const ChatInputFormattingToolbar = ({
};
const chatToolMap = {
- emoji: (
-
- {
if (isRecordingMessage) return;
setEmojiOpen(true);
}}
>
-
-
-
+
+ emoji
+
+ ) : (
+
+ {
+ if (isRecordingMessage) return;
+ setEmojiOpen(true);
+ }}
+ >
+
+
+
+ ),
+
+ audio: (
+
),
- audio: ,
- video: ,
- file: (
-
-
+ ),
+ file:
+ isPopoverOpen && popOverItems.includes('file') ? (
+ {
if (isRecordingMessage) return;
handleClickToOpenFiles();
}}
>
-
-
-
- ),
- link: (
-
-
+ file
+
+ ) : (
+
+ {
+ if (isRecordingMessage) return;
+ handleClickToOpenFiles();
+ }}
+ >
+
+
+
+ ),
+ link:
+ isPopoverOpen && popOverItems.includes('link') ? (
+ {
+ if (isRecordingMessage) return;
setInsertLinkOpen(true);
}}
>
-
-
-
- ),
- formatter: formatters
- .map((name) => formatter.find((item) => item.name === name))
- .map((item) => (
-
+
+ link
+
+ ) : (
+
{
if (isRecordingMessage) return;
- formatSelection(messageRef, item.pattern);
+ setInsertLinkOpen(true);
}}
>
-
+
- )),
+ ),
+ formatter: formatters
+ .map((name) => formatter.find((item) => item.name === name))
+ .map((item) =>
+ isPopoverOpen && popOverItems.includes('formatter') ? (
+ <>
+ {
+ if (isRecordingMessage) return;
+ handleFormatterClick(item);
+ }}
+ css={styles.popOverItemStyles}
+ >
+
+ {item.name}
+
+ >
+ ) : (
+
+ {
+ if (isRecordingMessage) return;
+ formatSelection(messageRef, item.pattern);
+ }}
+ >
+
+
+
+ )
+ ),
};
return (
@@ -152,8 +244,95 @@ const ChatInputFormattingToolbar = ({
className={`ec-chat-input-formatting-toolbar ${classNames}`}
style={styleOverrides}
>
- {surfaceItems.map((key) => chatToolMap[key])}
+
+ {surfaceItems.map((key) => chatToolMap[key])}
+
+ {isPopoverOpen && (
+
+ {popOverItems.map((name) => {
+ const itemInFormatter = formatter.find(
+ (item) => item.name === name
+ );
+ if (itemInFormatter) {
+ return (
+ handleFormatterClick(itemInFormatter)}
+ css={styles.popOverItemStyles}
+ >
+
+ {itemInFormatter.name}
+
+ );
+ }
+ return chatToolMap[name];
+ })}
+
+ )}
+
+ {smallScreenSurfaceItems.map((name) => {
+ const itemInFormatter = formatter.find((item) => item.name === name);
+ if (itemInFormatter) {
+ return (
+
+
+ formatSelection(messageRef, itemInFormatter.pattern)
+ }
+ >
+
+
+
+ );
+ }
+ return chatToolMap[name];
+ })}
+ {popOverItems.length > 0 && (
+
+ {
+ if (isRecordingMessage) return;
+ setPopoverOpen(!isPopoverOpen);
+ }}
+ >
+
+
+
+ )}
+
{isEmojiOpen && (
)}
diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
index eeb8c394e0..814c2093aa 100644
--- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js
+++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
@@ -13,8 +13,9 @@ import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
import useAttachmentWindowStore from '../../store/attachmentwindow';
-const VideoMessageRecorder = ({ disabled }) => {
+const VideoMessageRecorder = (props) => {
const videoRef = useRef(null);
+ const { disabled, displayName, popOverItemStyles } = props;
const { theme } = useTheme();
const styles = getCommonRecorderStyles(theme);
@@ -146,18 +147,29 @@ const VideoMessageRecorder = ({ disabled }) => {
return (
<>
- {state === 'idle' && (
-
-
-
-
-
- )}
+
+ {displayName}
+
+ ) : (
+
+
+
+
+
+ ))}
{state === 'recording' && (
<>
diff --git a/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js b/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js
index 1b6619ea95..61c5c8d05f 100644
--- a/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js
+++ b/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js
@@ -14,6 +14,11 @@ const getQuoteMessageStyles = (theme) => {
border-radius: ${theme.radius};
max-width: 100%;
box-sizing: border-box;
+
+ @media (max-width: 500px) {
+ margin: 0;
+ width: 100%;
+ }
`,
avatarContainer: css`
From 51597ed11c69467dd8d02a5f29526b66a6fde638 Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sun, 2 Feb 2025 14:03:56 +0530
Subject: [PATCH 079/153] fix: upgrade actions/upload-artifact to v4 to address
deprecation (#917)
* fix: upgrade actions/upload-artifact to v4 to address deprecation
* Update playwright.yml
---
.github/workflows/playwright.yml | 101 ++++++++++++++++---------------
1 file changed, 51 insertions(+), 50 deletions(-)
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 088f92dcdb..f6f6f20c7c 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -1,60 +1,61 @@
name: Playwright Tests
+
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
+
jobs:
test:
timeout-minutes: 60
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- - name: Checkout repository
- uses: actions/checkout@v3
-
- - name: Setup Node.js environment
- uses: actions/setup-node@v3
- with:
- node-version: 16.19.0
-
- - name: Cache dependencies
- uses: actions/cache@v2
- with:
- path: ~/.yarn
- key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
- restore-keys: |
- ${{ runner.os }}-yarn-
-
- - name: Install dependencies
- run: yarn install
-
- - name: Build the project
- run: |
- yarn build
-
- - name: Get installed Playwright version
- id: playwright-version
- run: echo "::set-output name=version::$(yarn why --json @playwright/test | grep -h 'workspace:.' | jq --raw-output '.children[].locator' | sed -e 's/@playwright\/test@.*://')"
-
- - uses: actions/cache@v3
- id: playwright-cache
- with:
- path: '~/.cache/ms-playwright'
- key: '${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}'
- restore-keys: |
- ${{ runner.os }}-playwright-
-
- - name: Install Playwright's dependencies
- if: steps.playwright-cache.outputs.cache-hit != 'true'
- run: npx playwright install --with-deps
-
- - name: Run Playwright tests
- run: cd packages/e2e-react && npx playwright test
-
- - name: Upload Playwright report
- uses: actions/upload-artifact@v3
- if: always()
- with:
- name: playwright-report
- path: packages/e2e-react/playwright-report/
- retention-days: 30
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js environment
+ uses: actions/setup-node@v4
+ with:
+ node-version: 16.19.0
+
+ - name: Cache dependencies
+ uses: actions/cache@v3
+ with:
+ path: ~/.yarn
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+
+ - name: Install dependencies
+ run: yarn install
+
+ - name: Build the project
+ run: yarn build
+
+ - name: Get installed Playwright version
+ id: playwright-version
+ run: echo "version=$(yarn why --json @playwright/test | grep -h 'workspace:.' | jq --raw-output '.children[].locator' | sed -e 's/@playwright\/test@.*://')" >> $GITHUB_OUTPUT
+
+ - uses: actions/cache@v3
+ id: playwright-cache
+ with:
+ path: '~/.cache/ms-playwright'
+ key: '${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}'
+ restore-keys: |
+ ${{ runner.os }}-playwright-
+
+ - name: Install Playwright's dependencies
+ if: steps.playwright-cache.outputs.cache-hit != 'true'
+ run: npx playwright install --with-deps
+
+ - name: Run Playwright tests
+ run: cd packages/e2e-react && npx playwright test
+
+ - name: Upload Playwright report
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: playwright-report
+ path: packages/e2e-react/playwright-report/
+ retention-days: 30
From 676253636d7a969dc2a6cc605686dad119e6218a Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sun, 9 Feb 2025 13:27:20 +0530
Subject: [PATCH 080/153] fix: Code Block Overflow and Add Backdrop for
Announcement Modal (#940)
* add wrapping
* make modal scrollable
---
packages/markups/src/elements/CodeBlock.js | 3 +++
packages/react/src/views/ChatBody/ChatBody.js | 23 +++++++++++++++++--
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/packages/markups/src/elements/CodeBlock.js b/packages/markups/src/elements/CodeBlock.js
index d2d93901ee..0aeb71d398 100644
--- a/packages/markups/src/elements/CodeBlock.js
+++ b/packages/markups/src/elements/CodeBlock.js
@@ -22,6 +22,9 @@ const CodeBlock = ({ lines }) => {
style={mode === 'dark' ? monokai : vs}
wrapLines
css={styles.codeBlock}
+ codeTagProps={{
+ style: { wordBreak: 'break-all', whiteSpace: 'pre-wrap' },
+ }}
>
{code}
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index 8d7c3ac978..4a36e2aa96 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -14,6 +14,7 @@ import {
useComponentOverrides,
Modal,
useTheme,
+ Button,
} from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
import {
@@ -316,9 +317,15 @@ const ChatBody = ({
)}
{isModalOpen && (
-
+
- Announcement
+
+ Announcement
+
{channelInfo.announcement}
+
+
+ Close
+
+
)}
Date: Sun, 9 Feb 2025 13:31:46 +0530
Subject: [PATCH 081/153] Feat: Enhanced 'Email' and 'Created At' Fields of
User Info (#786)
* Enhance Email UI and modify Created At field format
* Fixed lint error
* removed hardcoded config for email color
---
packages/react/src/lib/formatTimestampGetDate.js | 10 ++++++++++
.../src/views/UserInformation/UserInformation.js | 12 ++++++++++--
2 files changed, 20 insertions(+), 2 deletions(-)
create mode 100644 packages/react/src/lib/formatTimestampGetDate.js
diff --git a/packages/react/src/lib/formatTimestampGetDate.js b/packages/react/src/lib/formatTimestampGetDate.js
new file mode 100644
index 0000000000..856799fcf9
--- /dev/null
+++ b/packages/react/src/lib/formatTimestampGetDate.js
@@ -0,0 +1,10 @@
+const formatTimestampGetDate = (timestamp) => {
+ const date = new Date(timestamp);
+ return date.toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ });
+};
+
+export default formatTimestampGetDate;
diff --git a/packages/react/src/views/UserInformation/UserInformation.js b/packages/react/src/views/UserInformation/UserInformation.js
index 7937f2ab5e..d03232d651 100644
--- a/packages/react/src/views/UserInformation/UserInformation.js
+++ b/packages/react/src/views/UserInformation/UserInformation.js
@@ -14,6 +14,7 @@ import {
import RCContext from '../../context/RCInstance';
import { useUserStore } from '../../store';
import formatTimestamp from '../../lib/formatTimestamp';
+import formatTimestampGetDate from '../../lib/formatTimestampGetDate';
import UserInfoField from './UserInfoField';
import getUserInformationStyles from './UserInformation.styles';
import useSetExclusiveState from '../../hooks/useSetExclusiveState';
@@ -24,6 +25,7 @@ const UserInformation = () => {
const setExclusiveState = useSetExclusiveState();
const { RCInstance } = useContext(RCContext);
const { theme } = useTheme();
+ const { mode } = useTheme();
const styles = getUserInformationStyles(theme);
const [currentUserInfo, setCurrentUserInfo] = useState({});
const [isUserInfoFetched, setIsUserInfoFetched] = useState(false);
@@ -186,7 +188,13 @@ const UserInformation = () => {
{email.address}
@@ -201,7 +209,7 @@ const UserInformation = () => {
/>
Date: Sun, 9 Feb 2025 13:34:32 +0530
Subject: [PATCH 082/153] Feat: Add keyboard shortcuts for closing modal
(Escape) and submitting (Enter) in File Upload Window (#802)
* feat: Add keyboard shortcuts (Enter to submit, Escape to close) for File Upload Window
* Changed logic to EventListener
---
.../AttachmentPreview/AttachmentPreview.js | 25 ++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
index 2c007f1a71..82ce58e818 100644
--- a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
+++ b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
@@ -1,4 +1,4 @@
-import React, { useContext, useState, useRef } from 'react';
+import React, { useContext, useState, useRef, useEffect } from 'react';
import { css } from '@emotion/react';
import { Box, Icon, Button, Input, Modal } from '@embeddedchat/ui-elements';
import useAttachmentWindowStore from '../../store/attachmentwindow';
@@ -24,6 +24,7 @@ const AttachmentPreview = () => {
const [filteredMembers, setFilteredMembers] = useState([]);
const [mentionIndex, setMentionIndex] = useState(-1);
const [startReadMentionUser, setStartReadMentionUser] = useState(false);
+ const [keyPressed, setKeyPressed] = useState(null);
const [fileName, setFileName] = useState(data?.name);
@@ -65,6 +66,28 @@ const AttachmentPreview = () => {
setIsPending(false);
}
};
+
+ useEffect(() => {
+ const keyHandler = (e) => {
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ setKeyPressed('Enter');
+ }
+ };
+
+ document.addEventListener('keydown', keyHandler);
+ return () => {
+ document.removeEventListener('keydown', keyHandler);
+ };
+ }, []);
+
+ useEffect(() => {
+ if (keyPressed === 'Enter') {
+ submit();
+ setKeyPressed(null);
+ }
+ }, [keyPressed, submit]);
+
return (
From fe63e3d810eff1d416d15020ed3052b6aab0d077 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 9 Feb 2025 13:41:33 +0530
Subject: [PATCH 083/153] chore/feat: Add tooltip displaying users who reacted
with a particular emoji (#820)
* Add tooltip to reactions
* remove tagvisible prop
* update tooltipMap
---
.../src/views/EmojiReaction/EmojiReaction.js | 2 +-
.../react/src/views/Message/Message.styles.js | 16 ++++
.../src/views/Message/MessageReactions.js | 90 ++++++++++++++-----
3 files changed, 85 insertions(+), 23 deletions(-)
diff --git a/packages/react/src/views/EmojiReaction/EmojiReaction.js b/packages/react/src/views/EmojiReaction/EmojiReaction.js
index a85dfc92fc..80ba34d76e 100644
--- a/packages/react/src/views/EmojiReaction/EmojiReaction.js
+++ b/packages/react/src/views/EmojiReaction/EmojiReaction.js
@@ -7,7 +7,7 @@ import DOMPurify from 'dompurify';
const EmojiReaction = ({ body }) => {
const emojiHtml = emojione.toImage(body);
-
+ emojione.imageTitleTag = false;
return (
{
reactionMine: css`
background: ${theme.colors.secondary};
`,
+ emojiTooltip: css`
+ position: absolute;
+ bottom: 120%;
+ left: 50%;
+ transform: translateX(-40%);
+ background-color: ${theme.invertedColors.secondary};
+ color: ${theme.invertedColors.secondaryForeground};
+ z-index: ${theme.zIndex?.tooltip || 1400};
+ border-radius: ${theme.radius};
+ padding: 8px 10px;
+ width: 200px;
+ white-space: normal;
+ overflow-wrap: break-word;
+ word-break: break-word;
+ font-size: 0.85rem;
+ `,
};
return styles;
diff --git a/packages/react/src/views/Message/MessageReactions.js b/packages/react/src/views/Message/MessageReactions.js
index 5f05a684d0..39a0cc6f96 100644
--- a/packages/react/src/views/Message/MessageReactions.js
+++ b/packages/react/src/views/Message/MessageReactions.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState, useMemo } from 'react';
import {
Box,
useComponentOverrides,
@@ -24,6 +24,44 @@ export const MessageReactions = ({
);
const { theme } = useTheme();
const styles = getMessageReactionsStyles(theme);
+ const [hoveredReaction, setHoveredReaction] = useState(null);
+
+ const tooltipMap = useMemo(() => {
+ const map = {};
+ if (message.reactions) {
+ serializeReactions(message.reactions).forEach((reaction) => {
+ const usernames = reaction.usernames || [];
+ const updatedUsernames = [];
+ let isUserIncluded = false;
+
+ usernames.forEach((username) => {
+ if (username === authenticatedUserUsername) {
+ isUserIncluded = true;
+ } else {
+ updatedUsernames.push(username);
+ }
+ });
+
+ if (isUserIncluded) {
+ updatedUsernames.unshift('You');
+ }
+
+ const visibleNames = updatedUsernames.slice(0, 9);
+ const remainingCount = updatedUsernames.length - visibleNames.length;
+
+ let tooltipContent = visibleNames.join(', ');
+ if (remainingCount > 0) {
+ tooltipContent += `, and ${remainingCount} ${
+ remainingCount === 1 ? 'other' : 'others'
+ }`;
+ }
+
+ map[reaction.name] = `${tooltipContent} reacted with ${reaction.name}`;
+ });
+ }
+ return map;
+ }, [message.reactions, authenticatedUserUsername]);
+
return (
{message.reactions &&
- serializeReactions(message.reactions).map((reaction) => (
-
- handleEmojiClick(
- reaction,
- message,
- !isSameUser(reaction, authenticatedUserUsername)
- )
- }
- >
-
- {reaction.count}
-
- ))}
+ serializeReactions(message.reactions).map((reaction) => {
+ const isUserReaction = isSameUser(
+ reaction,
+ authenticatedUserUsername
+ );
+ return (
+
+ handleEmojiClick(reaction, message, !isUserReaction)
+ }
+ onMouseEnter={() => setHoveredReaction(reaction.name)}
+ onMouseLeave={() => setHoveredReaction(null)}
+ style={{ position: 'relative' }}
+ >
+
+ {reaction.count}
+ {hoveredReaction === reaction.name && (
+ {tooltipMap[reaction.name]}
+ )}
+
+ );
+ })}
);
};
From b03c0b73642811e44d150e57ccc520547b4b289d Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sun, 9 Feb 2025 13:45:45 +0530
Subject: [PATCH 084/153] feat: Add file size in attached docs and Tooltips for
downloads/collapse/title options. (#829)
* add Tooltips and size
* fix css
* fix-tooltip
* responsive
* fix videoAttachment
* css
* also fix imageAttachment
* audioAttachment
* fix
---
.../AttachmentHandler/AttachmentMetadata.js | 173 ++++++++++++++----
.../AttachmentHandler/AudioAttachment.js | 24 ++-
.../AttachmentHandler/ImageAttachment.js | 25 ++-
.../AttachmentHandler/VideoAttachment.js | 50 ++++-
4 files changed, 209 insertions(+), 63 deletions(-)
diff --git a/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js b/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
index 390cab7b71..17e25c03db 100644
--- a/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
+++ b/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
@@ -1,6 +1,6 @@
import React from 'react';
import { css } from '@emotion/react';
-import { ActionButton, Box } from '@embeddedchat/ui-elements';
+import { ActionButton, Box, Tooltip } from '@embeddedchat/ui-elements';
import { Markdown } from '../Markdown';
const AttachmentMetadata = ({
@@ -16,7 +16,6 @@ const AttachmentMetadata = ({
const response = await fetch(url);
const data = await response.blob();
const downloadUrl = URL.createObjectURL(data);
-
const anchor = document.createElement('a');
anchor.href = downloadUrl;
anchor.download = attachment.title || 'download';
@@ -36,6 +35,10 @@ const AttachmentMetadata = ({
css`
display: flex;
flex-direction: column;
+ @media (max-width: 420px) {
+ flex-direction: column;
+ align-items: flex-start;
+ }
`,
variantStyles.attachmentMetaContainer,
]}
@@ -46,10 +49,16 @@ const AttachmentMetadata = ({
? [
css`
margin: 10px 0px;
+ @media (max-width: 420px) {
+ margin: 5px 0px;
+ }
`,
]
: css`
margin: -7px 0px;
+ @media (max-width: 420px) {
+ margin: -5px 0px;
+ }
`
}
>
@@ -64,47 +73,137 @@ const AttachmentMetadata = ({
display: flex;
flex-direction: row;
align-items: center;
+ @media (max-width: 420px) {
+ flex-direction: column;
+ align-items: flex-start;
+ }
`}
>
-
- {attachment.title}
-
-
-
+
+
+ {attachment.title.length > 22
+ ? `${attachment.title.substring(0, 22)}...`
+ : attachment.title}
+
+
+
+ (
+ {attachment.image_size
+ ? (attachment.image_size / 1024).toFixed(2)
+ : 0}{' '}
+ kB)
+
+
+
+ >
+
+
+ {
+ onExpandCollapseClick();
+ }}
+ />
+
+
+
+
+
+
+
+
);
diff --git a/packages/react/src/views/AttachmentHandler/AudioAttachment.js b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
index 5caf16e760..867792b4f7 100644
--- a/packages/react/src/views/AttachmentHandler/AudioAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
@@ -67,14 +67,22 @@ const AudioAttachment = ({
) : (
''
)}
-
+
+
+
{isExpanded && (
+
+
+
{isExpanded && (
setShowGallery(true)}>
- @{authorName}
+
+ @{authorName}
+
>
) : (
''
)}
-
+
+
+
{isExpanded && (
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.styles.js b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
index 5925297dcf..b77233120a 100644
--- a/packages/react/src/views/RoomInformation/RoomInformation.styles.js
+++ b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
@@ -1,6 +1,6 @@
import { css } from '@emotion/react';
-const getRoomInformationStyles = () => {
+const getRoomInformationStyles = (theme, mode) => {
const styles = {
infoContainer: css`
margin: 16px;
@@ -19,6 +19,22 @@ const getRoomInformationStyles = () => {
opacity: 0.7;
font-size: 0.9rem;
`,
+
+ archivedRoomInfo: css`
+ display: flex;
+ border: 1px solid
+ ${mode === 'light'
+ ? theme.colors.warning
+ : theme.colors.warningForeground};
+ border-radius: ${theme.radius};
+ padding: 0.75rem 1rem;
+ width: 100%;
+ gap: 0.75rem;
+ margin-bottom: 1rem;
+ `,
+ archivedText: css`
+ font-size: 1rem;
+ `,
};
return styles;
From ebd921feb3eb4ee1b2ea0a1d73aafc263b37eddf Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sat, 24 May 2025 12:20:44 +0530
Subject: [PATCH 098/153] Added Support for displaying the timestamp messages
(#990)
---
.../markups/src/elements/InlineElements.js | 5 +
.../markups/src/elements/TimestampElement.js | 118 ++++++++++++++++++
2 files changed, 123 insertions(+)
create mode 100644 packages/markups/src/elements/TimestampElement.js
diff --git a/packages/markups/src/elements/InlineElements.js b/packages/markups/src/elements/InlineElements.js
index 0ab5a7fb1e..2584196e89 100644
--- a/packages/markups/src/elements/InlineElements.js
+++ b/packages/markups/src/elements/InlineElements.js
@@ -10,6 +10,7 @@ import ChannelMention from '../mentions/ChannelMention';
import ColorElement from './ColorElement';
import LinkSpan from './LinkSpan';
import UserMention from '../mentions/UserMention';
+import TimestampElement from './TimestampElement';
const InlineElements = ({ contents }) =>
contents.map((content, index) => {
@@ -53,6 +54,10 @@ const InlineElements = ({ contents }) =>
}
/>
);
+
+ case 'TIMESTAMP':
+ return
;
+
default:
return null;
}
diff --git a/packages/markups/src/elements/TimestampElement.js b/packages/markups/src/elements/TimestampElement.js
new file mode 100644
index 0000000000..fd860046d7
--- /dev/null
+++ b/packages/markups/src/elements/TimestampElement.js
@@ -0,0 +1,118 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import CodeElement from './CodeElement';
+
+function timeAgo(dateParam, locale) {
+ const int = new Intl.RelativeTimeFormat(locale, { style: 'long' });
+
+ const date = new Date(dateParam).getTime();
+ const today = new Date().getTime();
+ const seconds = Math.round((date - today) / 1000);
+ const minutes = Math.round(seconds / 60);
+ const hours = Math.round(minutes / 60);
+ const days = Math.round(hours / 24);
+ const weeks = Math.round(days / 7);
+ const months = new Date(date).getMonth() - new Date().getMonth();
+ const years = new Date(date).getFullYear() - new Date().getFullYear();
+
+ if (Math.abs(seconds) < 60) {
+ return int.format(seconds, 'seconds');
+ }
+ if (Math.abs(minutes) < 60) {
+ return int.format(minutes, 'minutes');
+ }
+ if (Math.abs(hours) < 24) {
+ return int.format(hours, 'hours');
+ }
+ if (Math.abs(days) < 7) {
+ return int.format(days, 'days');
+ }
+ if (Math.abs(weeks) < 4) {
+ return int.format(weeks, 'weeks');
+ }
+ if (Math.abs(months) < 12) {
+ return int.format(months, 'months');
+ }
+ return int.format(years, 'years');
+}
+
+const formatTimestamp = (timestamp, format) => {
+ const date = new Date(timestamp * 1000);
+
+ const getOrdinalDate = (day) => {
+ const suffix = ['th', 'st', 'nd', 'rd'];
+ const val = day % 100;
+ return day + (suffix[(val - 20) % 10] || suffix[val] || suffix[0]);
+ };
+
+ const timeZoneOffset = date.getTimezoneOffset();
+ const sign = timeZoneOffset > 0 ? '-' : '+';
+ const hours = Math.floor(Math.abs(timeZoneOffset) / 60);
+ const minutes = Math.abs(timeZoneOffset) % 60;
+ const timeZone = `GMT${sign}${String(hours).padStart(2, '0')}:${String(
+ minutes
+ ).padStart(2, '0')}`;
+
+ const month = date.toLocaleString('en-US', { month: 'long' });
+ const day = getOrdinalDate(date.getDate());
+ const year = date.getFullYear();
+ const time = date.toLocaleString([], {
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ });
+
+ const shortDate = date.toLocaleDateString('en-US');
+ const shortTime = date.toLocaleTimeString([], {
+ hour: '2-digit',
+ minute: '2-digit',
+ });
+
+ switch (format) {
+ case 't': {
+ return shortTime;
+ }
+ case 'T': {
+ return time;
+ }
+ case 'd': {
+ return shortDate;
+ }
+ case 'D': {
+ return `${shortDate}, ${shortTime}`;
+ }
+ case 'f': {
+ return `${month} ${day}, ${year} at ${time} ${timeZone}`;
+ }
+ case 'F': {
+ const weekday = date.toLocaleString('en-US', { weekday: 'long' });
+ return `${weekday}, ${month} ${day} ${year} at ${time} ${timeZone}`;
+ }
+ case 'R': {
+ return timeAgo(timestamp * 1000, 'en');
+ }
+ default: {
+ return date.toLocaleString();
+ }
+ }
+};
+
+const TimestampElement = ({ contents }) => {
+ if (typeof contents === 'object' && contents.timestamp && contents.format) {
+ const { timestamp, format } = contents;
+
+ const formattedTimestamp = formatTimestamp(parseInt(timestamp, 10), format);
+ return
;
+ }
+
+ return null;
+};
+
+export default TimestampElement;
+
+TimestampElement.propTypes = {
+ contents: PropTypes.shape({
+ timestamp: PropTypes.string.isRequired,
+ format: PropTypes.string.isRequired,
+ }).isRequired,
+};
From 58d672e9285e43fa398e602b49f8ee6554fd47cf Mon Sep 17 00:00:00 2001
From: KrishnaShuk
Date: Sat, 24 May 2025 12:32:15 +0530
Subject: [PATCH 099/153] Fix: Alt + Arrow Key Shortcuts Not Functioning in
Message Navigation (#991)
* Fixed functionality of alt + left/right/up/down keys
* Apply Prettier formatting to ChatInput.js to pass lint test
* made changes for lint test
---
.../react/src/views/ChatInput/ChatInput.js | 48 ++++++++++++++++---
1 file changed, 42 insertions(+), 6 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index c7d41f2059..ca748520a6 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -449,21 +449,57 @@ const ChatInput = ({ scrollToBottom }) => {
sendMessage();
}
break;
- case e.altKey && (e.code === 'ArrowUp' || 'ArrowRight'): {
+ case (e.ctrlKey || e.altKey) && e.code === 'ArrowLeft': {
+ e.preventDefault();
+ if (messageRef && messageRef.current) {
+ const { value, selectionStart } = messageRef.current;
+ let newPosition = selectionStart;
+
+ while (newPosition > 0 && /\s/.test(value[newPosition - 1])) {
+ newPosition -= 1;
+ }
+ while (newPosition > 0 && !/\s/.test(value[newPosition - 1])) {
+ newPosition -= 1;
+ }
+
+ messageRef.current.setSelectionRange(newPosition, newPosition);
+ messageRef.current.focus();
+ }
+ break;
+ }
+ case (e.ctrlKey || e.altKey) && e.code === 'ArrowRight': {
+ e.preventDefault();
+ if (messageRef && messageRef.current) {
+ const { value, selectionEnd } = messageRef.current;
+ let newPosition = selectionEnd;
+
+ while (newPosition < value.length && /\s/.test(value[newPosition])) {
+ newPosition += 1;
+ }
+ while (newPosition < value.length && !/\s/.test(value[newPosition])) {
+ newPosition += 1;
+ }
+
+ messageRef.current.setSelectionRange(newPosition, newPosition);
+ messageRef.current.focus();
+ }
+ break;
+ }
+ case (e.ctrlKey || e.altKey) && e.code === 'ArrowUp': {
e.preventDefault();
- e.stopPropagation();
if (messageRef && messageRef.current) {
messageRef.current.setSelectionRange(0, 0);
messageRef.current.focus();
}
break;
}
- case e.altKey && (e.code === 'ArrowDown' || 'ArrowLeft'): {
+ case (e.ctrlKey || e.altKey) && e.code === 'ArrowDown': {
e.preventDefault();
- e.stopPropagation();
if (messageRef && messageRef.current) {
- const endlength = messageRef.current.value.length;
- messageRef.current.setSelectionRange(endlength, endlength);
+ const { current } = messageRef;
+ const { value } = current;
+ const { length } = value;
+ messageRef.current.setSelectionRange(length, length);
messageRef.current.focus();
}
break;
From 63c2360a2b65a8c00a8db97963fc885ccbba28ad Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sat, 24 May 2025 12:36:50 +0530
Subject: [PATCH 100/153] Feat: Add color to link messages & link in link
preview based on light and dark theme (#912)
---
packages/markups/src/elements/LinkSpan.js | 26 +++++++++++++++++--
.../src/views/LinkPreview/LinkPreview.js | 20 +++++++++-----
2 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/packages/markups/src/elements/LinkSpan.js b/packages/markups/src/elements/LinkSpan.js
index b1257f98de..319d180130 100644
--- a/packages/markups/src/elements/LinkSpan.js
+++ b/packages/markups/src/elements/LinkSpan.js
@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
+import { useTheme } from '@embeddedchat/ui-elements';
import PlainSpan from './PlainSpan';
import StrikeSpan from './StrikeSpan';
import ItalicSpan from './ItalicSpan';
@@ -27,6 +28,9 @@ const getBaseURI = () => {
const isExternal = (href) => href.indexOf(getBaseURI()) !== 0;
const LinkSpan = ({ href, label }) => {
+ const { theme } = useTheme();
+ const { mode } = useTheme();
+
const contents = React.useMemo(() => {
const labelArray = Array.isArray(label) ? label : [label];
@@ -54,13 +58,31 @@ const LinkSpan = ({ href, label }) => {
if (isExternal(href)) {
return (
-
+
{contents}
);
}
return (
-
+
{contents}
);
diff --git a/packages/react/src/views/LinkPreview/LinkPreview.js b/packages/react/src/views/LinkPreview/LinkPreview.js
index 7290714edc..62ae860001 100644
--- a/packages/react/src/views/LinkPreview/LinkPreview.js
+++ b/packages/react/src/views/LinkPreview/LinkPreview.js
@@ -1,6 +1,5 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
-import { css } from '@emotion/react';
import {
Box,
ActionButton,
@@ -20,6 +19,7 @@ const LinkPreview = ({
}) => {
const { classNames, styleOverrides } = useComponentOverrides('LinkPreview');
const { theme } = useTheme();
+ const { mode } = useTheme();
const styles = getLinkPreviewStyles(theme);
const [isPreviewOpen, setIsPreviewOpen] = useState(true);
@@ -88,9 +88,12 @@ const LinkPreview = ({
@@ -100,9 +103,12 @@ const LinkPreview = ({
{isSiteName && (
From d14c1743caf450e6d0224b8c697155a482ed53bb Mon Sep 17 00:00:00 2001
From: Piyush Bhatt <157290995+thepiyush-303@users.noreply.github.com>
Date: Sat, 24 May 2025 16:56:13 +0530
Subject: [PATCH 101/153] feat: Add a Preview Feature to check the text after
formatting it. (#889)
* fix
* add_css
* fix
* add_marked_package
* formatText
* Update QuoteMessage.js
* fic
* resolve conflicts
* add disable
* fix
---
package.json | 3 +-
packages/react/src/store/messageStore.js | 9 +++
.../react/src/views/ChatInput/ChatInput.js | 10 ++++
.../ChatInput/ChatInputFormattingToolbar.js | 55 ++++++++++++++++++-
.../views/PreviewMessage/PreviewMessage.js | 48 ++++++++++++++++
.../PreviewMessage/PreviewMessage.styles.js | 43 +++++++++++++++
yarn.lock | 10 ++++
7 files changed, 174 insertions(+), 4 deletions(-)
create mode 100644 packages/react/src/views/PreviewMessage/PreviewMessage.js
create mode 100644 packages/react/src/views/PreviewMessage/PreviewMessage.styles.js
diff --git a/package.json b/package.json
index 3868bafb9c..d4980db375 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"typescript": "^5.1.3"
},
"dependencies": {
- "dompurify": "^3.1.6"
+ "dompurify": "^3.1.6",
+ "marked": "latest"
}
}
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index c359a0c8eb..58368594dd 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -10,6 +10,7 @@ const useMessageStore = create((set, get) => ({
editMessage: {},
messagesOffset: 0,
quoteMessage: [],
+ previewMessage: [],
deleteMessageRoles: {},
deleteOwnMessageRoles: {},
forceDeleteMessageRoles: {},
@@ -100,6 +101,14 @@ const useMessageStore = create((set, get) => ({
})),
clearQuoteMessages: () => set({ quoteMessage: [] }),
+ addPreviewMessage: (previewMessage) =>
+ set((state) => ({
+ previewMessage: [...state.previewMessage, previewMessage],
+ })),
+ removePreviewMessage: (previewMessage) =>
+ set((state) => ({
+ previewMessage: state.previewMessage.filter((i) => i !== previewMessage),
+ })),
setMessageToReport: (messageId) =>
set(() => ({ messageToReport: messageId })),
toggleShowReportMessage: () => {
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index ca748520a6..7d3aa0c9c2 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -34,6 +34,7 @@ import useShowCommands from '../../hooks/useShowCommands';
import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import formatSelection from '../../lib/formatSelection';
import { parseEmoji } from '../../lib/emoji';
+import PreviewMessage from '../PreviewMessage/PreviewMessage';
const ChatInput = ({ scrollToBottom }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
@@ -97,6 +98,7 @@ const ChatInput = ({ scrollToBottom }) => {
editMessage,
setEditMessage,
quoteMessage,
+ previewMessage,
isRecordingMessage,
upsertMessage,
replaceMessage,
@@ -106,6 +108,7 @@ const ChatInput = ({ scrollToBottom }) => {
editMessage: state.editMessage,
setEditMessage: state.setEditMessage,
quoteMessage: state.quoteMessage,
+ previewMessage: state.previewMessage,
isRecordingMessage: state.isRecordingMessage,
upsertMessage: state.upsertMessage,
replaceMessage: state.replaceMessage,
@@ -519,6 +522,13 @@ const ChatInput = ({ scrollToBottom }) => {
))}
+
+ {previewMessage &&
+ previewMessage.length > 0 &&
+ previewMessage.map((message, index) => (
+
+ ))}
+
{editMessage.msg || editMessage.attachments || isChannelReadOnly ? (
state.isRecordingMessage
);
+ const addPreviewMessage = useMessageStore((state) => state.addPreviewMessage);
+ const previewMessage = useMessageStore((state) => state.previewMessage);
+ const removePreviewMessage = useMessageStore(
+ (state) => state.removePreviewMessage
+ );
+
const [isEmojiOpen, setEmojiOpen] = useState(false);
const [isInsertLinkOpen, setInsertLinkOpen] = useState(false);
const [isPopoverOpen, setPopoverOpen] = useState(false);
@@ -144,7 +158,7 @@ const ChatInputFormattingToolbar = ({
}}
>
- file
+ File
) : (
@@ -173,7 +187,7 @@ const ChatInputFormattingToolbar = ({
}}
>
- link
+ Link
) : (
@@ -190,6 +204,41 @@ const ChatInputFormattingToolbar = ({
),
+ preview:
+ isPopoverOpen && popOverItems.includes('preview') ? (
+ {
+ if (isRecordingMessage || !messageRef.current?.value) return;
+ if (previewMessage) {
+ removePreviewMessage(previewMessage[0]);
+ }
+ addPreviewMessage(messageRef.current.value);
+ }}
+ >
+
+ Preview
+
+ ) : (
+
+ {
+ if (isRecordingMessage || !messageRef.current?.value) return;
+ if (previewMessage) {
+ removePreviewMessage(previewMessage[0]);
+ }
+ addPreviewMessage(messageRef.current.value);
+ }}
+ >
+
+
+
+ ),
formatter: formatters
.map((name) => formatter.find((item) => item.name === name))
.map((item) =>
diff --git a/packages/react/src/views/PreviewMessage/PreviewMessage.js b/packages/react/src/views/PreviewMessage/PreviewMessage.js
new file mode 100644
index 0000000000..293e0b83aa
--- /dev/null
+++ b/packages/react/src/views/PreviewMessage/PreviewMessage.js
@@ -0,0 +1,48 @@
+import React from 'react';
+import {
+ useComponentOverrides,
+ useTheme,
+ Box,
+ ActionButton,
+ Icon,
+} from '@embeddedchat/ui-elements';
+import { marked } from 'marked';
+import Dompurify from 'dompurify';
+import getPreviewMessageStyles from './PreviewMessage.styles';
+import { useMessageStore } from '../../store';
+
+const PreviewMessage = ({ className = '', style = {}, message }) => {
+ const { theme } = useTheme();
+ const styles = getPreviewMessageStyles(theme);
+ const { classNames, styleOverrides } = useComponentOverrides('QuoteMessage');
+ const removePreviewMessage = useMessageStore(
+ (state) => state.removePreviewMessage
+ );
+
+ const formatMessage = () => {
+ const markedText = marked.parse(message);
+ const sanitizedText = Dompurify.sanitize(markedText);
+ return ;
+ };
+
+ return (
+
+
+ removePreviewMessage(message)}
+ size="small"
+ >
+
+
+
+ {formatMessage()}
+
+ );
+};
+
+export default PreviewMessage;
diff --git a/packages/react/src/views/PreviewMessage/PreviewMessage.styles.js b/packages/react/src/views/PreviewMessage/PreviewMessage.styles.js
new file mode 100644
index 0000000000..6e678cf4a5
--- /dev/null
+++ b/packages/react/src/views/PreviewMessage/PreviewMessage.styles.js
@@ -0,0 +1,43 @@
+import { css } from '@emotion/react';
+
+const getPreviewMessageStyles = (theme) => {
+ const styles = {
+ messageContainer: css`
+ margin: 0.2rem 2rem;
+ position: relative;
+ font-size: 0.85rem;
+ background-color: ${theme.colors.background};
+ color: ${theme.colors.foreground};
+ padding: 0.5rem;
+ z-index: 1200;
+ border: 1px solid ${theme.colors.border};
+ border-radius: ${theme.radius};
+ max-width: 100%;
+ box-sizing: border-box;
+ `,
+
+ avatarContainer: css`
+ padding: 0.25rem;
+ display: flex;
+ gap: 0.5rem;
+ `,
+
+ message: css`
+ padding: 0.25rem;
+ overflow-wrap: break-word;
+ word-break: break-word;
+ white-space: normal;
+ width: 100%;
+ `,
+
+ actionBtn: css`
+ position: absolute;
+ top: 0.75rem;
+ right: 0.75rem;
+ `,
+ };
+
+ return styles;
+};
+
+export default getPreviewMessageStyles;
diff --git a/yarn.lock b/yarn.lock
index d3dec11bea..2b3d729442 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -15208,6 +15208,7 @@ __metadata:
esbuild: ^0.17.19
husky: ^9.0.11
lerna: ^6.6.2
+ marked: latest
typescript: ^5.1.3
languageName: unknown
linkType: soft
@@ -22445,6 +22446,15 @@ __metadata:
languageName: node
linkType: hard
+"marked@npm:latest":
+ version: 15.0.6
+ resolution: "marked@npm:15.0.6"
+ bin:
+ marked: bin/marked.js
+ checksum: 5218363ac4f6cd1893318ad8b1efacdc8a416f87da28cbcffb419d97602168935249351a3fbe2c59221e7e9955862c6a038ec00f19bf4a6d7e8e0e2e9643d154
+ languageName: node
+ linkType: hard
+
"material-colors@npm:^1.2.1":
version: 1.2.6
resolution: "material-colors@npm:1.2.6"
From 51f18028250fb1cfb60def01df86916320640ef2 Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sat, 24 May 2025 16:58:12 +0530
Subject: [PATCH 102/153] =?UTF-8?q?Revert=20"feat:=20Add=20a=20Preview=20F?=
=?UTF-8?q?eature=20to=20check=20the=20text=20after=20formatting=20it.=20(?=
=?UTF-8?q?#=E2=80=A6"=20(#1002)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit d14c1743caf450e6d0224b8c697155a482ed53bb.
---
package.json | 3 +-
packages/react/src/store/messageStore.js | 9 ---
.../react/src/views/ChatInput/ChatInput.js | 10 ----
.../ChatInput/ChatInputFormattingToolbar.js | 55 +------------------
.../views/PreviewMessage/PreviewMessage.js | 48 ----------------
.../PreviewMessage/PreviewMessage.styles.js | 43 ---------------
yarn.lock | 10 ----
7 files changed, 4 insertions(+), 174 deletions(-)
delete mode 100644 packages/react/src/views/PreviewMessage/PreviewMessage.js
delete mode 100644 packages/react/src/views/PreviewMessage/PreviewMessage.styles.js
diff --git a/package.json b/package.json
index d4980db375..3868bafb9c 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,6 @@
"typescript": "^5.1.3"
},
"dependencies": {
- "dompurify": "^3.1.6",
- "marked": "latest"
+ "dompurify": "^3.1.6"
}
}
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index 58368594dd..c359a0c8eb 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -10,7 +10,6 @@ const useMessageStore = create((set, get) => ({
editMessage: {},
messagesOffset: 0,
quoteMessage: [],
- previewMessage: [],
deleteMessageRoles: {},
deleteOwnMessageRoles: {},
forceDeleteMessageRoles: {},
@@ -101,14 +100,6 @@ const useMessageStore = create((set, get) => ({
})),
clearQuoteMessages: () => set({ quoteMessage: [] }),
- addPreviewMessage: (previewMessage) =>
- set((state) => ({
- previewMessage: [...state.previewMessage, previewMessage],
- })),
- removePreviewMessage: (previewMessage) =>
- set((state) => ({
- previewMessage: state.previewMessage.filter((i) => i !== previewMessage),
- })),
setMessageToReport: (messageId) =>
set(() => ({ messageToReport: messageId })),
toggleShowReportMessage: () => {
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 7d3aa0c9c2..ca748520a6 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -34,7 +34,6 @@ import useShowCommands from '../../hooks/useShowCommands';
import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import formatSelection from '../../lib/formatSelection';
import { parseEmoji } from '../../lib/emoji';
-import PreviewMessage from '../PreviewMessage/PreviewMessage';
const ChatInput = ({ scrollToBottom }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
@@ -98,7 +97,6 @@ const ChatInput = ({ scrollToBottom }) => {
editMessage,
setEditMessage,
quoteMessage,
- previewMessage,
isRecordingMessage,
upsertMessage,
replaceMessage,
@@ -108,7 +106,6 @@ const ChatInput = ({ scrollToBottom }) => {
editMessage: state.editMessage,
setEditMessage: state.setEditMessage,
quoteMessage: state.quoteMessage,
- previewMessage: state.previewMessage,
isRecordingMessage: state.isRecordingMessage,
upsertMessage: state.upsertMessage,
replaceMessage: state.replaceMessage,
@@ -522,13 +519,6 @@ const ChatInput = ({ scrollToBottom }) => {
))}
-
- {previewMessage &&
- previewMessage.length > 0 &&
- previewMessage.map((message, index) => (
-
- ))}
-
{editMessage.msg || editMessage.attachments || isChannelReadOnly ? (
state.isRecordingMessage
);
- const addPreviewMessage = useMessageStore((state) => state.addPreviewMessage);
- const previewMessage = useMessageStore((state) => state.previewMessage);
- const removePreviewMessage = useMessageStore(
- (state) => state.removePreviewMessage
- );
-
const [isEmojiOpen, setEmojiOpen] = useState(false);
const [isInsertLinkOpen, setInsertLinkOpen] = useState(false);
const [isPopoverOpen, setPopoverOpen] = useState(false);
@@ -158,7 +144,7 @@ const ChatInputFormattingToolbar = ({
}}
>
- File
+ file
) : (
@@ -187,7 +173,7 @@ const ChatInputFormattingToolbar = ({
}}
>
- Link
+ link
) : (
@@ -204,41 +190,6 @@ const ChatInputFormattingToolbar = ({
),
- preview:
- isPopoverOpen && popOverItems.includes('preview') ? (
- {
- if (isRecordingMessage || !messageRef.current?.value) return;
- if (previewMessage) {
- removePreviewMessage(previewMessage[0]);
- }
- addPreviewMessage(messageRef.current.value);
- }}
- >
-
- Preview
-
- ) : (
-
- {
- if (isRecordingMessage || !messageRef.current?.value) return;
- if (previewMessage) {
- removePreviewMessage(previewMessage[0]);
- }
- addPreviewMessage(messageRef.current.value);
- }}
- >
-
-
-
- ),
formatter: formatters
.map((name) => formatter.find((item) => item.name === name))
.map((item) =>
diff --git a/packages/react/src/views/PreviewMessage/PreviewMessage.js b/packages/react/src/views/PreviewMessage/PreviewMessage.js
deleted file mode 100644
index 293e0b83aa..0000000000
--- a/packages/react/src/views/PreviewMessage/PreviewMessage.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-import {
- useComponentOverrides,
- useTheme,
- Box,
- ActionButton,
- Icon,
-} from '@embeddedchat/ui-elements';
-import { marked } from 'marked';
-import Dompurify from 'dompurify';
-import getPreviewMessageStyles from './PreviewMessage.styles';
-import { useMessageStore } from '../../store';
-
-const PreviewMessage = ({ className = '', style = {}, message }) => {
- const { theme } = useTheme();
- const styles = getPreviewMessageStyles(theme);
- const { classNames, styleOverrides } = useComponentOverrides('QuoteMessage');
- const removePreviewMessage = useMessageStore(
- (state) => state.removePreviewMessage
- );
-
- const formatMessage = () => {
- const markedText = marked.parse(message);
- const sanitizedText = Dompurify.sanitize(markedText);
- return ;
- };
-
- return (
-
-
- removePreviewMessage(message)}
- size="small"
- >
-
-
-
- {formatMessage()}
-
- );
-};
-
-export default PreviewMessage;
diff --git a/packages/react/src/views/PreviewMessage/PreviewMessage.styles.js b/packages/react/src/views/PreviewMessage/PreviewMessage.styles.js
deleted file mode 100644
index 6e678cf4a5..0000000000
--- a/packages/react/src/views/PreviewMessage/PreviewMessage.styles.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { css } from '@emotion/react';
-
-const getPreviewMessageStyles = (theme) => {
- const styles = {
- messageContainer: css`
- margin: 0.2rem 2rem;
- position: relative;
- font-size: 0.85rem;
- background-color: ${theme.colors.background};
- color: ${theme.colors.foreground};
- padding: 0.5rem;
- z-index: 1200;
- border: 1px solid ${theme.colors.border};
- border-radius: ${theme.radius};
- max-width: 100%;
- box-sizing: border-box;
- `,
-
- avatarContainer: css`
- padding: 0.25rem;
- display: flex;
- gap: 0.5rem;
- `,
-
- message: css`
- padding: 0.25rem;
- overflow-wrap: break-word;
- word-break: break-word;
- white-space: normal;
- width: 100%;
- `,
-
- actionBtn: css`
- position: absolute;
- top: 0.75rem;
- right: 0.75rem;
- `,
- };
-
- return styles;
-};
-
-export default getPreviewMessageStyles;
diff --git a/yarn.lock b/yarn.lock
index 2b3d729442..d3dec11bea 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -15208,7 +15208,6 @@ __metadata:
esbuild: ^0.17.19
husky: ^9.0.11
lerna: ^6.6.2
- marked: latest
typescript: ^5.1.3
languageName: unknown
linkType: soft
@@ -22446,15 +22445,6 @@ __metadata:
languageName: node
linkType: hard
-"marked@npm:latest":
- version: 15.0.6
- resolution: "marked@npm:15.0.6"
- bin:
- marked: bin/marked.js
- checksum: 5218363ac4f6cd1893318ad8b1efacdc8a416f87da28cbcffb419d97602168935249351a3fbe2c59221e7e9955862c6a038ec00f19bf4a6d7e8e0e2e9643d154
- languageName: node
- linkType: hard
-
"material-colors@npm:^1.2.1":
version: 1.2.6
resolution: "material-colors@npm:1.2.6"
From 7d0fe432a300f8af0495f55e09ed89ec5d0280be Mon Sep 17 00:00:00 2001
From: Piyush Bhatt <157290995+thepiyush-303@users.noreply.github.com>
Date: Sat, 24 May 2025 16:59:42 +0530
Subject: [PATCH 103/153] feat: Enhance Message Report modal and fix the logic
of visibility of report option in toolbar (#907)
* initial fix
* fix_css
* add scroller
* format
---------
Co-authored-by: Zishan Ahmad
---
.../react/src/views/Message/MessageToolbox.js | 4 +-
.../src/views/MessageList/MessageList.js | 7 +-
.../ReportMessage/MessageReportWindow.js | 19 +++-
.../ReportMessage/ReportMessage.styles.js | 1 +
.../ReportMessage/ReportWindowButtons.js | 101 ++++++++++++++----
5 files changed, 107 insertions(+), 25 deletions(-)
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 0749eed697..75bdc7467d 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -83,6 +83,8 @@ export const MessageToolbox = ({
const isAllowedToPin = userRoles.some((role) => pinRoles.has(role));
+ const isAllowedToReport = message.u._id !== authenticatedUserId;
+
const isAllowedToEditMessage = userRoles.some((role) =>
editMessageRoles.has(role)
)
@@ -192,7 +194,7 @@ export const MessageToolbox = ({
id: 'report',
onClick: () => handlerReportMessage(message),
iconName: 'report',
- visible: true,
+ visible: isAllowedToReport,
type: 'destructive',
},
}),
diff --git a/packages/react/src/views/MessageList/MessageList.js b/packages/react/src/views/MessageList/MessageList.js
index ede0a694bf..80379eb1a1 100644
--- a/packages/react/src/views/MessageList/MessageList.js
+++ b/packages/react/src/views/MessageList/MessageList.js
@@ -26,6 +26,8 @@ const MessageList = ({
const filteredMessages = messages.filter((msg) => !msg.tmid);
+ const reportedMessage = messages.find((msg) => msg._id === messageToReport);
+
return (
<>
{filteredMessages.length === 0 ? (
@@ -98,7 +100,10 @@ const MessageList = ({
);
})}
{showReportMessage && (
-
+
)}
>
)}
diff --git a/packages/react/src/views/ReportMessage/MessageReportWindow.js b/packages/react/src/views/ReportMessage/MessageReportWindow.js
index 33957e72ea..2383682c22 100644
--- a/packages/react/src/views/ReportMessage/MessageReportWindow.js
+++ b/packages/react/src/views/ReportMessage/MessageReportWindow.js
@@ -1,11 +1,12 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
-import { Box, Input } from '@embeddedchat/ui-elements';
+import { Box, Input, useTheme } from '@embeddedchat/ui-elements';
+import { css } from '@emotion/react';
import ReportWindowButtons from './ReportWindowButtons';
import styles from './ReportMessage.styles';
-const MessageReportWindow = ({ messageId }) => {
- const [reportDescription, setDescription] = useState('');
+const MessageReportWindow = ({ messageId, message }) => {
+ const [reportDescription, setDescription] = useState(' ');
return (
{
cancelText="Cancel"
reportDescription={reportDescription}
messageId={messageId}
+ message={message}
>
{
setDescription(e.target.value);
}}
/>
+ {reportDescription === '' ? (
+
+ You need to write something!
+
+ ) : null}
);
diff --git a/packages/react/src/views/ReportMessage/ReportMessage.styles.js b/packages/react/src/views/ReportMessage/ReportMessage.styles.js
index 112fd95bfe..c96e159164 100644
--- a/packages/react/src/views/ReportMessage/ReportMessage.styles.js
+++ b/packages/react/src/views/ReportMessage/ReportMessage.styles.js
@@ -4,6 +4,7 @@ const styles = {
conatiner: css`
display: flex;
justify-content: center;
+ flex-direction: column;
margin-bottom: 0.125rem;
padding: 0.6rem 0.4rem;
`,
diff --git a/packages/react/src/views/ReportMessage/ReportWindowButtons.js b/packages/react/src/views/ReportMessage/ReportWindowButtons.js
index 5763fc87bc..9dcdd4df1f 100644
--- a/packages/react/src/views/ReportMessage/ReportWindowButtons.js
+++ b/packages/react/src/views/ReportMessage/ReportWindowButtons.js
@@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import {
+ Box,
Button,
Icon,
Modal,
@@ -9,8 +10,16 @@ import {
} from '@embeddedchat/ui-elements';
import { useMessageStore } from '../../store';
import RCContext from '../../context/RCInstance';
+import { Markdown } from '../Markdown';
-const ReportWindowButtons = ({ children, reportDescription, messageId }) => {
+const ReportWindowButtons = ({
+ children,
+ reportDescription,
+ messageId,
+ confirmText,
+ cancelText,
+ message,
+}) => {
const [toggleReportMessage, setMessageToReport] = useMessageStore((state) => [
state.toggleShowReportMessage,
state.setMessageToReport,
@@ -41,30 +50,82 @@ const ReportWindowButtons = ({ children, reportDescription, messageId }) => {
handleOnClose();
};
+ const messageDescription = (msg) => {
+ if (msg.file) {
+ if (msg.attachments[0]?.description) {
+ return (
+
+ );
+ }
+ return msg.file.name;
+ }
+ return ;
+ };
+
return (
-
-
- Report this message?
-
+
+
+
+ Report this message?
+
+
- {children}
-
-
- Cancel
-
-
- Report message
-
-
+
+
+
+ {messageDescription(message)}
+
+ {children}
+
+
+
+
+
+ {cancelText}
+
+
+ {confirmText}
+
+
+
);
};
From 710305e49903cf3b61150532ba04005a04b00b76 Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sat, 31 May 2025 14:03:07 +0530
Subject: [PATCH 104/153] fixed blog broken links
---
packages/docs/blog/EmbeddedChat-2024.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/packages/docs/blog/EmbeddedChat-2024.md b/packages/docs/blog/EmbeddedChat-2024.md
index 6827d5940b..2d65e99fb0 100644
--- a/packages/docs/blog/EmbeddedChat-2024.md
+++ b/packages/docs/blog/EmbeddedChat-2024.md
@@ -89,7 +89,7 @@ A demonstration video is available here:
-For further details on theming, you can visit the [documentation](https://github.com/RocketChat/EmbeddedChat/blob/develop/packages/docs/theming.md) or check out the [technical guide](https://github.com/RocketChat/EmbeddedChat/blob/develop/packages/docs/theming_technical.md) for insights on how theming is implemented in the repository.
+For further details on theming, you can visit the [documentation](https://rocketchat.github.io/EmbeddedChat/docs/docs/Usage/theming) or check out the [technical guide](https://rocketchat.github.io/EmbeddedChat/docs/docs/Development/theming_technical) for insights on how theming is implemented in the repository.
### Enhanced Authentication with HTTP-Only Cookies
@@ -99,7 +99,7 @@ A video demonstration is available here:
-For more information on authentication, refer to the [authentication guide](https://github.com/RocketChat/EmbeddedChat/blob/develop/packages/docs/authentication.md).
+For more information on authentication, refer to the [authentication guide](https://rocketchat.github.io/EmbeddedChat/docs/docs/Usage/authentication).
### UI-Kit Improvement
@@ -134,7 +134,7 @@ The following videos demonstrate its usage:
-To set up the EmbeddedChat RC App, follow this guide: [EmbeddedChat RC App Setup](https://github.com/RocketChat/EmbeddedChat/blob/develop/packages/docs/ec_rc_setup.md).
+To set up the EmbeddedChat RC App, follow this guide: [EmbeddedChat RC App Setup](https://rocketchat.github.io/EmbeddedChat/docs/docs/Usage/ec_rc_setup).
### Layout Editor
@@ -144,7 +144,7 @@ A video demonstration showcases the features:
-To learn more about the layout editor, visit the guide: [Layout Editor Guide](https://github.com/RocketChat/EmbeddedChat/blob/develop/packages/docs/layout_editor.md).
+To learn more about the layout editor, visit the guide: [Layout Editor Guide](https://rocketchat.github.io/EmbeddedChat/docs/docs/Usage/layout_editor).
## 🚀 Contributions
From 70d714c667a05a2ebb301cc646461a95e7589ff2 Mon Sep 17 00:00:00 2001
From: Khizar Shah <109973520+Khizarshah01@users.noreply.github.com>
Date: Sun, 1 Jun 2025 18:00:22 +0530
Subject: [PATCH 105/153] fix: auto-detect OS/browser color theme on initial
load (#1005)
---
packages/docs/docusaurus.config.js | 5 +++++
packages/docs/src/css/custom.css | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/packages/docs/docusaurus.config.js b/packages/docs/docusaurus.config.js
index 1201dae919..0ffbd70998 100644
--- a/packages/docs/docusaurus.config.js
+++ b/packages/docs/docusaurus.config.js
@@ -123,6 +123,11 @@ const config = {
},
],
},
+ colorMode: {
+ defaultMode: 'light',
+ disableSwitch: false,
+ respectPrefersColorScheme: true,
+ },
prism: {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
diff --git a/packages/docs/src/css/custom.css b/packages/docs/src/css/custom.css
index 8fa55b551b..8697856532 100644
--- a/packages/docs/src/css/custom.css
+++ b/packages/docs/src/css/custom.css
@@ -5,7 +5,7 @@
*/
/* You can override the default Infima variables here. */
-:root {
+[data-theme='light']:root {
--ifm-color-primary: #1f3e05;
--ifm-color-primary-dark: #29784c;
--ifm-color-primary-darker: #277148;
From fbf5daedc367d69d229f8e44a066dd6a5c65acb8 Mon Sep 17 00:00:00 2001
From: Khizar Shah <109973520+Khizarshah01@users.noreply.github.com>
Date: Sun, 8 Jun 2025 16:53:10 +0530
Subject: [PATCH 106/153] docs: add Node.js >=18 requirement and nvm
instructions for docs/ folder & format the readme (#1007)
---
packages/docs/README.md | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/packages/docs/README.md b/packages/docs/README.md
index 812eeb9d01..aaf7803b93 100644
--- a/packages/docs/README.md
+++ b/packages/docs/README.md
@@ -1,17 +1,29 @@
# EmbeddedChat Documentation
-This is the official documentation website of EmbeddedChat
+This is the official documentation website of EmbeddedChat.
+
+> **Node.js Version Requirement**
+>
+> The `docs/` folder requires **Node.js v18 or higher** to run correctly.
+> If you’re using a lower version (e.g., v16.19.0 from other parts of the monorepo), you may encounter errors.
+>
+> Use [NVM](https://github.com/nvm-sh/nvm) to install and switch to the correct version:
+>
+> ```bash
+> nvm install 18
+> nvm use 18
+> ```
### Installation
```
-$ yarn install
+ yarn install
```
### Local Development
```
-$ yarn dev
+ yarn dev
```
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
@@ -19,7 +31,7 @@ This command starts a local development server and opens up a browser window. Mo
### Build
```
-$ yarn build
+ yarn build
```
This command generates static content into the `build` directory and can be served using any static contents hosting service.
From 58e1f816c8498d57cc5fd9ef5e6538941586950f Mon Sep 17 00:00:00 2001
From: Khizar Shah <109973520+Khizarshah01@users.noreply.github.com>
Date: Sun, 21 Sep 2025 22:10:00 +0530
Subject: [PATCH 107/153] fix: implement URL validation in InsertLinkToolBox
(#1012)
---
package.json | 3 +-
.../src/views/ChatInput/InsertLinkToolBox.js | 39 ++++++++++++++++---
yarn.lock | 8 ++++
3 files changed, 44 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index 3868bafb9c..c589243fe2 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"typescript": "^5.1.3"
},
"dependencies": {
- "dompurify": "^3.1.6"
+ "dompurify": "^3.1.6",
+ "validator": "^13.15.15"
}
}
diff --git a/packages/react/src/views/ChatInput/InsertLinkToolBox.js b/packages/react/src/views/ChatInput/InsertLinkToolBox.js
index 49e8e0d4ad..c8f9247628 100644
--- a/packages/react/src/views/ChatInput/InsertLinkToolBox.js
+++ b/packages/react/src/views/ChatInput/InsertLinkToolBox.js
@@ -1,5 +1,6 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
import { Modal, Input, Button, useTheme } from '@embeddedchat/ui-elements';
+import validator from 'validator';
import { getInsertLinkModalStyles } from './ChatInput.styles';
const InsertLinkToolBox = ({
@@ -9,14 +10,35 @@ const InsertLinkToolBox = ({
}) => {
const { theme } = useTheme();
const styles = getInsertLinkModalStyles(theme);
- const [linkText, setLinkText] = useState(selectedText || 'Text');
- const [linkUrl, setLinkUrl] = useState(null);
+ const [linkText, setLinkText] = useState(selectedText || '');
+ const [linkUrl, setLinkUrl] = useState('');
+ const [isUrlValid, setIsUrlValid] = useState(false);
+
+ const validateUrl = (url) =>
+ validator.isURL(url, {
+ protocols: ['http', 'https'],
+ require_protocol: true,
+ require_valid_protocol: true,
+ disallow_auth: true,
+ });
+
+ useEffect(() => {
+ const isValid = validateUrl(linkUrl);
+ setIsUrlValid(isValid);
+ }, [linkUrl]);
const handleLinkTextOnChange = (e) => {
setLinkText(e.target.value);
};
const handleLinkUrlOnChange = (e) => {
- setLinkUrl(e.target.value);
+ const url = e.target.value.trim();
+ setLinkUrl(url);
+ setIsUrlValid(url ? validateUrl(url) : false);
+ };
+
+ const handleAdd = () => {
+ if (!isUrlValid) return;
+ handleAddLink(linkText, linkUrl);
};
return (
@@ -30,11 +52,13 @@ const InsertLinkToolBox = ({
type="text"
onChange={handleLinkTextOnChange}
value={linkText}
+ placeholder="Text"
css={styles.inputWithFormattingBox}
/>
@@ -43,7 +67,12 @@ const InsertLinkToolBox = ({
Cancel
- handleAddLink(linkText, linkUrl)}>
+
Add
diff --git a/yarn.lock b/yarn.lock
index d3dec11bea..23b67cfd11 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -15209,6 +15209,7 @@ __metadata:
husky: ^9.0.11
lerna: ^6.6.2
typescript: ^5.1.3
+ validator: ^13.15.15
languageName: unknown
linkType: soft
@@ -31653,6 +31654,13 @@ __metadata:
languageName: node
linkType: hard
+"validator@npm:^13.15.15":
+ version: 13.15.15
+ resolution: "validator@npm:13.15.15"
+ checksum: 10c1b9215a25c31497c481cf4a3ee3e17dcf0b8a219445788e7167ed1b93b8597bbf657bd5c8ca22199b699c3ab41df902c23526cc514075c4b71bd19a13d02c
+ languageName: node
+ linkType: hard
+
"vary@npm:^1, vary@npm:~1.1.2":
version: 1.1.2
resolution: "vary@npm:1.1.2"
From 23b6c398e56323ba858592b5a7f332401c03b910 Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sun, 19 Oct 2025 18:21:56 +0530
Subject: [PATCH 108/153] removed placeholder lines
Signed-off-by: Zishan Ahmad
---
packages/docs/docs/Usage/authentication.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/packages/docs/docs/Usage/authentication.md b/packages/docs/docs/Usage/authentication.md
index 95c3c3e7b9..3a496980cc 100644
--- a/packages/docs/docs/Usage/authentication.md
+++ b/packages/docs/docs/Usage/authentication.md
@@ -74,8 +74,6 @@ This method leverages the OAuth configuration established in Rocket.Chat, ensuri
For instructions on installing the EmbeddedChat RC app on your Rocket.Chat server, refer to the [EmbeddedChat RC App installation guide](../Usage/ec_rc_setup.md).
-Certainly! Here are the instructions to enable OAuth login in the EmbeddedChat RC app, without using sub-bullets:
-
#### Steps to Enable OAuth Login in EmbeddedChat RC App
1. Copy Callback URL:
From 698489748fa0083e8938efbd41c51205bc6a02d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B2=99=E4=BB=80=E7=93=A6=E7=89=B9?=
<114943221+ShashwatPS@users.noreply.github.com>
Date: Thu, 27 Nov 2025 20:57:42 +0530
Subject: [PATCH 109/153] fixed userSidibar re-render (#1014)
---
packages/react/src/views/UserInformation/UserInformation.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/react/src/views/UserInformation/UserInformation.js b/packages/react/src/views/UserInformation/UserInformation.js
index d03232d651..de79395c50 100644
--- a/packages/react/src/views/UserInformation/UserInformation.js
+++ b/packages/react/src/views/UserInformation/UserInformation.js
@@ -58,7 +58,7 @@ const UserInformation = () => {
};
getCurrentUserInfo();
- }, [RCInstance, setCurrentUserInfo]);
+ }, [RCInstance, currentUser]);
const ViewComponent = viewType === 'Popup' ? Popup : Sidebar;
From d746198282f319de4c01c3c00d70d97315971350 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B2=99=E4=BB=80=E7=93=A6=E7=89=B9?=
<114943221+ShashwatPS@users.noreply.github.com>
Date: Thu, 27 Nov 2025 21:03:36 +0530
Subject: [PATCH 110/153] Configured delete while edit (#1021)
---
packages/react/src/store/messageStore.js | 3 +++
packages/react/src/views/ChatInput/ChatInput.js | 14 ++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index c359a0c8eb..4f84f8c1f8 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -8,6 +8,7 @@ const useMessageStore = create((set, get) => ({
threadMessages: [],
filtered: false,
editMessage: {},
+ deletedMessage: {},
messagesOffset: 0,
quoteMessage: [],
deleteMessageRoles: {},
@@ -51,6 +52,7 @@ const useMessageStore = create((set, get) => ({
const message = get().messages.find((m) => m._id === messageId);
if (threadMessage) {
return set((state) => ({
+ deletedMessage: threadMessage,
threadMessages: cloneArray(state.threadMessages).filter(
(m) => m._id !== messageId
),
@@ -58,6 +60,7 @@ const useMessageStore = create((set, get) => ({
}
if (message) {
return set((state) => ({
+ deletedMessage: message,
messages: cloneArray(state.messages).filter((m) => m._id !== messageId),
}));
}
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index ca748520a6..50a342fb92 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -102,6 +102,7 @@ const ChatInput = ({ scrollToBottom }) => {
replaceMessage,
clearQuoteMessages,
threadId,
+ deletedMessage,
} = useMessageStore((state) => ({
editMessage: state.editMessage,
setEditMessage: state.setEditMessage,
@@ -111,6 +112,7 @@ const ChatInput = ({ scrollToBottom }) => {
replaceMessage: state.replaceMessage,
threadId: state.threadMainMessage?._id,
clearQuoteMessages: state.clearQuoteMessages,
+ deletedMessage: state.deletedMessage,
}));
const setIsLoginModalOpen = useLoginStore(
@@ -168,6 +170,18 @@ const ChatInput = ({ scrollToBottom }) => {
}
}, [editMessage]);
+ useEffect(() => {
+ if (
+ deletedMessage._id &&
+ editMessage._id &&
+ deletedMessage._id === editMessage._id
+ ) {
+ messageRef.current.value = '';
+ setDisableButton(true);
+ setEditMessage({});
+ }
+ }, [deletedMessage]);
+
const getMessageLink = async (id) => {
const host = RCInstance.getHost();
const res = await RCInstance.channelInfo();
From 883e3c87544a2abe9e4db7903f26778fdea9dac9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B2=99=E4=BB=80=E7=93=A6=E7=89=B9?=
<114943221+ShashwatPS@users.noreply.github.com>
Date: Thu, 27 Nov 2025 21:06:11 +0530
Subject: [PATCH 111/153] fixed focus (#1019)
---
packages/react/src/views/ChatInput/ChatInput.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 50a342fb92..998e9007cd 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -163,8 +163,10 @@ const ChatInput = ({ scrollToBottom }) => {
if (editMessage.attachments) {
messageRef.current.value =
editMessage.attachments[0]?.description || editMessage.msg;
+ messageRef.current.focus();
} else if (editMessage.msg) {
messageRef.current.value = editMessage.msg;
+ messageRef.current.focus();
} else {
messageRef.current.value = '';
}
From 68b0d36896d94feb48c69570b882a864cd50e4ca Mon Sep 17 00:00:00 2001
From: R Pratheek <111165032+Pratheek555@users.noreply.github.com>
Date: Thu, 27 Nov 2025 22:28:51 +0530
Subject: [PATCH 112/153] FIX: Pin action system message does not render
markdown or message content #1022 (#1023)
* fixed pinned message not appearing in system message
* removed unecessary logs
* lint issues
* further fixing the lint issues
---------
Co-authored-by: Pratheek
---
packages/react/src/views/AttachmentHandler/TextAttachment.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/AttachmentHandler/TextAttachment.js b/packages/react/src/views/AttachmentHandler/TextAttachment.js
index 423684e4f1..73387c7413 100644
--- a/packages/react/src/views/AttachmentHandler/TextAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/TextAttachment.js
@@ -2,6 +2,7 @@ import React, { useState, useContext } from 'react';
import { css } from '@emotion/react';
import PropTypes from 'prop-types';
import { Box, Avatar, useTheme, Icon } from '@embeddedchat/ui-elements';
+import { parse } from '@rocket.chat/message-parser';
import AttachmentMetadata from './AttachmentMetadata';
import RCContext from '../../context/RCInstance';
import { Markdown } from '../Markdown';
@@ -114,7 +115,7 @@ const FileAttachment = ({
) : (
)
From 1b777fb89dbd8c7cc978635eaffd23c0cc206082 Mon Sep 17 00:00:00 2001
From: R Pratheek <111165032+Pratheek555@users.noreply.github.com>
Date: Wed, 10 Dec 2025 12:01:31 +0530
Subject: [PATCH 113/153] fixing messages not being rendered inside threads
(#1033)
* fixing messages not being rendered inside threads
* removing roomId parameter
---
packages/api/src/EmbeddedChatApi.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 46690e24e6..809b6f4b5c 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -632,7 +632,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const messages = await fetch(
- `${this.host}/api/v1/chat.getThreadMessages?roomId=${this.rid}&tmid=${tmid}`,
+ `${this.host}/api/v1/chat.getThreadMessages?tmid=${tmid}`,
{
headers: {
"Content-Type": "application/json",
From 5ada56e2d60d8aea3c58c8eedf45c0183a4d1882 Mon Sep 17 00:00:00 2001
From: srijna
Date: Thu, 15 Jan 2026 14:55:49 +0530
Subject: [PATCH 114/153] feat: add unread messages divider with theme-aware
styling (#1047)
---
packages/react/src/views/ChatBody/ChatBody.js | 30 +++++++++++
.../react/src/views/ChatInput/ChatInput.js | 6 ++-
.../react/src/views/ChatLayout/ChatLayout.js | 9 +++-
.../react/src/views/Message/Message.styles.js | 52 +++++++++++++++++++
.../react/src/views/Message/MessageDivider.js | 12 +++--
.../src/views/MessageList/MessageList.js | 26 ++++++----
6 files changed, 120 insertions(+), 15 deletions(-)
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index eeae34dfb7..34f5c8bf40 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -40,6 +40,7 @@ const ChatBody = ({
showRoles,
messageListRef,
scrollToBottom,
+ clearUnreadDividerRef,
}) => {
const { classNames, styleOverrides } = useComponentOverrides('ChatBody');
const { theme, mode } = useTheme();
@@ -49,6 +50,8 @@ const ChatBody = ({
const [, setIsUserScrolledUp] = useState(false);
const [otherUserMessage, setOtherUserMessage] = useState(false);
const [isOverflowing, setIsOverflowing] = useState(false);
+ const [firstUnreadMessageId, setFirstUnreadMessageId] = useState(null);
+ const pendingFirstUnreadRef = useRef(null);
const { RCInstance, ECOptions } = useContext(RCContext);
const showAnnouncement = ECOptions?.showAnnouncement;
const messages = useMessageStore((state) => state.messages);
@@ -124,6 +127,10 @@ const ChatBody = ({
const isScrolledUp = messageListRef?.current?.scrollTop !== 0;
if (isScrolledUp && !('pinned' in message) && !('starred' in message)) {
setOtherUserMessage(true);
+ // Track the first unread message (only set if not already tracking)
+ if (!pendingFirstUnreadRef.current) {
+ pendingFirstUnreadRef.current = message._id;
+ }
}
}
upsertMessage(message, ECOptions?.enableThreads);
@@ -177,7 +184,22 @@ const ChatBody = ({
});
}, []);
+ // Expose clearUnreadDivider function via ref for ChatInput to call
+ useEffect(() => {
+ if (clearUnreadDividerRef) {
+ clearUnreadDividerRef.current = () => {
+ setFirstUnreadMessageId(null);
+ pendingFirstUnreadRef.current = null;
+ };
+ }
+ }, [clearUnreadDividerRef]);
+
const handlePopupClick = () => {
+ // Set the unread divider to show above the first unread message
+ if (pendingFirstUnreadRef.current) {
+ setFirstUnreadMessageId(pendingFirstUnreadRef.current);
+ pendingFirstUnreadRef.current = null;
+ }
scrollToBottom();
setIsUserScrolledUp(false);
setOtherUserMessage(false);
@@ -242,6 +264,12 @@ const ChatBody = ({
setPopupVisible(false);
setIsUserScrolledUp(false);
setOtherUserMessage(false);
+ // Clear unread divider when scrolled to bottom
+ if (firstUnreadMessageId) {
+ setFirstUnreadMessageId(null);
+ }
+ // Also clear pending unread ref
+ pendingFirstUnreadRef.current = null;
}
}, [
messageListRef,
@@ -258,6 +286,7 @@ const ChatBody = ({
setIsUserScrolledUp,
setPopupVisible,
setOtherUserMessage,
+ firstUnreadMessageId,
]);
const showNewMessagesPopup = () => {
@@ -392,6 +421,7 @@ const ChatBody = ({
loadingOlderMessages={loadingOlderMessages}
isUserAuthenticated={isUserAuthenticated}
hasMoreMessages={hasMoreMessages}
+ firstUnreadMessageId={firstUnreadMessageId}
/>
)}
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 998e9007cd..c30e9c03cf 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -35,7 +35,7 @@ import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import formatSelection from '../../lib/formatSelection';
import { parseEmoji } from '../../lib/emoji';
-const ChatInput = ({ scrollToBottom }) => {
+const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
const { RCInstance, ECOptions } = useRCContext();
const { theme } = useTheme();
@@ -398,6 +398,10 @@ const ChatInput = ({ scrollToBottom }) => {
handleSendNewMessage(message);
scrollToBottom();
+ // Clear unread divider when user sends a message
+ if (clearUnreadDividerRef?.current) {
+ clearUnreadDividerRef.current();
+ }
};
const sendAttachment = (event) => {
diff --git a/packages/react/src/views/ChatLayout/ChatLayout.js b/packages/react/src/views/ChatLayout/ChatLayout.js
index 60c935a360..f3b4262acb 100644
--- a/packages/react/src/views/ChatLayout/ChatLayout.js
+++ b/packages/react/src/views/ChatLayout/ChatLayout.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useRef, useCallback, useState } from 'react';
+import React, { useEffect, useRef, useCallback } from 'react';
import { Box, useComponentOverrides } from '@embeddedchat/ui-elements';
import styles from './ChatLayout.styles';
import {
@@ -35,6 +35,7 @@ import useUiKitStore from '../../store/uiKitStore';
const ChatLayout = () => {
const messageListRef = useRef(null);
+ const clearUnreadDividerRef = useRef(null);
const { classNames, styleOverrides } = useComponentOverrides('ChatBody');
const { RCInstance, ECOptions } = useRCContext();
const anonymousMode = ECOptions?.anonymousMode;
@@ -113,8 +114,12 @@ const ChatLayout = () => {
showRoles={showRoles}
messageListRef={messageListRef}
scrollToBottom={scrollToBottom}
+ clearUnreadDividerRef={clearUnreadDividerRef}
+ />
+
-
diff --git a/packages/react/src/views/Message/Message.styles.js b/packages/react/src/views/Message/Message.styles.js
index 75253043e2..9099f72ec2 100644
--- a/packages/react/src/views/Message/Message.styles.js
+++ b/packages/react/src/views/Message/Message.styles.js
@@ -108,6 +108,58 @@ export const getMessageDividerStyles = (theme) => {
return styles;
};
+export const getUnreadMessageDividerStyles = (theme, mode) => {
+ // Use destructive (red) for light themes, warningForeground (orange) for dark themes
+ const dividerColor =
+ mode === 'light'
+ ? theme.colors.destructive
+ : theme.colors.warningForeground;
+
+ const styles = {
+ divider: css`
+ letter-spacing: 0rem;
+ font-size: 0.75rem;
+ font-weight: 700;
+ line-height: 1rem;
+ position: relative;
+ display: flex;
+ z-index: 1000;
+ align-items: center;
+ margin-top: 0.5rem;
+ margin-bottom: 0.75rem;
+ padding-left: 1.25rem;
+ padding-right: 1.25rem;
+ @media (max-width: 780px) {
+ z-index: 1;
+ }
+ `,
+
+ dividerContent: css`
+ margin-top: 0.5rem;
+ margin-bottom: 0.5rem;
+ padding-left: 0.5rem;
+ padding-right: 0.5rem;
+ background-color: ${theme.colors.background};
+ color: ${dividerColor};
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ border-radius: ${theme.radius};
+ `,
+
+ bar: css`
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ flex-grow: 1;
+ height: 1px;
+ background-color: ${dividerColor};
+ `,
+ };
+
+ return styles;
+};
+
export const getMessageHeaderStyles = (theme) => {
const styles = {
header: css`
diff --git a/packages/react/src/views/Message/MessageDivider.js b/packages/react/src/views/Message/MessageDivider.js
index 617b7615cf..9c8f1c26bf 100644
--- a/packages/react/src/views/Message/MessageDivider.js
+++ b/packages/react/src/views/Message/MessageDivider.js
@@ -6,11 +6,15 @@ import {
useTheme,
} from '@embeddedchat/ui-elements';
-import { getMessageDividerStyles } from './Message.styles';
+import {
+ getMessageDividerStyles,
+ getUnreadMessageDividerStyles,
+} from './Message.styles';
export const MessageDivider = ({
children,
unreadLabel,
+ unread = false,
className = '',
style = {},
...props
@@ -20,8 +24,10 @@ export const MessageDivider = ({
className,
style
);
- const { theme } = useTheme();
- const styles = getMessageDividerStyles(theme);
+ const { theme, mode } = useTheme();
+ const styles = unread
+ ? getUnreadMessageDividerStyles(theme, mode)
+ : getMessageDividerStyles(theme);
return (
{
const showReportMessage = useMessageStore((state) => state.showReportMessage);
const messageToReport = useMessageStore((state) => state.messageToReport);
@@ -86,17 +88,23 @@ const MessageList = ({
const sequential = isMessageSequential(msg, prev, 300);
const lastSequential =
sequential && isMessageLastSequential(msg, next);
+ const showUnreadDivider =
+ firstUnreadMessageId && msg._id === firstUnreadMessageId;
return (
-
+
+ {showUnreadDivider && (
+ Unread Messages
+ )}
+
+
);
})}
{showReportMessage && (
From 7a241ab28931463c7b5f23ebe56705bc33229051 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Thu, 15 Jan 2026 15:01:46 +0530
Subject: [PATCH 115/153] feat: Enhance video recorder (#831)
* Enhance video recorder
* Updated Config
* Fixed Bug - Disabled Send button should not work after the click
---------
Co-authored-by: Zishan Ahmad
---
packages/react/src/hooks/useMediaRecorder.js | 79 +++++-
.../src/views/ChatInput/ChatInput.styles.js | 31 ++-
.../views/ChatInput/VideoMessageRecoder.js | 254 +++++++++++-------
.../src/components/Icon/icons/Record.js | 25 ++
.../src/components/Icon/icons/StopRecord.js | 25 ++
.../src/components/Icon/icons/index.js | 4 +
6 files changed, 322 insertions(+), 96 deletions(-)
create mode 100644 packages/ui-elements/src/components/Icon/icons/Record.js
create mode 100644 packages/ui-elements/src/components/Icon/icons/StopRecord.js
diff --git a/packages/react/src/hooks/useMediaRecorder.js b/packages/react/src/hooks/useMediaRecorder.js
index 05046a59de..028b0d9b1d 100644
--- a/packages/react/src/hooks/useMediaRecorder.js
+++ b/packages/react/src/hooks/useMediaRecorder.js
@@ -1,4 +1,4 @@
-import { useState, useRef } from 'react';
+import { useState, useRef, useEffect } from 'react';
function useUserMedia(constraints, videoRef) {
const [stream, setStream] = useState();
@@ -47,3 +47,80 @@ export function useMediaRecorder({ constraints, onStop, videoRef }) {
return [start, stop];
}
+
+export function useNewMediaRecorder({ constraints, videoRef, onStop }) {
+ const [stream, setStream] = useState();
+ const [isStreaming, setIsStreaming] = useState(false);
+ const [recorder, setRecorder] = useState();
+ const [recordingData, setRecordingData] = useState(null);
+ const chunks = useRef([]);
+
+ async function startCameraAndMic() {
+ if (isStreaming) return;
+ try {
+ const _stream = await navigator.mediaDevices.getUserMedia(constraints);
+ setStream(_stream);
+ setIsStreaming(true);
+ if (videoRef.current) {
+ videoRef.current.srcObject = _stream;
+ }
+ } catch (error) {
+ console.error('Error starting camera and mic:', error);
+ }
+ }
+
+ async function startRecording() {
+ if (!isStreaming) {
+ console.error('Camera and mic must be on to start recording.');
+ return;
+ }
+
+ chunks.current = [];
+ const _recorder = new MediaRecorder(stream);
+ _recorder.start();
+ setRecorder(_recorder);
+
+ _recorder.addEventListener('dataavailable', (event) => {
+ chunks.current.push(event.data);
+ });
+
+ _recorder.addEventListener('stop', () => {
+ setRecordingData(new Blob(chunks.current, { type: 'video/mp4' }));
+ onStop && onStop(chunks.current);
+ });
+ }
+
+ async function stopRecording() {
+ if (recorder && recorder.state === 'recording') {
+ recorder.stop();
+ }
+ }
+
+ function getRecording() {
+ return recordingData;
+ }
+
+ function deleteRecording() {
+ setRecordingData(null);
+ chunks.current = [];
+ }
+
+ function stopCameraAndMic() {
+ if (stream) {
+ stream.getTracks().forEach((track) => track.stop());
+ setStream(null);
+ setIsStreaming(false);
+ }
+ }
+
+ useEffect(() => () => stopCameraAndMic(), []);
+
+ return {
+ startCameraAndMic,
+ startRecording,
+ stopRecording,
+ getRecording,
+ deleteRecording,
+ stopCameraAndMic,
+ };
+}
diff --git a/packages/react/src/views/ChatInput/ChatInput.styles.js b/packages/react/src/views/ChatInput/ChatInput.styles.js
index b193d06922..0841451324 100644
--- a/packages/react/src/views/ChatInput/ChatInput.styles.js
+++ b/packages/react/src/views/ChatInput/ChatInput.styles.js
@@ -118,21 +118,48 @@ export const getCommonRecorderStyles = (theme) => {
border-radius: 50%;
background-color: ${theme.colors.destructive};
margin: auto;
- margin-right: 8px;
+ margin-right: 5px;
+ margin-left: 5px;
+ `,
+
+ oppositeDot: css`
+ width: 0.5rem;
+ height: 0.5rem;
+ border-radius: 50%;
+ background-color: ${theme.colors.background};
+ margin: auto;
+ margin-right: 5px;
+ margin-left: 5px;
`,
controller: css`
- gap: 0.15rem;
+ width: 100%;
display: inline-flex;
`,
timer: css`
margin: auto;
`,
+
+ spacer: css`
+ flex-grow: 1;
+ `,
+
record: css`
display: flex;
margin: auto;
`,
+
+ leftSection: css`
+ display: flex;
+ align-items: left;
+ `,
+
+ rightSection: css`
+ display: flex;
+ align-items: right;
+ margin-top: 0.3rem;
+ `,
modal: {
'@media(max-width: 768px)': {
height: '100%',
diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
index 814c2093aa..f153d4c697 100644
--- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js
+++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
@@ -7,94 +7,52 @@ import {
Tooltip,
Modal,
useTheme,
+ Button,
+ lighten,
+ darken,
} from '@embeddedchat/ui-elements';
-import { useMediaRecorder } from '../../hooks/useMediaRecorder';
+import { useNewMediaRecorder } from '../../hooks/useMediaRecorder';
import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
import useAttachmentWindowStore from '../../store/attachmentwindow';
const VideoMessageRecorder = (props) => {
const videoRef = useRef(null);
+ const [isRecording, setIsRecording] = useState(false);
const { disabled, displayName, popOverItemStyles } = props;
const { theme } = useTheme();
+ const { mode } = useTheme();
const styles = getCommonRecorderStyles(theme);
- const toogleRecordingMessage = useMessageStore(
- (state) => state.toogleRecordingMessage
- );
-
- const { toggle, setData } = useAttachmentWindowStore((state) => ({
- toggle: state.toggle,
- setData: state.setData,
- }));
+ const [state, setRecordState] = useState('idle'); // 1. idle, 2. preview.
- const [state, setRecordState] = useState('idle');
const [time, setTime] = useState('00:00');
const [recordingInterval, setRecordingInterval] = useState(null);
const [file, setFile] = useState(null);
- const [isRecorded, setIsRecorded] = useState(false);
- const onStop = (videoChunks) => {
- const videoBlob = new Blob(videoChunks, { type: 'video/mp4' });
- const fileName = 'Video record.mp4';
- setFile(new File([videoBlob], fileName, { type: 'video/mp4' }));
- };
+ const [isSendDisabled, setIsSendDisabled] = useState(true);
- const [start, stop] = useMediaRecorder({
- constraints: { audio: true, video: true }, // Update constraints as needed
- onStop,
+ const { toggle, setData } = useAttachmentWindowStore((state_) => ({
+ toggle: state_.toggle,
+ setData: state_.setData,
+ }));
+
+ const {
+ startCameraAndMic,
+ startRecording,
+ stopRecording,
+ deleteRecording,
+ stopCameraAndMic,
+ } = useNewMediaRecorder({
+ constraints: { video: true, audio: true },
videoRef,
+ onStop: (videoChunks) => {
+ const videoBlob = new Blob(videoChunks, { type: 'video/mp4' });
+ const fileName = 'Video record.mp4';
+ setFile(new File([videoBlob], fileName, { type: 'video/mp4' }));
+ },
});
- const stopRecording = async () => {
- stop();
- if (recordingInterval) {
- clearInterval(recordingInterval);
- }
- setRecordingInterval(null);
- setTime('00:00');
- setRecordState('idle');
- };
-
- const handleRecordButtonClick = () => {
- if (disabled) return;
- setRecordState('recording');
- try {
- start(videoRef.current);
- toogleRecordingMessage();
- const startTime = new Date();
- setRecordingInterval(
- setInterval(() => {
- const now = new Date();
- const distance = (now.getTime() - startTime.getTime()) / 1000;
- const minutes = Math.floor(distance / 60);
- const seconds = Math.floor(distance % 60);
- setTime(
- `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(
- 2,
- '0'
- )}`
- );
- }, 1000)
- );
- } catch (error) {
- console.log(error);
- setRecordState('idle');
- }
- };
-
- const handleCancelRecordButton = async () => {
- toogleRecordingMessage();
- await stopRecording();
- setIsRecorded(false);
- };
-
- const handleStopRecordButton = async () => {
- toogleRecordingMessage();
- setIsRecorded(true);
- await stopRecording();
- };
-
const handleMount = useCallback(async () => {
if (navigator.permissions) {
try {
@@ -134,16 +92,77 @@ const VideoMessageRecorder = (props) => {
handleMount();
}, [handleMount]);
- useEffect(() => {
- if (isRecorded && file) {
- toggle();
- setData(file);
- setIsRecorded(false);
+ const startRecordingInterval = () => {
+ const startTime = new Date();
+ setRecordingInterval(
+ setInterval(() => {
+ const now = new Date();
+ const distance = (now.getTime() - startTime.getTime()) / 1000;
+ const minutes = Math.floor(distance / 60);
+ const seconds = Math.floor(distance % 60);
+ setTime(
+ `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(
+ 2,
+ '0'
+ )}`
+ );
+ }, 1000)
+ );
+ };
+
+ const stopRecordingInterval = () => {
+ if (recordingInterval) {
+ clearInterval(recordingInterval);
}
+ setRecordingInterval(null);
+ };
+
+ const deleteRecordingInterval = () => {
+ stopRecordingInterval();
+ setTime('00:00');
+ };
+
+ const openWindowToRecord = () => {
+ startCameraAndMic();
+ setRecordState('preview');
+ };
+
+ const handleStartRecording = () => {
+ deleteRecordingInterval();
+ setIsRecording(true);
+ startRecording();
+ startRecordingInterval();
+ setIsSendDisabled(true);
+ };
+
+ const handleStopRecording = () => {
+ stopRecording();
+ stopRecordingInterval();
+ setIsRecording(false);
+ setIsSendDisabled(false);
+ };
+
+ const handleSendRecording = () => {
+ if (isRecording) return;
if (file) {
- setFile(null);
+ toggle();
+ setData(file);
}
- }, [isRecorded, file]);
+ deleteRecordingInterval();
+ deleteRecording();
+ stopCameraAndMic();
+ setRecordState('idle');
+ setIsSendDisabled(true);
+ };
+
+ const closeWindowStopRecord = () => {
+ stopRecording();
+ deleteRecordingInterval();
+ deleteRecording();
+ stopCameraAndMic();
+ setRecordState('idle');
+ setIsSendDisabled(true);
+ };
return (
<>
@@ -152,7 +171,7 @@ const VideoMessageRecorder = (props) => {
@@ -164,21 +183,21 @@ const VideoMessageRecorder = (props) => {
ghost
square
disabled={disabled}
- onClick={handleRecordButtonClick}
+ onClick={openWindowToRecord}
>
))}
- {state === 'recording' && (
+ {state === 'preview' && (
<>
>
diff --git a/packages/ui-elements/src/components/Icon/icons/Record.js b/packages/ui-elements/src/components/Icon/icons/Record.js
new file mode 100644
index 0000000000..aa5480cc23
--- /dev/null
+++ b/packages/ui-elements/src/components/Icon/icons/Record.js
@@ -0,0 +1,25 @@
+import React from 'react';
+
+const Record = (props) => (
+
+);
+
+export default Record;
diff --git a/packages/ui-elements/src/components/Icon/icons/StopRecord.js b/packages/ui-elements/src/components/Icon/icons/StopRecord.js
new file mode 100644
index 0000000000..c4adda4cd2
--- /dev/null
+++ b/packages/ui-elements/src/components/Icon/icons/StopRecord.js
@@ -0,0 +1,25 @@
+import React from 'react';
+
+const StopRecord = (props) => (
+
+);
+
+export default StopRecord;
diff --git a/packages/ui-elements/src/components/Icon/icons/index.js b/packages/ui-elements/src/components/Icon/icons/index.js
index 234251edab..1f416a020a 100644
--- a/packages/ui-elements/src/components/Icon/icons/index.js
+++ b/packages/ui-elements/src/components/Icon/icons/index.js
@@ -37,6 +37,8 @@ import Kebab from './Kebab';
import Check from './Check';
import ErrorCircle from './ErrorCircle';
import ArrowDown from './ArrowDown';
+import Record from './Record';
+import StopRecord from './StopRecord';
import PinFilled from './PinFilled';
import VideoRecorder from './VideoRecoder';
import DisabledRecorder from './DisableRecorder';
@@ -109,6 +111,8 @@ const icons = {
check: Check,
'error-circle': ErrorCircle,
'arrow-down': ArrowDown,
+ record: Record,
+ 'stop-record': StopRecord,
'pin-filled': PinFilled,
clipboard: Clipboard,
clip: Clip,
From adfd0eeb035aa9575a8e51a8f0dc66f759a251b1 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Thu, 15 Jan 2026 15:03:24 +0530
Subject: [PATCH 116/153] Feat: Added 'Online User Status' Filter to Members
List (#782)
* Feat: Add 'Online User Status' Filter to Members List
* Added space between InviteButton and search bar-user status filter
* fixed lint import error
* Added Divider along with Display count and total count of members
* Updated count logic with RC
* Removed API Call to fetch status of user
---------
Co-authored-by: Zishan Ahmad
---
.../react/src/views/RoomMembers/RoomMember.js | 96 +++++++++++++++----
.../src/views/RoomMembers/RoomMemberItem.js | 21 +---
.../views/RoomMembers/RoomMembers.styles.js | 8 +-
3 files changed, 87 insertions(+), 38 deletions(-)
diff --git a/packages/react/src/views/RoomMembers/RoomMember.js b/packages/react/src/views/RoomMembers/RoomMember.js
index f60c3476f9..27a97278fc 100644
--- a/packages/react/src/views/RoomMembers/RoomMember.js
+++ b/packages/react/src/views/RoomMembers/RoomMember.js
@@ -7,9 +7,12 @@ import {
Sidebar,
Input,
Popup,
+ StaticSelect,
+ Divider,
useComponentOverrides,
useTheme,
} from '@embeddedchat/ui-elements';
+import { css } from '@emotion/react';
import RoomMemberItem from './RoomMemberItem';
import RCContext, { useRCContext } from '../../context/RCInstance';
import useInviteStore from '../../store/inviteStore';
@@ -37,6 +40,8 @@ const RoomMembers = ({ members }) => {
const [searchTerm, setSearchTerm] = useState('');
const [filteredMembers, setFilteredMembers] = useState(members);
+ const [viewStatus, setViewStatus] = useState('All');
+
useEffect(() => {
const getUserInfo = async () => {
try {
@@ -52,19 +57,32 @@ const RoomMembers = ({ members }) => {
}, [RCInstance]);
useEffect(() => {
+ const filtered = members.filter((member) => {
+ if (viewStatus === 'Online') {
+ return member.status === 'online';
+ }
+ return true;
+ });
+
setFilteredMembers(
- members.filter(
+ filtered.filter(
(member) =>
member.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
member.username?.toLowerCase().includes(searchTerm.toLowerCase())
)
);
- }, [searchTerm, members]);
+ }, [viewStatus, searchTerm, members]);
const roles = userInfo && userInfo.roles ? userInfo.roles : [];
const isAdmin = roles.includes('admin');
const ViewComponent = viewType === 'Popup' ? Popup : Sidebar;
+ const handleSelect = (value) => {
+ setViewStatus(value);
+ };
+
+ const displayedMembers = filteredMembers.length;
+
return (
{
<>
{isAdmin && (
{
toggleInviteView();
}}
@@ -95,25 +117,63 @@ const RoomMembers = ({ members }) => {
Invite Link
)}
-
- setSearchTerm(e.target.value)}
- placeholder="Search members"
- />
-
+
+
+ setSearchTerm(e.target.value)}
+ placeholder="Search members"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+ Showing {displayedMembers} of {displayedMembers}
{filteredMembers.length > 0 ? (
filteredMembers.map((member) => (
- <>
-
- >
+
))
) : (
No members found
diff --git a/packages/react/src/views/RoomMembers/RoomMemberItem.js b/packages/react/src/views/RoomMembers/RoomMemberItem.js
index f5ff504035..d53632782d 100644
--- a/packages/react/src/views/RoomMembers/RoomMemberItem.js
+++ b/packages/react/src/views/RoomMembers/RoomMemberItem.js
@@ -1,34 +1,17 @@
-import React, { useContext, useEffect, useState } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import { Box, Icon, Avatar, useTheme } from '@embeddedchat/ui-elements';
-import RCContext from '../../context/RCInstance';
import { RoomMemberItemStyles } from './RoomMembers.styles';
import useSetExclusiveState from '../../hooks/useSetExclusiveState';
import { useUserStore } from '../../store';
-const RoomMemberItem = ({ user, host }) => {
- const { RCInstance } = useContext(RCContext);
- const [userStatus, setUserStatus] = useState('');
+const RoomMemberItem = ({ user, host, userStatus }) => {
const avatarUrl = new URL(`avatar/${user.username}`, host).toString();
const { theme } = useTheme();
const { mode } = useTheme();
const styles = RoomMemberItemStyles(theme, mode);
- useEffect(() => {
- const getStatus = async () => {
- try {
- const res = await RCInstance.getUserStatus(user._id);
- if (res.success) {
- setUserStatus(res.status);
- }
- } catch (err) {
- console.error('Error fetching user status:', err);
- }
- };
-
- getStatus();
- }, [RCInstance]);
const setExclusiveState = useSetExclusiveState();
const { setShowCurrentUserInfo, setCurrentUser } = useUserStore((state) => ({
setShowCurrentUserInfo: state.setShowCurrentUserInfo,
diff --git a/packages/react/src/views/RoomMembers/RoomMembers.styles.js b/packages/react/src/views/RoomMembers/RoomMembers.styles.js
index 415940c2f4..1ff0181b7f 100644
--- a/packages/react/src/views/RoomMembers/RoomMembers.styles.js
+++ b/packages/react/src/views/RoomMembers/RoomMembers.styles.js
@@ -19,7 +19,13 @@ export const getRoomMemberStyles = (theme) => {
padding: 0 0.5rem;
border-radius: ${theme.radius};
position: relative;
- margin-top: 1rem;
+ width: 60%;
+ `,
+ filterContainer: css`
+ width: 40%;
+ margin-left: 0.5rem;
+ border-radius: ${theme.radius};
+ position: relative;
`,
textInput: css`
flex: 1;
From 2de96a8e058ffbe47ec58e8c05d942572c66595b Mon Sep 17 00:00:00 2001
From: Kartik
Date: Thu, 15 Jan 2026 15:30:18 +0530
Subject: [PATCH 117/153] fix: improve system message layout and avatar
consistency (#1061)
* fix: improve system message layout and avatar consistency
- Add flex-wrap to message header for proper text wrapping
- Move system action text to separate line using CSS order
- Make avatar sizes consistent across all message types
- Remove conditional avatar sizing for system messages
* Added the avatar size back to original size and keep the username truncation fix
* fix: prevent username truncation in system messages and add tooltip for long action text
---------
Co-authored-by: dodaa08
---
packages/react/src/views/Message/Message.styles.js | 8 ++------
packages/react/src/views/Message/MessageHeader.js | 1 +
2 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/packages/react/src/views/Message/Message.styles.js b/packages/react/src/views/Message/Message.styles.js
index 9099f72ec2..5cdf333662 100644
--- a/packages/react/src/views/Message/Message.styles.js
+++ b/packages/react/src/views/Message/Message.styles.js
@@ -179,10 +179,8 @@ export const getMessageHeaderStyles = (theme) => {
font-size: 0.875rem;
font-weight: 700;
line-height: 1.25rem;
- overflow: hidden;
- text-overflow: ellipsis;
white-space: nowrap;
- flex-shrink: 1;
+ flex-shrink: 0;
`,
userName: css`
@@ -191,10 +189,8 @@ export const getMessageHeaderStyles = (theme) => {
letter-spacing: 0rem;
font-size: 0.875rem;
line-height: 1.25rem;
- overflow: hidden;
- text-overflow: ellipsis;
white-space: nowrap;
- flex-shrink: 1;
+ flex-shrink: 0;
`,
userRole: css`
diff --git a/packages/react/src/views/Message/MessageHeader.js b/packages/react/src/views/Message/MessageHeader.js
index a93a46e243..a4bff59b10 100644
--- a/packages/react/src/views/Message/MessageHeader.js
+++ b/packages/react/src/views/Message/MessageHeader.js
@@ -165,6 +165,7 @@ const MessageHeader = ({
css={styles.userActions}
className={appendClassNames('ec-message-header-useractions')}
style={{ marginLeft: '2px' }}
+ title={userActions()}
>
{userActions()}
From b5f374c8e3fec491d4d3f801c0d23d640973edce Mon Sep 17 00:00:00 2001
From: Kartik
Date: Thu, 15 Jan 2026 15:47:08 +0530
Subject: [PATCH 118/153] feat: detect links in user bio (#1056)
* fix: add URL detection and linking in user bio fields
- Add parseUrls utility function to detect URLs in bio text
- Convert detected URLs to clickable links with proper styling
- Match email link styling for consistency
- Support both http/https URLs and URLs without protocol
* fix: add React import back to UserInformation component
* refactor: use @rocket.chat/message-parser instead of custom URL regex
---------
Co-authored-by: dodaa08
---
.../react/src/views/UserInformation/UserInformation.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/UserInformation/UserInformation.js b/packages/react/src/views/UserInformation/UserInformation.js
index de79395c50..a544bd334b 100644
--- a/packages/react/src/views/UserInformation/UserInformation.js
+++ b/packages/react/src/views/UserInformation/UserInformation.js
@@ -1,5 +1,6 @@
import React, { useContext, useEffect, useState } from 'react';
import { css } from '@emotion/react';
+import { parse } from '@rocket.chat/message-parser';
import {
Box,
Sidebar,
@@ -18,6 +19,7 @@ import formatTimestampGetDate from '../../lib/formatTimestampGetDate';
import UserInfoField from './UserInfoField';
import getUserInformationStyles from './UserInformation.styles';
import useSetExclusiveState from '../../hooks/useSetExclusiveState';
+import { Markdown } from '../Markdown';
const UserInformation = () => {
const { variantOverrides } = useComponentOverrides('UserInformation');
@@ -176,7 +178,12 @@ const UserInformation = () => {
{currentUserInfo?.bio && (
+ }
isAdmin={isAllowedToViewFullInfo}
authenticatedUserId={authenticatedUserId}
currentUserInfo={currentUserInfo}
From 4c3cfd1a5dabe22e3dbc6131b9dfe311131554b7 Mon Sep 17 00:00:00 2001
From: R Pratheek <111165032+Pratheek555@users.noreply.github.com>
Date: Thu, 15 Jan 2026 15:50:51 +0530
Subject: [PATCH 119/153] Fixed slash commands entered in threads displayed in
main chat (#1042)
* Fixed slash commands entered in threads displayed in main chat
* Fixing lint issues
---
packages/api/src/EmbeddedChatApi.ts | 11 ++++++++++-
packages/react/src/views/ChatInput/ChatInput.js | 2 +-
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 809b6f4b5c..f55f55d58f 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -1191,7 +1191,15 @@ export default class EmbeddedChatApi {
return data;
}
- async execCommand({ command, params }: { command: string; params: string }) {
+ async execCommand({
+ command,
+ params,
+ tmid,
+ }: {
+ command: string;
+ params: string;
+ tmid?: string;
+ }) {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/commands.run`, {
headers: {
@@ -1203,6 +1211,7 @@ export default class EmbeddedChatApi {
body: JSON.stringify({
command,
params,
+ tmid,
roomId: this.rid,
triggerId: Math.random().toString(32).slice(2, 20),
}),
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index c30e9c03cf..e753b689ae 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -354,7 +354,7 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
const handleCommandExecution = async (message) => {
const execCommand = async (command, params) => {
- await RCInstance.execCommand({ command, params });
+ await RCInstance.execCommand({ command, params, tmid: threadId });
setFilteredCommands([]);
};
From 1fb4274ee6504fe50168ab467c5ba414f46907b6 Mon Sep 17 00:00:00 2001
From: Deepak Bhagat <149673145+deepak0x@users.noreply.github.com>
Date: Thu, 15 Jan 2026 15:53:45 +0530
Subject: [PATCH 120/153] fix: replace import assertion with readFileSync in
rollup configs (#1052)
* fix: replace import assertion with readFileSync in rollup configs
- Replace 'import packageJson from ./package.json assert { type: 'json' }' with readFileSync
- Fixes build error: SyntaxError: Unexpected identifier 'assert'
- Affects packages/auth and packages/api rollup.config.js files
- Uses Node.js fs.readFileSync which is compatible with Rollup parser
* fix: use 'with' syntax for JSON import assertions in rollup configs
- Replace readFileSync with 'with { type: 'json' }' import syntax
- Uses newer standard import attributes syntax
* fix: use createRequire with explicit path resolution for Node 16 compatibility
- Replace 'with { type: 'json' }' import syntax with createRequire approach
- Add fileURLToPath and path.dirname for explicit path resolution
- Ensures backward compatibility with Node.js 16.19.0
- Fixes build error during yarn install postinstall script
- Affects packages/auth and packages/api rollup.config.js files
---
packages/api/rollup.config.js | 8 +++++++-
packages/auth/rollup.config.js | 8 +++++++-
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/packages/api/rollup.config.js b/packages/api/rollup.config.js
index 5351b95f5f..6ce2f32df8 100644
--- a/packages/api/rollup.config.js
+++ b/packages/api/rollup.config.js
@@ -1,7 +1,13 @@
import dts from 'rollup-plugin-dts'
import esbuild from 'rollup-plugin-esbuild'
-import packageJson from './package.json' assert { type: 'json' };
import path from 'path';
+import { createRequire } from 'module';
+import { fileURLToPath } from 'url';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const require = createRequire(import.meta.url);
+const packageJson = require(path.resolve(__dirname, './package.json'));
const name = packageJson.main.replace(/\.js$/, '');
diff --git a/packages/auth/rollup.config.js b/packages/auth/rollup.config.js
index ab1343496a..6ce2f32df8 100644
--- a/packages/auth/rollup.config.js
+++ b/packages/auth/rollup.config.js
@@ -1,7 +1,13 @@
import dts from 'rollup-plugin-dts'
import esbuild from 'rollup-plugin-esbuild'
import path from 'path';
-import packageJson from './package.json' assert { type: 'json' };
+import { createRequire } from 'module';
+import { fileURLToPath } from 'url';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const require = createRequire(import.meta.url);
+const packageJson = require(path.resolve(__dirname, './package.json'));
const name = packageJson.main.replace(/\.js$/, '');
From c706b678180ee855e2e1460aa3caa05504cfcaca Mon Sep 17 00:00:00 2001
From: Kartik
Date: Thu, 15 Jan 2026 22:50:56 +0530
Subject: [PATCH 121/153] fix: mobile header layout overlap (#1066)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix: prevent header icon row from overlapping channel name on mobile
* fix: prevent header icon row from overlapping channel name on mobile
- Add flex-wrap to header for natural content wrapping
- Set min-width on channel description to prevent over-shrinking
- Add responsive styles for icon row at narrow widths (≤380px)
---------
Co-authored-by: dodaa08
---
.../react/src/views/ChatHeader/ChatHeader.js | 3 +++
.../src/views/ChatHeader/ChatHeader.styles.js | 16 ++++++++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 9143598d30..0986104ae5 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -399,6 +399,9 @@ const ChatHeader = ({
{channelInfo.name || channelName || 'channelName'}
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.styles.js b/packages/react/src/views/ChatHeader/ChatHeader.styles.js
index 46a9ecd32c..5ae8b52647 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.styles.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.styles.js
@@ -18,6 +18,8 @@ const getChatHeaderStyles = ({ theme, mode }) => {
padding: 0 0.75rem;
justify-content: space-between;
width: 100%;
+ flex-wrap: wrap;
+ gap: 0.5rem;
`,
chatHeaderParent: css`
@@ -42,20 +44,30 @@ const getChatHeaderStyles = ({ theme, mode }) => {
channelDescription: css`
${rowCentreAlign}
flex: 1;
- min-width: 0;
+ min-width: 120px;
gap: 0.5rem;
+ overflow: hidden;
`,
chatHeaderIconRow: css`
${rowCentreAlign}
- position:relative;
+ position: relative;
gap: 0.5rem;
+ flex-shrink: 0;
+ @media (max-width: 380px) {
+ gap: 0.25rem;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+ }
`,
channelName: css`
display: flex;
align-items: center;
gap: 0.1rem;
cursor: pointer;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
`,
channelTopic: css`
opacity: 0.8rem;
From 89e85b77224176e1ecb991b4cae8c14b9f56f28f Mon Sep 17 00:00:00 2001
From: Deepak Bhagat <149673145+deepak0x@users.noreply.github.com>
Date: Thu, 22 Jan 2026 01:34:31 +0530
Subject: [PATCH 122/153] fix(api): escape json body in api calls to prevent
injection (#1072)
* fix(api): escape json body in api calls to prevent injection
* fix(api): replace manual JSON string construction with JSON.stringify to prevent injection
- Replaced template literal JSON construction with JSON.stringify() in all API methods
- Fixes vulnerability where user input containing quotes would break JSON structure
- Affected methods: updateMessage, deleteMessage, updateUserUsername, reactToMessage, reportMessage, starMessage, unstarMessage, pinMessage, unpinMessage, updateUserNameThroughSuggestion
---
packages/api/src/EmbeddedChatApi.ts | 30 +++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index f55f55d58f..72e25a0466 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -414,7 +414,10 @@ export default class EmbeddedChatApi {
if (suggestedUsername.success) {
const response2 = await fetch(`${this.host}/api/v1/users.update`, {
- body: `{"userId": "${userid}", "data": { "username": "${suggestedUsername.result}" }}`,
+ body: JSON.stringify({
+ userId: userid,
+ data: { username: suggestedUsername.result },
+ }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
@@ -439,7 +442,10 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/users.update`, {
- body: `{"userId": "${userid}", "data": { "username": "${newUserName}" }}`,
+ body: JSON.stringify({
+ userId: userid,
+ data: { username: newUserName },
+ }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
@@ -776,7 +782,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/chat.delete`, {
- body: `{"roomId": "${this.rid}", "msgId": "${msgId}"}`,
+ body: JSON.stringify({ roomId: this.rid, msgId }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
@@ -794,7 +800,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/chat.update`, {
- body: `{"roomId": "${this.rid}", "msgId": "${msgId}","text" : "${text}" }`,
+ body: JSON.stringify({ roomId: this.rid, msgId, text }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
@@ -854,7 +860,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/chat.starMessage`, {
- body: `{"messageId": "${mid}"}`,
+ body: JSON.stringify({ messageId: mid }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
@@ -872,7 +878,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/chat.unStarMessage`, {
- body: `{"messageId": "${mid}"}`,
+ body: JSON.stringify({ messageId: mid }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
@@ -950,7 +956,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/chat.pinMessage`, {
- body: `{"messageId": "${mid}"}`,
+ body: JSON.stringify({ messageId: mid }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
@@ -970,7 +976,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/chat.unPinMessage`, {
- body: `{"messageId": "${mid}"}`,
+ body: JSON.stringify({ messageId: mid }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
@@ -988,7 +994,11 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/chat.react`, {
- body: `{"messageId": "${messageId}", "emoji": "${emoji}", "shouldReact": ${shouldReact}}`,
+ body: JSON.stringify({
+ messageId,
+ emoji,
+ shouldReact,
+ }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
@@ -1006,7 +1016,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(`${this.host}/api/v1/chat.reportMessage`, {
- body: `{"messageId": "${messageId}", "description": "${description}"}`,
+ body: JSON.stringify({ messageId, description }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
From 52d26b51cec59d11d1cca27fb9afb97082ef7f9d Mon Sep 17 00:00:00 2001
From: Deepak Bhagat <149673145+deepak0x@users.noreply.github.com>
Date: Mon, 9 Feb 2026 10:32:44 +0530
Subject: [PATCH 123/153] fix: infinite render loop in media recorders by
adding missing dependency arrays to useCallback (#1090)
---
packages/react/src/views/ChatInput/AudioMessageRecorder.js | 2 +-
packages/react/src/views/ChatInput/VideoMessageRecoder.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/ChatInput/AudioMessageRecorder.js b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
index 53dbddf4bd..35e8063a52 100644
--- a/packages/react/src/views/ChatInput/AudioMessageRecorder.js
+++ b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
@@ -119,7 +119,7 @@ const AudioMessageRecorder = (props) => {
} catch (error) {
console.warn(error);
}
- });
+ }, []);
useEffect(() => {
handleMount();
diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
index f153d4c697..b45c821757 100644
--- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js
+++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
@@ -86,7 +86,7 @@ const VideoMessageRecorder = (props) => {
} catch (error) {
console.warn(error);
}
- });
+ }, []);
useEffect(() => {
handleMount();
From daf291df7d9e159b67b8b83df501879cee1d5d7b Mon Sep 17 00:00:00 2001
From: "khizar (RinX)" <109973520+Khizarshah01@users.noreply.github.com>
Date: Fri, 13 Mar 2026 09:45:22 +0530
Subject: [PATCH 124/153] feat: add clickable timestamp to quoted messages
(#1089)
---
.../views/AttachmentHandler/TextAttachment.js | 84 +++++++++++++++++--
1 file changed, 79 insertions(+), 5 deletions(-)
diff --git a/packages/react/src/views/AttachmentHandler/TextAttachment.js b/packages/react/src/views/AttachmentHandler/TextAttachment.js
index 73387c7413..1bdd9b602d 100644
--- a/packages/react/src/views/AttachmentHandler/TextAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/TextAttachment.js
@@ -1,4 +1,5 @@
import React, { useState, useContext } from 'react';
+import { format } from 'date-fns';
import { css } from '@emotion/react';
import PropTypes from 'prop-types';
import { Box, Avatar, useTheme, Icon } from '@embeddedchat/ui-elements';
@@ -11,12 +12,11 @@ const FileAttachment = ({
attachment,
host,
type,
- author,
variantStyles = {},
msg,
}) => {
const { RCInstance } = useContext(RCContext);
- const { theme } = useTheme();
+ const { theme, mode } = useTheme();
const [isExpanded, setIsExpanded] = useState(true);
const getUserAvatarUrl = (icon) => {
@@ -28,6 +28,51 @@ const FileAttachment = ({
setIsExpanded((prevState) => !prevState);
};
+ const getMessageIdFromAttachment = (quoteAttachment) => {
+ const link = quoteAttachment?.title_link || quoteAttachment?.message_link;
+ if (!link) return null;
+
+ try {
+ const query = link.includes('?') ? link.split('?')[1] : '';
+ const params = new URLSearchParams(query);
+ return params.get('msg');
+ } catch {
+ return null;
+ }
+ };
+
+ const handleQuoteClick = (quoteAttachment) => {
+ const msgId = getMessageIdFromAttachment(quoteAttachment);
+ if (!msgId) return;
+
+ const element = document.getElementById(`ec-message-body-${msgId}`);
+ if (!element) return;
+
+ const container = element.closest('.ec-message');
+ if (!container) return;
+
+ container.scrollIntoView({ behavior: 'smooth', block: 'center' });
+
+ const highlightColor =
+ mode === 'light' ? theme.colors.warningForeground : theme.colors.warning;
+
+ container.style.transition = 'background-color 1s ease-out';
+ container.style.backgroundColor = highlightColor;
+
+ setTimeout(() => {
+ container.style.backgroundColor = '';
+ }, 2000);
+ };
+
+ const getTimeString = (ts) => {
+ if (!ts) return null;
+ if (typeof ts === 'object' && ts.$date) {
+ ts = ts.$date;
+ }
+ const date = new Date(ts);
+ return !Number.isNaN(date.getTime()) ? format(date, 'h:mm a') : ts;
+ };
+
const formatFileSize = (bytes) => {
if (!bytes || bytes === 0) return '0 B';
@@ -44,9 +89,9 @@ const FileAttachment = ({
return `${size.toFixed(decimals)} ${units[unitIndex]}`;
};
- const getFileSizeWithFormat = (size, format) => {
+ const getFileSizeWithFormat = (size, fileFormat) => {
const formattedSize = formatFileSize(size);
- return format ? `${formattedSize} - ${format}` : formattedSize;
+ return fileFormat ? `${formattedSize} - ${fileFormat}` : formattedSize;
};
return (
@@ -84,6 +129,21 @@ const FileAttachment = ({
size="1.2em"
/>
@{attachment?.author_name}
+ {getTimeString(attachment?.ts) && (
+
handleQuoteClick(attachment)}
+ css={css`
+ font-size: 0.75rem;
+ color: ${theme.colors.mutedForeground};
+ cursor: pointer;
+ &:hover {
+ text-decoration: underline;
+ }
+ `}
+ >
+ {getTimeString(attachment.ts)}
+
+ )}
)}
@@ -217,6 +277,21 @@ const FileAttachment = ({
size="1.2em"
/>
@{nestedAttachment?.author_name}
+ {getTimeString(nestedAttachment?.ts) && (
+
handleQuoteClick(nestedAttachment)}
+ css={css`
+ font-size: 0.75rem;
+ color: ${theme.colors.mutedForeground};
+ cursor: pointer;
+ &:hover {
+ text-decoration: underline;
+ }
+ `}
+ >
+ {getTimeString(nestedAttachment.ts)}
+
+ )}
>
)}
@@ -309,7 +384,6 @@ FileAttachment.propTypes = {
attachment: PropTypes.object,
host: PropTypes.string,
type: PropTypes.string,
- author: PropTypes.object,
variantStyles: PropTypes.object,
msg: PropTypes.object,
};
From 2ccf1901034becc39ca6e9cf2be4f4fdb8213ca6 Mon Sep 17 00:00:00 2001
From: srijna
Date: Sat, 21 Mar 2026 11:11:20 +0530
Subject: [PATCH 125/153] feat: Added max length validation in file upload
modal in file description (#1037)
* feat: added max length validation in file uplode modal in file description
* fetch message limit from RC
* fixed lint format
* implemented review points
* fix: resolve prettier formatting in AttachmentPreview
* remove comments
* fix: remove empty catch block to resolve no-empty lint error
Made-with: Cursor
---
packages/react/src/store/settingsStore.js | 12 +-
.../AttachmentPreview/AttachmentPreview.js | 169 ++++++++++++------
.../react/src/views/ChatHeader/ChatHeader.js | 9 +-
3 files changed, 129 insertions(+), 61 deletions(-)
diff --git a/packages/react/src/store/settingsStore.js b/packages/react/src/store/settingsStore.js
index 4f9d78b687..a8ba42e96b 100644
--- a/packages/react/src/store/settingsStore.js
+++ b/packages/react/src/store/settingsStore.js
@@ -1,8 +1,16 @@
import { create } from 'zustand';
+const DEFAULT_MESSAGE_LIMIT = 5000;
+
const useSettingsStore = create((set) => ({
- messageLimit: 5000,
- setMessageLimit: (messageLimit) => set(() => ({ messageLimit })),
+ messageLimit: DEFAULT_MESSAGE_LIMIT,
+ setMessageLimit: (messageLimit) =>
+ set(() => ({
+ messageLimit:
+ typeof messageLimit === 'number' && Number.isFinite(messageLimit)
+ ? messageLimit
+ : DEFAULT_MESSAGE_LIMIT,
+ })),
}));
export default useSettingsStore;
diff --git a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
index 01123dafbe..e6dadeae61 100644
--- a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
+++ b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
@@ -1,10 +1,18 @@
import React, { useContext, useState, useRef, useEffect } from 'react';
import { css } from '@emotion/react';
-import { Box, Icon, Button, Input, Modal } from '@embeddedchat/ui-elements';
+import {
+ Box,
+ Icon,
+ Button,
+ Input,
+ Modal,
+ useTheme,
+} from '@embeddedchat/ui-elements';
import useAttachmentWindowStore from '../../store/attachmentwindow';
import CheckPreviewType from './CheckPreviewType';
import RCContext from '../../context/RCInstance';
import { useMessageStore, useMemberStore } from '../../store';
+import useSettingsStore from '../../store/settingsStore';
import getAttachmentPreviewStyles from './AttachmentPreview.styles';
import { parseEmoji } from '../../lib/emoji';
import MembersList from '../Mentions/MembersList';
@@ -13,29 +21,30 @@ import useSearchMentionUser from '../../hooks/useSearchMentionUser';
const AttachmentPreview = () => {
const { RCInstance, ECOptions } = useContext(RCContext);
+ const { theme } = useTheme();
const styles = getAttachmentPreviewStyles();
const toggle = useAttachmentWindowStore((state) => state.toggle);
const data = useAttachmentWindowStore((state) => state.data);
const setData = useAttachmentWindowStore((state) => state.setData);
+
const [isPending, setIsPending] = useState(false);
const messageRef = useRef(null);
const [showMembersList, setShowMembersList] = useState(false);
const [filteredMembers, setFilteredMembers] = useState([]);
const [mentionIndex, setMentionIndex] = useState(-1);
const [startReadMentionUser, setStartReadMentionUser] = useState(false);
- const [keyPressed, setKeyPressed] = useState(null);
- const [fileName, setFileName] = useState(data?.name);
+ const [fileName, setFileName] = useState(data?.name ?? '');
+ useEffect(() => setFileName(data?.name ?? ''), [data?.name]);
- const threadId = useMessageStore((state) => state.threadMainMessage?._id);
- const handleFileName = (e) => {
- setFileName(e.target.value);
- };
+ const [description, setDescription] = useState('');
+ const charCount = description.length;
+ const msgMaxLength = useSettingsStore((s) => s?.messageLimit);
+ const isOverLimit = msgMaxLength && charCount > msgMaxLength;
- const { members } = useMemberStore((state) => ({
- members: state.members,
- }));
+ const threadId = useMessageStore((state) => state.threadMainMessage?._id);
+ const { members } = useMemberStore((state) => ({ members: state.members }));
const searchMentionUser = useSearchMentionUser(
members,
@@ -46,47 +55,44 @@ const AttachmentPreview = () => {
setShowMembersList
);
+ const handleFileName = (e) => setFileName(e.target.value);
+
const handleFileDescription = (e) => {
- const description = e.target.value;
- messageRef.current.value = parseEmoji(description);
- searchMentionUser(description);
+ const raw = e.target.value || '';
+ setDescription(raw);
+
+ if (messageRef.current && typeof messageRef.current.value !== 'undefined') {
+ messageRef.current.value = raw;
+ }
+
+ searchMentionUser(raw);
};
const submit = async () => {
+ if (isPending) return;
+ if (msgMaxLength && description.length > msgMaxLength) return;
+
setIsPending(true);
- await RCInstance.sendAttachment(
- data,
- fileName,
- messageRef.current.value,
- ECOptions?.enableThreads ? threadId : undefined
- );
- toggle();
- setData(null);
- if (isPending) {
+ try {
+ await RCInstance.sendAttachment(
+ data,
+ fileName,
+ parseEmoji(description),
+ ECOptions?.enableThreads ? threadId : undefined
+ );
+ toggle();
+ setData(null);
+ } finally {
setIsPending(false);
}
};
- useEffect(() => {
- const keyHandler = (e) => {
- if (e.key === 'Enter') {
- e.preventDefault();
- setKeyPressed('Enter');
- }
- };
-
- document.addEventListener('keydown', keyHandler);
- return () => {
- document.removeEventListener('keydown', keyHandler);
- };
- }, []);
-
- useEffect(() => {
- if (keyPressed === 'Enter') {
+ const onDescKeyDown = (e) => {
+ if (e.key === 'Enter' && !e.shiftKey) {
+ e.preventDefault();
submit();
- setKeyPressed(null);
}
- }, [keyPressed, submit]);
+ };
return (
@@ -98,11 +104,12 @@ const AttachmentPreview = () => {
css={css`
margin-right: 0.5rem;
`}
- />{' '}
+ />
File Upload
+
{
>
+
{
File name
{
- handleFileName(e);
- }}
+ onChange={handleFileName}
value={fileName}
type="text"
css={styles.input}
@@ -150,6 +156,7 @@ const AttachmentPreview = () => {
>
File description
+
{showMembersList && (
@@ -161,21 +168,73 @@ const AttachmentPreview = () => {
setFilteredMembers={setFilteredMembers}
setStartReadMentionUser={setStartReadMentionUser}
setShowMembersList={setShowMembersList}
- css={css`
- width: auto;
- `}
/>
)}
+
{
- handleFileDescription(e);
- }}
+ onChange={handleFileDescription}
+ onKeyDown={onDescKeyDown}
type="text"
- css={styles.input}
placeholder="Description"
ref={messageRef}
+ value={description}
+ css={css`
+ ${styles.input};
+ border-color: ${isOverLimit
+ ? theme.colors.destructive
+ : null};
+ color: ${isOverLimit ? theme.colors.destructive : null};
+ `}
/>
+
+ {msgMaxLength && (
+
+
+ {isOverLimit
+ ? `Cannot upload file, description is over the ${msgMaxLength} character limit`
+ : ''}
+
+
+
+ ({charCount}/{msgMaxLength})
+
+
+ )}
@@ -190,12 +249,8 @@ const AttachmentPreview = () => {
Cancel
- {
- submit();
- }}
- >
+
+
{isPending ? 'Sending...' : 'Send'}
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 0986104ae5..a310e538fd 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -150,8 +150,13 @@ const ChatHeader = ({
useEffect(() => {
const getMessageLimit = async () => {
- const messageLimitObj = await RCInstance.getMessageLimit();
- setMessageLimit(messageLimitObj?.value);
+ try {
+ const messageLimitObj = await RCInstance.getMessageLimit();
+ setMessageLimit(messageLimitObj?.value);
+ } catch (e) {
+ console.error('Failed to fetch message limit', e);
+ setMessageLimit(undefined);
+ }
};
const setMessageAllowed = async () => {
From 46546f3c30cdf97afd10a3e42df63ed6bf4fa4d1 Mon Sep 17 00:00:00 2001
From: Kartik
Date: Sat, 21 Mar 2026 11:36:16 +0530
Subject: [PATCH 126/153] fix: update file upload to use RC 8.x rooms.media API
(#1070)
* fix: update file upload to use RC 8.x rooms.media API
- Replace deprecated rooms.upload endpoint with new two-step process
- Step 1: POST to rooms.media/:rid to upload file
- Step 2: POST to rooms.mediaConfirm/:rid/:fileId to confirm with metadata
- Fixes file upload 404 error on Rocket.Chat 8.x servers
* fix: reset file input after upload to allow re-selecting same file
* style: fix prettier formatting
* fix: resolve variable shadowing in ChatInput.js
* Remove comments
* Remove comments
---------
Co-authored-by: dodaa08
---
packages/api/src/EmbeddedChatApi.ts | 59 ++++++++++++++-----
.../react/src/views/ChatInput/ChatInput.js | 11 +++-
2 files changed, 52 insertions(+), 18 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 72e25a0466..a3549af990 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -1056,26 +1056,53 @@ export default class EmbeddedChatApi {
) {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
- const form = new FormData();
- if (threadId) {
- form.append("tmid", threadId);
+ if (!userId || !authToken) {
+ console.error("sendAttachment: User not authenticated");
+ return;
}
+
+ const form = new FormData();
form.append("file", file, fileName);
- form.append(
- "description",
- fileDescription.length !== 0 ? fileDescription : ""
+
+ const uploadResponse = await fetch(
+ `${this.host}/api/v1/rooms.media/${this.rid}`,
+ {
+ method: "POST",
+ body: form,
+ headers: {
+ "X-Auth-Token": authToken,
+ "X-User-Id": userId,
+ },
+ }
);
- const response = fetch(`${this.host}/api/v1/rooms.upload/${this.rid}`, {
- method: "POST",
- body: form,
- headers: {
- "X-Auth-Token": authToken,
- "X-User-Id": userId,
- },
- }).then((r) => r.json());
- return response;
+
+ const uploadResult = await uploadResponse.json();
+
+ if (!uploadResult.success || !uploadResult.file?._id) {
+ console.error("sendAttachment: Upload failed", uploadResult);
+ return uploadResult;
+ }
+
+ const confirmResponse = await fetch(
+ `${this.host}/api/v1/rooms.mediaConfirm/${this.rid}/${uploadResult.file._id}`,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-Auth-Token": authToken,
+ "X-User-Id": userId,
+ },
+ body: JSON.stringify(
+ threadId
+ ? { msg: "", description: fileDescription || "", tmid: threadId }
+ : { msg: "", description: fileDescription || "" }
+ ),
+ }
+ );
+
+ return await confirmResponse.json();
} catch (err) {
- console.log(err);
+ console.error("sendAttachment error:", err);
}
}
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index e753b689ae..0bdebf322b 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -120,9 +120,10 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
);
const isLoginIn = useLoginStore((state) => state.isLoginIn);
- const { toggle, setData } = useAttachmentWindowStore((state) => ({
+ const { toggle, setData, data } = useAttachmentWindowStore((state) => ({
toggle: state.toggle,
setData: state.setData,
+ data: state.data,
}));
const userInfo = { _id: userId, username, name };
@@ -147,7 +148,7 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
RCInstance.auth.onAuthChange((user) => {
if (user) {
RCInstance.getCommandsList()
- .then((data) => setCommands(data.commands || []))
+ .then((response) => setCommands(response.commands || []))
.catch(console.error);
RCInstance.getChannelMembers(isChannelPrivate)
@@ -184,6 +185,12 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
}
}, [deletedMessage]);
+ useEffect(() => {
+ if (data === null && inputRef.current) {
+ inputRef.current.value = '';
+ }
+ }, [data]);
+
const getMessageLink = async (id) => {
const host = RCInstance.getHost();
const res = await RCInstance.channelInfo();
From 631be797d065fd6681815f26c909eab6166312b6 Mon Sep 17 00:00:00 2001
From: Deepak Bhagat <149673145+deepak0x@users.noreply.github.com>
Date: Sat, 21 Mar 2026 11:48:42 +0530
Subject: [PATCH 127/153] fix: resolve memory leak in MediaRecorder event
listeners (#1077)
---
packages/react/src/hooks/useMediaRecorder.js | 42 ++++++++++++++------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/packages/react/src/hooks/useMediaRecorder.js b/packages/react/src/hooks/useMediaRecorder.js
index 028b0d9b1d..1c79fe20b3 100644
--- a/packages/react/src/hooks/useMediaRecorder.js
+++ b/packages/react/src/hooks/useMediaRecorder.js
@@ -28,19 +28,29 @@ export function useMediaRecorder({ constraints, onStop, videoRef }) {
const stream = await getStream(constraints, true);
chunks.current = [];
const _recorder = new MediaRecorder(stream);
- _recorder.start();
- setRecorder(_recorder);
- _recorder.addEventListener('dataavailable', (event) => {
+
+ const handleDataAvailable = (event) => {
chunks.current.push(event.data);
- });
- _recorder.addEventListener('stop', () => {
+ };
+
+ const handleStop = () => {
onStop && onStop(chunks.current);
- });
+ _recorder.removeEventListener('dataavailable', handleDataAvailable);
+ _recorder.removeEventListener('stop', handleStop);
+ };
+
+ _recorder.addEventListener('dataavailable', handleDataAvailable);
+ _recorder.addEventListener('stop', handleStop);
+
+ _recorder.start();
+ setRecorder(_recorder);
}
async function stop() {
if (recorder) {
- recorder.stop();
+ if (recorder.state !== 'inactive') {
+ recorder.stop();
+ }
(await getStream()).getTracks().forEach((track) => track.stop());
}
}
@@ -77,17 +87,23 @@ export function useNewMediaRecorder({ constraints, videoRef, onStop }) {
chunks.current = [];
const _recorder = new MediaRecorder(stream);
- _recorder.start();
- setRecorder(_recorder);
- _recorder.addEventListener('dataavailable', (event) => {
+ const handleDataAvailable = (event) => {
chunks.current.push(event.data);
- });
+ };
- _recorder.addEventListener('stop', () => {
+ const handleStop = () => {
setRecordingData(new Blob(chunks.current, { type: 'video/mp4' }));
onStop && onStop(chunks.current);
- });
+ _recorder.removeEventListener('dataavailable', handleDataAvailable);
+ _recorder.removeEventListener('stop', handleStop);
+ };
+
+ _recorder.addEventListener('dataavailable', handleDataAvailable);
+ _recorder.addEventListener('stop', handleStop);
+
+ _recorder.start();
+ setRecorder(_recorder);
}
async function stopRecording() {
From 039a3c9a07925697b4bd6032c04b3a83340fb615 Mon Sep 17 00:00:00 2001
From: Deepak Bhagat <149673145+deepak0x@users.noreply.github.com>
Date: Sat, 21 Mar 2026 11:55:48 +0530
Subject: [PATCH 128/153] fix: show edit icon for sequential messages (#1079)
* fix: show edit icon for sequential messages
* style: fix formatting in MessageAvatarContainer
---
packages/react/src/views/Message/Message.styles.js | 6 ++++++
packages/react/src/views/Message/MessageAvatarContainer.js | 5 +++++
2 files changed, 11 insertions(+)
diff --git a/packages/react/src/views/Message/Message.styles.js b/packages/react/src/views/Message/Message.styles.js
index 5cdf333662..03236addbd 100644
--- a/packages/react/src/views/Message/Message.styles.js
+++ b/packages/react/src/views/Message/Message.styles.js
@@ -230,6 +230,12 @@ export const getMessageHeaderStyles = (theme) => {
flex-shrink: 0;
margin-left: 0.25rem;
`,
+ messageStatus: css`
+ display: flex;
+ flex-flow: row nowrap;
+ align-items: center;
+ margin-left: 0.2rem;
+ `,
};
return styles;
diff --git a/packages/react/src/views/Message/MessageAvatarContainer.js b/packages/react/src/views/Message/MessageAvatarContainer.js
index 016bbb0b06..7fdf1b0b8a 100644
--- a/packages/react/src/views/Message/MessageAvatarContainer.js
+++ b/packages/react/src/views/Message/MessageAvatarContainer.js
@@ -60,6 +60,11 @@ const MessageAvatarContainer = ({
) : null}
+ {message.editedAt && sequential ? (
+
+
+
+ ) : null}
{isPinned && sequential ? (
From 37896cb04db6b836d5524026b60e3f25f77c47bc Mon Sep 17 00:00:00 2001
From: Deepak Bhagat <149673145+deepak0x@users.noreply.github.com>
Date: Sat, 21 Mar 2026 11:58:42 +0530
Subject: [PATCH 129/153] fix(auth): validate origin of oauth callback to
prevent login csrf (#1093)
---
packages/auth/src/loginWithRocketChatOAuth.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/packages/auth/src/loginWithRocketChatOAuth.ts b/packages/auth/src/loginWithRocketChatOAuth.ts
index 955e70c7a4..66a553a9f1 100644
--- a/packages/auth/src/loginWithRocketChatOAuth.ts
+++ b/packages/auth/src/loginWithRocketChatOAuth.ts
@@ -45,6 +45,9 @@ width=800,height=600,left=-1000,top=-1000,rel=opener`;
return new Promise((resolve) => {
if (popup) {
const onMessage = async (e: MessageEvent) => {
+ if (e.origin !== new URL(config.api.baseUrl).origin) {
+ return;
+ }
if (e.data.type === "rc-oauth-callback") {
const { accessToken, expiresIn, serviceName } = e.data.credentials;
const response = await config.api.post("/api/v1/login", {
From d3e6ee731ad313d1f601b65d28bf527b90fb9176 Mon Sep 17 00:00:00 2001
From: "khizar (RinX)" <109973520+Khizarshah01@users.noreply.github.com>
Date: Sat, 21 Mar 2026 12:13:48 +0530
Subject: [PATCH 130/153] fix: correctly render nested quotes media attachments
in quotes (#1075)
* fix: correctly render nested media attachments in quotes
* chore: fix formatting in TextAttachment
---
.../AttachmentHandler/AttachmentMetadata.js | 28 +-
.../views/AttachmentHandler/TextAttachment.js | 343 ++++++++++++------
2 files changed, 238 insertions(+), 133 deletions(-)
diff --git a/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js b/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
index 0c4eda27aa..a3a4076f36 100644
--- a/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
+++ b/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
@@ -41,13 +41,15 @@ const AttachmentMetadata = ({
} else if (attachment?.size) {
sizeInBytes = attachment.size;
} else {
- sizeInBytes = 0;
+ return null;
}
const sizeInKB = (sizeInBytes / 1024).toFixed(2);
return `${sizeInKB} kB`;
};
+ const fileSize = getFormattedFileSize();
+
return (
-
- ({getFormattedFileSize()})
-
+ {fileSize && (
+
+ ({fileSize})
+
+ )}
(
-
+ attachment.attachments.map((nestedAttachment, index) => {
+ if (nestedAttachment?.audio_url) {
+ return (
+
+ );
+ }
+ if (nestedAttachment?.video_url) {
+ return (
+
+ );
+ }
+ if (nestedAttachment?.image_url) {
+ return (
+
+ );
+ }
+ // Check for wrapped attachments (mirroring Attachment.js logic)
+ if (nestedAttachment?.attachments?.[0]?.audio_url) {
+ return (
+
+ );
+ }
+ if (nestedAttachment?.attachments?.[0]?.video_url) {
+ return (
+
+ );
+ }
+ if (nestedAttachment?.attachments?.[0]?.image_url) {
+ return (
+
+ );
+ }
+
+ return (
- {nestedAttachment?.author_name && (
- <>
-
- @{nestedAttachment?.author_name}
- {getTimeString(nestedAttachment?.ts) && (
- handleQuoteClick(nestedAttachment)}
- css={css`
- font-size: 0.75rem;
- color: ${theme.colors.mutedForeground};
- cursor: pointer;
- &:hover {
- text-decoration: underline;
- }
- `}
- >
- {getTimeString(nestedAttachment.ts)}
-
- )}
- >
- )}
-
-
-
-
- {isExpanded && (
- {nestedAttachment?.text ? (
- nestedAttachment.text[0] === '[' ? (
- nestedAttachment.text.match(/\n(.*)/)?.[1] || ''
- ) : (
-
+
- )
- ) : (
-
-
-
- @{nestedAttachment?.author_name}
+ {getTimeString(nestedAttachment?.ts) && (
+ handleQuoteClick(nestedAttachment)}
css={css`
- text-decoration: none;
- font-size: 0.875rem;
+ font-size: 0.75rem;
+ color: ${theme.colors.mutedForeground};
+ cursor: pointer;
&:hover {
text-decoration: underline;
}
`}
>
- {nestedAttachment?.title}
-
+ {getTimeString(nestedAttachment.ts)}
+
+ )}
+ >
+ )}
+
+
+ {!nestedAttachment?.text && !nestedAttachment?.attachments && (
+
+ )}
+
+ {isExpanded && (
+
+ {nestedAttachment?.text ? (
+ nestedAttachment.text[0] === '[' ? (
+ nestedAttachment.text.match(/\n(.*)/)?.[1] || ''
+ ) : (
+
+ )
+ ) : (
+
+
- {getFileSizeWithFormat(
- nestedAttachment?.size,
- nestedAttachment?.format
- )}
+
+ {nestedAttachment?.title}
+
+
+ {getFileSizeWithFormat(
+ nestedAttachment?.size,
+ nestedAttachment?.format
+ )}
+
-
- )}
-
- )}
-
- ))}
+ )}
+
+ )}
+
+ );
+ })}
);
From 10c86efa68523e0c819b914aa341ea977b093d80 Mon Sep 17 00:00:00 2001
From: R Pratheek <111165032+Pratheek555@users.noreply.github.com>
Date: Sat, 21 Mar 2026 12:15:14 +0530
Subject: [PATCH 131/153] Initial fix logic (#1085)
---
.../src/components/ToastBar/ToastBar.js | 12 +++++++--
.../components/ToastBar/ToastBar.styles.js | 4 ++-
.../components/ToastBar/ToastBarProvider.js | 6 ++++-
.../src/components/ToastBar/ToastContainer.js | 27 ++++++++++++-------
4 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/packages/ui-elements/src/components/ToastBar/ToastBar.js b/packages/ui-elements/src/components/ToastBar/ToastBar.js
index 71ea53a9d8..dcec7d6f5f 100644
--- a/packages/ui-elements/src/components/ToastBar/ToastBar.js
+++ b/packages/ui-elements/src/components/ToastBar/ToastBar.js
@@ -11,6 +11,7 @@ import useTheme from '../../hooks/useTheme';
const ToastBar = ({ toast, onClose }) => {
const { type, message, time = 2000 } = toast;
const toastRef = useRef();
+ const latestOnClose = useRef(onClose);
const { theme } = useTheme();
const { classNames, styleOverrides } = useComponentOverrides('ToastBar');
@@ -42,8 +43,15 @@ const ToastBar = ({ toast, onClose }) => {
}, [theme.colors, type]);
useEffect(() => {
- setTimeout(onClose, time);
- }, [onClose, time]);
+ latestOnClose.current = onClose;
+ }, [onClose]);
+
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ latestOnClose.current?.();
+ }, time);
+ return () => clearTimeout(timer);
+ }, [time]);
return (
{
position: absolute;
z-index: ${theme.zIndex?.toastbar || 1600};
border-radius: ${theme.radius};
- animation: ${animation} ${2000}ms ease-in-out forwards;
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
`,
};
return styles;
diff --git a/packages/ui-elements/src/components/ToastBar/ToastBarProvider.js b/packages/ui-elements/src/components/ToastBar/ToastBarProvider.js
index c3507ad61a..1455351ee9 100644
--- a/packages/ui-elements/src/components/ToastBar/ToastBarProvider.js
+++ b/packages/ui-elements/src/components/ToastBar/ToastBarProvider.js
@@ -6,7 +6,11 @@ const ToastBarProvider = ({ position = 'bottom right', children }) => {
const [toasts, setToasts] = useState([]);
const dispatchToast = useCallback(
(toast) => {
- setToasts((prevToasts) => [toast, ...prevToasts]);
+ const withId = {
+ id: toast.id || `${Date.now()}-${Math.random().toString(36).slice(2)}`,
+ ...toast,
+ };
+ setToasts((prevToasts) => [withId, ...prevToasts]);
},
[setToasts]
);
diff --git a/packages/ui-elements/src/components/ToastBar/ToastContainer.js b/packages/ui-elements/src/components/ToastBar/ToastContainer.js
index d417b6d67f..a382444a39 100644
--- a/packages/ui-elements/src/components/ToastBar/ToastContainer.js
+++ b/packages/ui-elements/src/components/ToastBar/ToastContainer.js
@@ -9,6 +9,7 @@ const ToastContainer = () => {
const { theme } = useTheme();
const styles = getToastBarContainerStyles(theme);
const { position, toasts, setToasts } = useContext(ToastContext);
+
const positionStyle = useMemo(() => {
const positions = position.split(/\s+/);
const styleAnchor = {};
@@ -17,21 +18,29 @@ const ToastContainer = () => {
});
return styleAnchor;
}, [position]);
- const currentToast = useMemo(() => {
- const toast = toasts[toasts.length - 1];
- return toast;
- }, [toasts]);
- const onClose = useCallback(() => {
- setToasts(toasts.slice(0, toasts.length - 1));
- }, [setToasts, toasts]);
- if (!currentToast) {
+ const stackedToasts = useMemo(() => [...toasts].reverse(), [toasts]);
+
+ const handleClose = useCallback(
+ (id) => {
+ setToasts((prevItems) => prevItems.filter((toast) => toast.id !== id));
+ },
+ [setToasts]
+ );
+
+ if (!stackedToasts.length) {
return null;
}
return (
-
+ {stackedToasts.map((toast) => (
+ handleClose(toast.id)}
+ />
+ ))}
);
};
From 7734fd0e85b903bbb6420359b0b5c05fcf4c0fc0 Mon Sep 17 00:00:00 2001
From: R Pratheek <111165032+Pratheek555@users.noreply.github.com>
Date: Sat, 21 Mar 2026 12:17:38 +0530
Subject: [PATCH 132/153] Intial logic for tooltip label position (#1087)
---
.../layout_editor/src/components/SurfaceMenu/SurfaceItem.jsx | 2 +-
packages/react/src/views/SurfaceMenu/SurfaceItem.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/layout_editor/src/components/SurfaceMenu/SurfaceItem.jsx b/packages/layout_editor/src/components/SurfaceMenu/SurfaceItem.jsx
index 4a4f47f231..caeb77ec37 100644
--- a/packages/layout_editor/src/components/SurfaceMenu/SurfaceItem.jsx
+++ b/packages/layout_editor/src/components/SurfaceMenu/SurfaceItem.jsx
@@ -18,7 +18,7 @@ const SurfaceItem = ({
onRemove,
type,
cursor = 'grab',
- tooltipPosition = 'bottom',
+ tooltipPosition = 'top',
size,
}) => {
const { attributes, listeners, setNodeRef, transform, isDragging } =
diff --git a/packages/react/src/views/SurfaceMenu/SurfaceItem.js b/packages/react/src/views/SurfaceMenu/SurfaceItem.js
index 9674ead1cf..f9f061b8b8 100644
--- a/packages/react/src/views/SurfaceMenu/SurfaceItem.js
+++ b/packages/react/src/views/SurfaceMenu/SurfaceItem.js
@@ -2,7 +2,7 @@ import React from 'react';
import { Tooltip, ActionButton } from '@embeddedchat/ui-elements';
const SurfaceItem = ({ item, size }) => (
-
+
Date: Sat, 21 Mar 2026 12:20:20 +0530
Subject: [PATCH 133/153] feat: Add Emoji Autocomplete functionality that
displays matching emoji suggestions on : colon type (#1015)
* Add emoji autocomplete functionality that displays matching emoji suggestions when users type ':' followed by at least 2 characters, similar to existing mention and command autocomplete features
* Theme refinement
* Prettier formatting #1
* Prettier Formatting #2
---
packages/react/src/hooks/useSearchEmoji.js | 67 +++
packages/react/src/lib/emojiList.js | 464 ++++++++++++++++++
.../react/src/views/ChatInput/ChatInput.js | 35 +-
.../react/src/views/EmojiList/EmojiList.js | 162 ++++++
.../src/views/EmojiList/EmojiList.styles.js | 53 ++
packages/react/src/views/EmojiList/index.js | 1 +
6 files changed, 780 insertions(+), 2 deletions(-)
create mode 100644 packages/react/src/hooks/useSearchEmoji.js
create mode 100644 packages/react/src/lib/emojiList.js
create mode 100644 packages/react/src/views/EmojiList/EmojiList.js
create mode 100644 packages/react/src/views/EmojiList/EmojiList.styles.js
create mode 100644 packages/react/src/views/EmojiList/index.js
diff --git a/packages/react/src/hooks/useSearchEmoji.js b/packages/react/src/hooks/useSearchEmoji.js
new file mode 100644
index 0000000000..7112fc3d81
--- /dev/null
+++ b/packages/react/src/hooks/useSearchEmoji.js
@@ -0,0 +1,67 @@
+import { useCallback } from 'react';
+import emojiList from '../lib/emojiList';
+
+const useSearchEmoji = (
+ startReadEmoji,
+ setStartReadEmoji,
+ setFilteredEmojis,
+ setEmojiIndex,
+ setShowEmojiList
+) =>
+ useCallback(
+ (message) => {
+ const lastChar = message ? message[message.length - 1] : '';
+
+ if (message.length === 0) {
+ setShowEmojiList(false);
+ setStartReadEmoji(false);
+ setFilteredEmojis([]);
+ setEmojiIndex(-1);
+ return;
+ }
+
+ // Check if user is typing emoji syntax (:emoji:)
+ const emojiMatch = message.match(/:([a-zA-Z0-9_+-]*?)$/);
+
+ if (emojiMatch) {
+ const query = emojiMatch[1].toLowerCase();
+
+ // Only show suggestions if query is at least 2 characters
+ if (query.length >= 2) {
+ setStartReadEmoji(true);
+
+ const filteredEmojis = emojiList
+ .filter(
+ (emoji) =>
+ emoji.shortname.toLowerCase().includes(query) ||
+ emoji.aliases.some((alias) =>
+ alias.toLowerCase().includes(query)
+ )
+ )
+ .slice(0, 10);
+
+ setFilteredEmojis(filteredEmojis);
+ setEmojiIndex(filteredEmojis.length > 0 ? 0 : -1);
+ setShowEmojiList(filteredEmojis.length > 0);
+ } else {
+ setShowEmojiList(false);
+ setFilteredEmojis([]);
+ setEmojiIndex(-1);
+ }
+ } else if (startReadEmoji) {
+ setStartReadEmoji(false);
+ setFilteredEmojis([]);
+ setEmojiIndex(-1);
+ setShowEmojiList(false);
+ }
+ },
+ [
+ startReadEmoji,
+ setStartReadEmoji,
+ setFilteredEmojis,
+ setEmojiIndex,
+ setShowEmojiList,
+ ]
+ );
+
+export default useSearchEmoji;
diff --git a/packages/react/src/lib/emojiList.js b/packages/react/src/lib/emojiList.js
new file mode 100644
index 0000000000..4aa794a7a0
--- /dev/null
+++ b/packages/react/src/lib/emojiList.js
@@ -0,0 +1,464 @@
+// Comprehensive list of popular emojis with emoji-toolkit compatible shortnames
+// Based on the most commonly used emojis and matching Rocket.Chat's emoji autocomplete
+
+const emojiList = [
+ // Popular smileys and emotions
+ { shortname: 'smile', emoji: '😊', aliases: ['happy', 'grinning'] },
+ { shortname: 'laughing', emoji: '😂', aliases: ['joy', 'tears'] },
+ { shortname: 'heart_eyes', emoji: '😍', aliases: ['love', 'heart'] },
+ { shortname: 'kissing_heart', emoji: '😘', aliases: ['kiss', 'love'] },
+ { shortname: 'wink', emoji: '😉', aliases: ['winking'] },
+ { shortname: 'blush', emoji: '😊', aliases: ['smiling', 'happy'] },
+ { shortname: 'grinning', emoji: '😀', aliases: ['grin', 'happy'] },
+ { shortname: 'grin', emoji: '😁', aliases: ['grinning', 'happy'] },
+ { shortname: 'joy', emoji: '😂', aliases: ['laughing', 'tears'] },
+ { shortname: 'smiley', emoji: '😃', aliases: ['happy', 'grinning'] },
+ { shortname: 'smirk', emoji: '😏', aliases: ['smirking'] },
+ { shortname: 'relaxed', emoji: '☺️', aliases: ['smile', 'happy'] },
+ {
+ shortname: 'stuck_out_tongue',
+ emoji: '😛',
+ aliases: ['tongue', 'playful'],
+ },
+ {
+ shortname: 'stuck_out_tongue_winking_eye',
+ emoji: '😜',
+ aliases: ['wink', 'tongue'],
+ },
+ {
+ shortname: 'stuck_out_tongue_closed_eyes',
+ emoji: '😝',
+ aliases: ['tongue', 'playful'],
+ },
+ { shortname: 'kissing', emoji: '😗', aliases: ['kiss'] },
+ {
+ shortname: 'kissing_smiling_eyes',
+ emoji: '😙',
+ aliases: ['kiss', 'happy'],
+ },
+ { shortname: 'kissing_closed_eyes', emoji: '😚', aliases: ['kiss', 'love'] },
+ { shortname: 'yum', emoji: '😋', aliases: ['delicious', 'tasty'] },
+ { shortname: 'relieved', emoji: '😌', aliases: ['relief', 'sigh'] },
+ { shortname: 'hugs', emoji: '🤗', aliases: ['hugging'] },
+ { shortname: 'thinking', emoji: '🤔', aliases: ['thought', 'considering'] },
+ { shortname: 'neutral_face', emoji: '😐', aliases: ['neutral', 'meh'] },
+ { shortname: 'expressionless', emoji: '😑', aliases: ['blank', 'neutral'] },
+ { shortname: 'no_mouth', emoji: '😶', aliases: ['mute', 'silent'] },
+ { shortname: 'rolling_eyes', emoji: '🙄', aliases: ['eyeroll', 'sarcasm'] },
+ { shortname: 'smiling_imp', emoji: '😈', aliases: ['devil', 'evil'] },
+ { shortname: 'imp', emoji: '👿', aliases: ['devil', 'evil'] },
+ { shortname: 'japanese_ogre', emoji: '👹', aliases: ['monster', 'ogre'] },
+ { shortname: 'japanese_goblin', emoji: '👺', aliases: ['goblin', 'monster'] },
+ { shortname: 'skull', emoji: '💀', aliases: ['death', 'dead'] },
+ { shortname: 'ghost', emoji: '👻', aliases: ['spooky', 'halloween'] },
+ { shortname: 'alien', emoji: '👽', aliases: ['ufo', 'extraterrestrial'] },
+ { shortname: 'robot', emoji: '🤖', aliases: ['bot', 'automation'] },
+ { shortname: 'smiley_cat', emoji: '😸', aliases: ['cat', 'happy'] },
+ { shortname: 'smile_cat', emoji: '😹', aliases: ['cat', 'laughing'] },
+ { shortname: 'joy_cat', emoji: '😻', aliases: ['cat', 'love'] },
+ { shortname: 'heart_eyes_cat', emoji: '😻', aliases: ['cat', 'love'] },
+ { shortname: 'smirk_cat', emoji: '😼', aliases: ['cat', 'smirk'] },
+ { shortname: 'kissing_cat', emoji: '😽', aliases: ['cat', 'kiss'] },
+ { shortname: 'scream_cat', emoji: '🙀', aliases: ['cat', 'scared'] },
+ { shortname: 'crying_cat_face', emoji: '😿', aliases: ['cat', 'cry', 'sad'] },
+ { shortname: 'pouting_cat', emoji: '😾', aliases: ['cat', 'angry'] },
+
+ // Hand gestures
+ { shortname: 'thumbsup', emoji: '👍', aliases: ['yes', 'good', 'approve'] },
+ {
+ shortname: 'thumbsdown',
+ emoji: '👎',
+ aliases: ['no', 'bad', 'disapprove'],
+ },
+ { shortname: 'clap', emoji: '👏', aliases: ['applause', 'bravo'] },
+ { shortname: 'open_hands', emoji: '👐', aliases: ['open', 'hands'] },
+ { shortname: 'palms_up_together', emoji: '🤲', aliases: ['prayer', 'hands'] },
+ { shortname: 'handshake', emoji: '🤝', aliases: ['deal', 'agreement'] },
+ { shortname: 'pray', emoji: '🙏', aliases: ['please', 'thanks', 'hope'] },
+ { shortname: 'writing_hand', emoji: '✍️', aliases: ['write', 'signature'] },
+ { shortname: 'nail_care', emoji: '💅', aliases: ['nail', 'polish'] },
+ { shortname: 'selfie', emoji: '🤳', aliases: ['camera', 'photo'] },
+ { shortname: 'muscle', emoji: '💪', aliases: ['strong', 'flex', 'biceps'] },
+ { shortname: 'mechanical_arm', emoji: '🦾', aliases: ['arm', 'robot'] },
+ { shortname: 'mechanical_leg', emoji: '🦿', aliases: ['leg', 'robot'] },
+ { shortname: 'leg', emoji: '🦵', aliases: ['kick', 'limb'] },
+ { shortname: 'foot', emoji: '🦶', aliases: ['kick', 'limb'] },
+ { shortname: 'ear', emoji: '👂', aliases: ['listen', 'hear'] },
+ {
+ shortname: 'ear_with_hearing_aid',
+ emoji: '🦻',
+ aliases: ['hearing', 'aid'],
+ },
+ { shortname: 'nose', emoji: '👃', aliases: ['smell', 'sniff'] },
+ { shortname: 'brain', emoji: '🧠', aliases: ['think', 'smart'] },
+ { shortname: 'anatomical_heart', emoji: '🫀', aliases: ['heart', 'health'] },
+ { shortname: 'lungs', emoji: '🫁', aliases: ['breath', 'health'] },
+ { shortname: 'tooth', emoji: '🦷', aliases: ['dental', 'health'] },
+ { shortname: 'bone', emoji: '🦴', aliases: ['skeleton', 'health'] },
+ { shortname: 'eyes', emoji: '👀', aliases: ['see', 'look', 'watch'] },
+ { shortname: 'eye', emoji: '👁️', aliases: ['see', 'look'] },
+ { shortname: 'tongue', emoji: '👅', aliases: ['taste', 'lick'] },
+ { shortname: 'lips', emoji: '👄', aliases: ['kiss', 'mouth'] },
+
+ // Hearts and symbols
+ { shortname: 'heart', emoji: '❤️', aliases: ['love', 'red'] },
+ { shortname: 'orange_heart', emoji: '🧡', aliases: ['love', 'orange'] },
+ { shortname: 'yellow_heart', emoji: '💛', aliases: ['love', 'yellow'] },
+ { shortname: 'green_heart', emoji: '💚', aliases: ['love', 'green'] },
+ { shortname: 'blue_heart', emoji: '💙', aliases: ['love', 'blue'] },
+ { shortname: 'purple_heart', emoji: '💜', aliases: ['love', 'purple'] },
+ { shortname: 'black_heart', emoji: '🖤', aliases: ['love', 'black'] },
+ { shortname: 'white_heart', emoji: '🤍', aliases: ['love', 'white'] },
+ { shortname: 'brown_heart', emoji: '🤎', aliases: ['love', 'brown'] },
+ { shortname: 'broken_heart', emoji: '💔', aliases: ['sad', 'broken'] },
+ {
+ shortname: 'heart_exclamation',
+ emoji: '❣️',
+ aliases: ['love', 'exclamation'],
+ },
+ { shortname: 'two_hearts', emoji: '💕', aliases: ['love', 'two'] },
+ {
+ shortname: 'revolving_hearts',
+ emoji: '💞',
+ aliases: ['love', 'revolving'],
+ },
+ { shortname: 'heartbeat', emoji: '💓', aliases: ['love', 'beat'] },
+ { shortname: 'heartpulse', emoji: '💗', aliases: ['love', 'pulse'] },
+ { shortname: 'heart_eyes', emoji: '😍', aliases: ['love', 'heart'] },
+ { shortname: 'sparkling_heart', emoji: '💖', aliases: ['love', 'sparkle'] },
+ { shortname: 'cupid', emoji: '💘', aliases: ['love', 'arrow'] },
+ { shortname: 'gift_heart', emoji: '💝', aliases: ['love', 'gift'] },
+ {
+ shortname: 'heart_decoration',
+ emoji: '💟',
+ aliases: ['love', 'decoration'],
+ },
+ { shortname: 'peace_symbol', emoji: '☮️', aliases: ['peace', 'symbol'] },
+ { shortname: 'latin_cross', emoji: '✝️', aliases: ['cross', 'christian'] },
+ { shortname: 'star_and_crescent', emoji: '☪️', aliases: ['islam', 'muslim'] },
+ { shortname: 'om', emoji: '🕉️', aliases: ['hindu', 'om'] },
+ {
+ shortname: 'wheel_of_dharma',
+ emoji: '☸️',
+ aliases: ['buddhism', 'dharma'],
+ },
+ { shortname: 'star_of_david', emoji: '✡️', aliases: ['judaism', 'star'] },
+ { shortname: 'six_pointed_star', emoji: '🔯', aliases: ['star', 'jewish'] },
+ { shortname: 'menorah', emoji: '🕎', aliases: ['hanukkah', 'candles'] },
+ { shortname: 'yin_yang', emoji: '☯️', aliases: ['balance', 'tao'] },
+ { shortname: 'orthodox_cross', emoji: '☦️', aliases: ['christian', 'cross'] },
+ {
+ shortname: 'place_of_worship',
+ emoji: '🛐',
+ aliases: ['worship', 'religion'],
+ },
+ { shortname: 'ophiuchus', emoji: '⛎', aliases: ['snake', 'zodiac'] },
+ { shortname: 'aries', emoji: '♈', aliases: ['ram', 'zodiac'] },
+ { shortname: 'taurus', emoji: '♉', aliases: ['bull', 'zodiac'] },
+ { shortname: 'gemini', emoji: '♊', aliases: ['twins', 'zodiac'] },
+ { shortname: 'cancer', emoji: '♋', aliases: ['crab', 'zodiac'] },
+ { shortname: 'leo', emoji: '♌', aliases: ['lion', 'zodiac'] },
+ { shortname: 'virgo', emoji: '♍', aliases: ['maiden', 'zodiac'] },
+ { shortname: 'libra', emoji: '♎', aliases: ['scales', 'zodiac'] },
+ { shortname: 'scorpius', emoji: '♏', aliases: ['scorpion', 'zodiac'] },
+ { shortname: 'sagittarius', emoji: '♐', aliases: ['archer', 'zodiac'] },
+ { shortname: 'capricorn', emoji: '♑', aliases: ['goat', 'zodiac'] },
+ { shortname: 'aquarius', emoji: '♒', aliases: ['water', 'zodiac'] },
+ { shortname: 'pisces', emoji: '♓', aliases: ['fish', 'zodiac'] },
+ { shortname: 'id', emoji: '🆔', aliases: ['identification', 'id'] },
+ { shortname: 'atom_symbol', emoji: '⚛️', aliases: ['atom', 'science'] },
+ { shortname: 'u7a7a', emoji: '🈳', aliases: ['japanese', 'empty'] },
+ { shortname: 'u5272', emoji: '🈹', aliases: ['japanese', 'discount'] },
+ {
+ shortname: 'radioactive',
+ emoji: '☢️',
+ aliases: ['nuclear', 'radioactive'],
+ },
+ { shortname: 'biohazard', emoji: '☣️', aliases: ['danger', 'biohazard'] },
+ { shortname: 'mobile_phone_off', emoji: '📴', aliases: ['off', 'phone'] },
+ { shortname: 'vibration_mode', emoji: '📳', aliases: ['vibrate', 'phone'] },
+ { shortname: 'u6709', emoji: '🈶', aliases: ['japanese', 'available'] },
+ { shortname: 'u7121', emoji: '🈚', aliases: ['japanese', 'not'] },
+ { shortname: 'u7533', emoji: '🈸', aliases: ['japanese', 'application'] },
+ { shortname: 'u55b6', emoji: '🈺', aliases: ['japanese', 'open'] },
+ { shortname: 'u6708', emoji: '🈷️', aliases: ['japanese', 'monthly'] },
+ {
+ shortname: 'eight_pointed_black_star',
+ emoji: '✴️',
+ aliases: ['star', 'eight'],
+ },
+ { shortname: 'vs', emoji: '🆚', aliases: ['versus', 'vs'] },
+ { shortname: 'accept', emoji: '🉑', aliases: ['japanese', 'acceptable'] },
+ { shortname: 'white_flower', emoji: '💮', aliases: ['flower', 'white'] },
+ {
+ shortname: 'ideograph_advantage',
+ emoji: '🉐',
+ aliases: ['japanese', 'advantage'],
+ },
+ { shortname: 'secret', emoji: '㊙️', aliases: ['japanese', 'secret'] },
+ {
+ shortname: 'congratulations',
+ emoji: '㊗️',
+ aliases: ['japanese', 'congratulations'],
+ },
+ { shortname: 'u5408', emoji: '🈴', aliases: ['japanese', 'congratulation'] },
+ { shortname: 'u6e80', emoji: '🈵', aliases: ['japanese', 'full'] },
+ { shortname: 'u7981', emoji: '🈲', aliases: ['japanese', 'prohibited'] },
+ { shortname: 'a', emoji: '🅰️', aliases: ['blood', 'type'] },
+ { shortname: 'b', emoji: '🅱️', aliases: ['blood', 'type'] },
+ { shortname: 'ab', emoji: '🆎', aliases: ['blood', 'type'] },
+ { shortname: 'cl', emoji: '🆑', aliases: ['clear', 'clear'] },
+ { shortname: 'o2', emoji: '🅾️', aliases: ['blood', 'type'] },
+ { shortname: 'sos', emoji: '🆘', aliases: ['help', 'emergency'] },
+ { shortname: 'no_entry', emoji: '⛔', aliases: ['no', 'entry'] },
+ { shortname: 'name_badge', emoji: '📛', aliases: ['name', 'badge'] },
+ { shortname: 'no_entry_sign', emoji: '🚫', aliases: ['no', 'entry'] },
+ { shortname: 'x', emoji: '❌', aliases: ['no', 'cross'] },
+ { shortname: 'o', emoji: '⭕', aliases: ['yes', 'circle'] },
+ { shortname: 'stop_sign', emoji: '🛑', aliases: ['stop', 'sign'] },
+ { shortname: 'anger', emoji: '💢', aliases: ['angry', 'mad'] },
+ { shortname: 'hotsprings', emoji: '♨️', aliases: ['hot', 'springs'] },
+ { shortname: 'no_pedestrians', emoji: '🚷', aliases: ['no', 'pedestrians'] },
+ { shortname: 'do_not_litter', emoji: '🚯', aliases: ['no', 'litter'] },
+ { shortname: 'no_bicycles', emoji: '🚳', aliases: ['no', 'bicycles'] },
+ { shortname: 'non-potable_water', emoji: '🚱', aliases: ['no', 'water'] },
+ { shortname: 'underage', emoji: '🔞', aliases: ['underage', '18'] },
+ { shortname: 'no_mobile_phones', emoji: '📵', aliases: ['no', 'phone'] },
+ {
+ shortname: 'exclamation',
+ emoji: '❗',
+ aliases: ['exclamation', 'warning'],
+ },
+ {
+ shortname: 'grey_exclamation',
+ emoji: '❕',
+ aliases: ['exclamation', 'grey'],
+ },
+ { shortname: 'question', emoji: '❓', aliases: ['question', 'help'] },
+ { shortname: 'grey_question', emoji: '❔', aliases: ['question', 'grey'] },
+ { shortname: 'bangbang', emoji: '‼️', aliases: ['exclamation', 'double'] },
+ {
+ shortname: 'interrobang',
+ emoji: '⁉️',
+ aliases: ['exclamation', 'question'],
+ },
+ { shortname: '100', emoji: '💯', aliases: ['hundred', 'perfect'] },
+ { shortname: 'low_brightness', emoji: '🔅', aliases: ['dim', 'brightness'] },
+ {
+ shortname: 'high_brightness',
+ emoji: '🔆',
+ aliases: ['bright', 'brightness'],
+ },
+ { shortname: 'trident', emoji: '🔱', aliases: ['trident', 'fork'] },
+ { shortname: 'fleur_de_lis', emoji: '⚜️', aliases: ['fleur', 'lily'] },
+ {
+ shortname: 'part_alternation_mark',
+ emoji: '〽️',
+ aliases: ['japanese', 'part'],
+ },
+ { shortname: 'warning', emoji: '⚠️', aliases: ['warning', 'caution'] },
+ {
+ shortname: 'children_crossing',
+ emoji: '🚸',
+ aliases: ['children', 'crossing'],
+ },
+ { shortname: 'beginner', emoji: '🔰', aliases: ['beginner', 'leaf'] },
+ { shortname: 'recycle', emoji: '♻️', aliases: ['recycle', 'green'] },
+ { shortname: 'u6307', emoji: '🈯', aliases: ['japanese', 'point'] },
+ { shortname: 'chart', emoji: '💹', aliases: ['chart', 'yen'] },
+ { shortname: 'sparkle', emoji: '✨', aliases: ['sparkle', 'shine'] },
+ {
+ shortname: 'eight_spoked_asterisk',
+ emoji: '✳️',
+ aliases: ['asterisk', 'eight'],
+ },
+ {
+ shortname: 'negative_squared_cross_mark',
+ emoji: '❎',
+ aliases: ['no', 'cross'],
+ },
+ { shortname: 'white_check_mark', emoji: '✅', aliases: ['yes', 'check'] },
+ {
+ shortname: 'diamond_shape_with_a_dot_inside',
+ emoji: '💠',
+ aliases: ['diamond', 'dot'],
+ },
+ { shortname: 'cyclone', emoji: '🌀', aliases: ['cyclone', 'spiral'] },
+ { shortname: 'loop', emoji: '➿', aliases: ['loop', 'curly'] },
+ {
+ shortname: 'globe_with_meridians',
+ emoji: '🌐',
+ aliases: ['globe', 'world'],
+ },
+ { shortname: 'm', emoji: 'Ⓜ️', aliases: ['metro', 'm'] },
+ { shortname: 'atm', emoji: '🏧', aliases: ['atm', 'cash'] },
+ { shortname: 'sa', emoji: '🈂️', aliases: ['japanese', 'service'] },
+ {
+ shortname: 'passport_control',
+ emoji: '🛂',
+ aliases: ['passport', 'control'],
+ },
+ { shortname: 'customs', emoji: '🛃', aliases: ['customs', 'border'] },
+ { shortname: 'baggage_claim', emoji: '🛄', aliases: ['baggage', 'claim'] },
+ { shortname: 'left_luggage', emoji: '🛅', aliases: ['left', 'luggage'] },
+ {
+ shortname: 'wheelchair',
+ emoji: '♿',
+ aliases: ['wheelchair', 'accessibility'],
+ },
+ { shortname: 'no_smoking', emoji: '🚭', aliases: ['no', 'smoking'] },
+ { shortname: 'wc', emoji: '🚾', aliases: ['toilet', 'wc'] },
+ { shortname: 'parking', emoji: '🅿️', aliases: ['parking', 'p'] },
+ { shortname: 'potable_water', emoji: '🚰', aliases: ['water', 'drinking'] },
+ { shortname: 'mens', emoji: '🚹', aliases: ['men', 'male'] },
+ { shortname: 'womens', emoji: '🚺', aliases: ['women', 'female'] },
+ { shortname: 'baby_symbol', emoji: '🚼', aliases: ['baby', 'symbol'] },
+ { shortname: 'restroom', emoji: '🚻', aliases: ['restroom', 'toilet'] },
+ {
+ shortname: 'put_litter_in_its_place',
+ emoji: '🚮',
+ aliases: ['litter', 'bin'],
+ },
+ { shortname: 'cinema', emoji: '🎦', aliases: ['cinema', 'movie'] },
+ {
+ shortname: 'signal_strength',
+ emoji: '📶',
+ aliases: ['signal', 'strength'],
+ },
+ { shortname: 'koko', emoji: '🈁', aliases: ['japanese', 'here'] },
+ { shortname: 'ng', emoji: '🆖', aliases: ['ng', 'no'] },
+ { shortname: 'ok', emoji: '🆗', aliases: ['ok', 'okay'] },
+ { shortname: 'up', emoji: '🆙', aliases: ['up', 'arrow'] },
+ { shortname: 'cool', emoji: '🆒', aliases: ['cool', 'fresh'] },
+ { shortname: 'new', emoji: '🆕', aliases: ['new', 'fresh'] },
+ { shortname: 'free', emoji: '🆓', aliases: ['free', 'complimentary'] },
+ { shortname: 'zero', emoji: '0️⃣', aliases: ['zero', '0'] },
+ { shortname: 'one', emoji: '1️⃣', aliases: ['one', '1'] },
+ { shortname: 'two', emoji: '2️⃣', aliases: ['two', '2'] },
+ { shortname: 'three', emoji: '3️⃣', aliases: ['three', '3'] },
+ { shortname: 'four', emoji: '4️⃣', aliases: ['four', '4'] },
+ { shortname: 'five', emoji: '5️⃣', aliases: ['five', '5'] },
+ { shortname: 'six', emoji: '6️⃣', aliases: ['six', '6'] },
+ { shortname: 'seven', emoji: '7️⃣', aliases: ['seven', '7'] },
+ { shortname: 'eight', emoji: '8️⃣', aliases: ['eight', '8'] },
+ { shortname: 'nine', emoji: '9️⃣', aliases: ['nine', '9'] },
+ { shortname: 'keycap_ten', emoji: '🔟', aliases: ['ten', '10'] },
+
+ // Additional popular emojis
+ { shortname: 'fire', emoji: '🔥', aliases: ['hot', 'flame'] },
+ { shortname: 'boom', emoji: '💥', aliases: ['explosion', 'bang'] },
+ { shortname: 'collision', emoji: '💥', aliases: ['explosion', 'bang'] },
+ { shortname: 'sweat_drops', emoji: '💦', aliases: ['water', 'drops'] },
+ { shortname: 'droplet', emoji: '💧', aliases: ['water', 'drop'] },
+ { shortname: 'dash', emoji: '💨', aliases: ['wind', 'fast'] },
+ { shortname: 'hole', emoji: '🕳️', aliases: ['hole', 'dark'] },
+ { shortname: 'bomb', emoji: '💣', aliases: ['bomb', 'explosive'] },
+ { shortname: 'speech_balloon', emoji: '💬', aliases: ['speech', 'bubble'] },
+ { shortname: 'eye_speech_bubble', emoji: '👁️🗨️', aliases: ['eye', 'speech'] },
+ { shortname: 'left_speech_bubble', emoji: '🗨️', aliases: ['left', 'speech'] },
+ { shortname: 'right_anger_bubble', emoji: '🗯️', aliases: ['right', 'anger'] },
+ { shortname: 'thought_balloon', emoji: '💭', aliases: ['thought', 'bubble'] },
+ { shortname: 'zzz', emoji: '💤', aliases: ['sleep', 'tired'] },
+ { shortname: 'wave', emoji: '👋', aliases: ['hello', 'goodbye'] },
+ { shortname: 'raised_back_of_hand', emoji: '🤚', aliases: ['stop', 'hand'] },
+ {
+ shortname: 'raised_hand_with_fingers_splayed',
+ emoji: '🖐️',
+ aliases: ['stop', 'hand'],
+ },
+ { shortname: 'hand', emoji: '✋', aliases: ['stop', 'hand'] },
+ { shortname: 'spock-hand', emoji: '🖖', aliases: ['spock', 'vulcan'] },
+ { shortname: 'the_horns', emoji: '🤘', aliases: ['rock', 'metal'] },
+ { shortname: 'call_me_hand', emoji: '🤙', aliases: ['call', 'phone'] },
+ { shortname: 'point_left', emoji: '👈', aliases: ['left', 'point'] },
+ { shortname: 'point_right', emoji: '👉', aliases: ['right', 'point'] },
+ { shortname: 'point_up_2', emoji: '👆', aliases: ['up', 'point'] },
+ { shortname: 'middle_finger', emoji: '🖕', aliases: ['middle', 'finger'] },
+ { shortname: 'point_down', emoji: '👇', aliases: ['down', 'point'] },
+ { shortname: 'point_up', emoji: '☝️', aliases: ['up', 'point'] },
+ { shortname: 'point_up_2', emoji: '👆', aliases: ['up', 'point'] },
+ { shortname: 'crossed_fingers', emoji: '🤞', aliases: ['luck', 'cross'] },
+ { shortname: 'love_you_gesture', emoji: '🤟', aliases: ['love', 'you'] },
+ { shortname: 'metal', emoji: '🤘', aliases: ['rock', 'metal'] },
+ { shortname: 'vulcan_salute', emoji: '🖖', aliases: ['spock', 'vulcan'] },
+ {
+ shortname: 'index_pointing_at_the_viewer',
+ emoji: '🫵',
+ aliases: ['point', 'you'],
+ },
+ { shortname: 'palms_up_together', emoji: '🤲', aliases: ['prayer', 'hands'] },
+ { shortname: 'back_of_hand', emoji: '🤚', aliases: ['back', 'hand'] },
+ {
+ shortname: 'hand_with_index_finger_and_thumb_crossed',
+ emoji: '🤌',
+ aliases: ['pinch', 'money'],
+ },
+ { shortname: 'index_pointing_up', emoji: '☝️', aliases: ['up', 'point'] },
+ {
+ shortname: 'index_pointing_at_the_viewer_dark_skin_tone',
+ emoji: '🫵🏿',
+ aliases: ['point', 'you', 'dark'],
+ },
+ {
+ shortname: 'index_pointing_at_the_viewer_light_skin_tone',
+ emoji: '🫵🏻',
+ aliases: ['point', 'you', 'light'],
+ },
+ {
+ shortname: 'index_pointing_at_the_viewer_medium_dark_skin_tone',
+ emoji: '🫵🏾',
+ aliases: ['point', 'you', 'medium_dark'],
+ },
+ {
+ shortname: 'index_pointing_at_the_viewer_medium_light_skin_tone',
+ emoji: '🫵🏼',
+ aliases: ['point', 'you', 'medium_light'],
+ },
+ {
+ shortname: 'index_pointing_at_the_viewer_medium_skin_tone',
+ emoji: '🫵🏽',
+ aliases: ['point', 'you', 'medium'],
+ },
+ { shortname: 'thumbs_up', emoji: '👍', aliases: ['yes', 'good', 'approve'] },
+ {
+ shortname: 'thumbs_down',
+ emoji: '👎',
+ aliases: ['no', 'bad', 'disapprove'],
+ },
+ { shortname: 'raised_fist', emoji: '✊', aliases: ['fist', 'punch'] },
+ { shortname: 'oncoming_fist', emoji: '👊', aliases: ['fist', 'punch'] },
+ { shortname: 'left_facing_fist', emoji: '🤛', aliases: ['fist', 'left'] },
+ { shortname: 'right_facing_fist', emoji: '🤜', aliases: ['fist', 'right'] },
+ { shortname: 'clap', emoji: '👏', aliases: ['applause', 'bravo'] },
+ { shortname: 'raised_hands', emoji: '🙌', aliases: ['celebration', 'hands'] },
+ { shortname: 'open_hands', emoji: '👐', aliases: ['open', 'hands'] },
+ { shortname: 'palms_up_together', emoji: '🤲', aliases: ['prayer', 'hands'] },
+ { shortname: 'handshake', emoji: '🤝', aliases: ['deal', 'agreement'] },
+ { shortname: 'pray', emoji: '🙏', aliases: ['please', 'thanks', 'hope'] },
+ { shortname: 'writing_hand', emoji: '✍️', aliases: ['write', 'signature'] },
+ { shortname: 'nail_care', emoji: '💅', aliases: ['nail', 'polish'] },
+ { shortname: 'selfie', emoji: '🤳', aliases: ['camera', 'photo'] },
+ { shortname: 'muscle', emoji: '💪', aliases: ['strong', 'flex', 'biceps'] },
+ { shortname: 'mechanical_arm', emoji: '🦾', aliases: ['arm', 'robot'] },
+ { shortname: 'mechanical_leg', emoji: '🦿', aliases: ['leg', 'robot'] },
+ { shortname: 'leg', emoji: '🦵', aliases: ['kick', 'limb'] },
+ { shortname: 'foot', emoji: '🦶', aliases: ['kick', 'limb'] },
+ { shortname: 'ear', emoji: '👂', aliases: ['listen', 'hear'] },
+ {
+ shortname: 'ear_with_hearing_aid',
+ emoji: '🦻',
+ aliases: ['hearing', 'aid'],
+ },
+ { shortname: 'nose', emoji: '👃', aliases: ['smell', 'sniff'] },
+ { shortname: 'brain', emoji: '🧠', aliases: ['think', 'smart'] },
+ { shortname: 'anatomical_heart', emoji: '🫀', aliases: ['heart', 'health'] },
+ { shortname: 'lungs', emoji: '🫁', aliases: ['breath', 'health'] },
+ { shortname: 'tooth', emoji: '🦷', aliases: ['dental', 'health'] },
+ { shortname: 'bone', emoji: '🦴', aliases: ['skeleton', 'health'] },
+ { shortname: 'eyes', emoji: '👀', aliases: ['see', 'look', 'watch'] },
+ { shortname: 'eye', emoji: '👁️', aliases: ['see', 'look'] },
+ { shortname: 'tongue', emoji: '👅', aliases: ['taste', 'lick'] },
+ { shortname: 'lips', emoji: '👄', aliases: ['kiss', 'mouth'] },
+];
+
+export default emojiList;
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 0bdebf322b..7d387ba2c5 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -26,12 +26,14 @@ import MembersList from '../Mentions/MembersList';
import { TypingUsers } from '../TypingUsers';
import createPendingMessage from '../../lib/createPendingMessage';
import { CommandsList } from '../CommandList';
+import { EmojiList } from '../EmojiList';
import useSettingsStore from '../../store/settingsStore';
import ChannelState from '../ChannelState/ChannelState';
import QuoteMessage from '../QuoteMessage/QuoteMessage';
import { getChatInputStyles } from './ChatInput.styles';
import useShowCommands from '../../hooks/useShowCommands';
import useSearchMentionUser from '../../hooks/useSearchMentionUser';
+import useSearchEmoji from '../../hooks/useSearchEmoji';
import formatSelection from '../../lib/formatSelection';
import { parseEmoji } from '../../lib/emoji';
@@ -56,6 +58,10 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
const [showMembersList, setShowMembersList] = useState(false);
const [showCommandList, setShowCommandList] = useState(false);
const [filteredCommands, setFilteredCommands] = useState([]);
+ const [showEmojiList, setShowEmojiList] = useState(false);
+ const [filteredEmojis, setFilteredEmojis] = useState([]);
+ const [emojiIndex, setEmojiIndex] = useState(-1);
+ const [startReadEmoji, setStartReadEmoji] = useState(false);
const [isMsgLong, setIsMsgLong] = useState(false);
const {
@@ -144,6 +150,14 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
setShowMembersList
);
+ const searchEmoji = useSearchEmoji(
+ startReadEmoji,
+ setStartReadEmoji,
+ setFilteredEmojis,
+ setEmojiIndex,
+ setShowEmojiList
+ );
+
useEffect(() => {
RCInstance.auth.onAuthChange((user) => {
if (user) {
@@ -423,12 +437,17 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
const onTextChange = (e, val) => {
sendTypingStart();
const message = val || e.target.value;
- messageRef.current.value = parseEmoji(message);
+
+ // Don't parse emojis if user is currently typing emoji autocomplete
+ const shouldParseEmoji = !message.match(/:([a-zA-Z0-9_+-]*?)$/);
+ messageRef.current.value = shouldParseEmoji ? parseEmoji(message) : message;
+
setDisableButton(!messageRef.current.value.length);
if (e !== null) {
handleNewLine(e, false);
searchMentionUser(message);
showCommands(e);
+ searchEmoji(message);
}
};
@@ -471,7 +490,7 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
case e.code === 'Enter':
e.preventDefault();
- if (!showCommandList && !showMembersList) {
+ if (!showCommandList && !showMembersList && !showEmojiList) {
sendTypingStop();
sendMessage();
}
@@ -594,6 +613,18 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
/>
)}
+ {showEmojiList && (
+
+ )}
+
{
+ const currentMessage = messageRef.current.value;
+ const emojiMatch = currentMessage.match(/:(.*?)$/);
+
+ if (emojiMatch) {
+ // Replace the :query with the selected emoji
+ const beforeQuery = currentMessage.substring(
+ 0,
+ currentMessage.lastIndexOf(':')
+ );
+ const insertionText = `${beforeQuery}${selectedEmoji.emoji} `;
+
+ messageRef.current.value = insertionText;
+
+ // Set cursor position after the emoji and space
+ const cursorPosition = insertionText.length;
+ messageRef.current.setSelectionRange(cursorPosition, cursorPosition);
+ messageRef.current.focus();
+
+ // Clear emoji autocomplete state
+ setFilteredEmojis([]);
+ setEmojiIndex(-1);
+ setStartReadEmoji(false);
+ setShowEmojiList(false);
+ }
+ },
+ [
+ messageRef,
+ setFilteredEmojis,
+ setEmojiIndex,
+ setShowEmojiList,
+ setStartReadEmoji,
+ ]
+ );
+
+ const setItemRef = (el, index) => {
+ itemRefs.current[index] = el;
+ };
+
+ useEffect(() => {
+ const handleKeyPress = (event) => {
+ switch (event.key) {
+ case 'Enter': {
+ const selectedEmoji = filteredEmojis[emojiIndex];
+ if (selectedEmoji) {
+ handleEmojiClick(selectedEmoji);
+ }
+ break;
+ }
+ case 'Escape': {
+ // Cancel emoji selection
+ setFilteredEmojis([]);
+ setEmojiIndex(-1);
+ setStartReadEmoji(false);
+ setShowEmojiList(false);
+ messageRef.current.focus();
+ break;
+ }
+ case 'ArrowUp':
+ event.preventDefault();
+ setEmojiIndex(
+ emojiIndex - 1 < 0 ? filteredEmojis.length - 1 : emojiIndex - 1
+ );
+ break;
+ case 'ArrowDown':
+ event.preventDefault();
+ setEmojiIndex(
+ emojiIndex + 1 >= filteredEmojis.length ? 0 : emojiIndex + 1
+ );
+ break;
+ default:
+ break;
+ }
+ };
+
+ document.addEventListener('keydown', handleKeyPress);
+
+ return () => {
+ document.removeEventListener('keydown', handleKeyPress);
+ };
+ }, [
+ emojiIndex,
+ filteredEmojis,
+ handleEmojiClick,
+ setEmojiIndex,
+ setFilteredEmojis,
+ setStartReadEmoji,
+ setShowEmojiList,
+ messageRef,
+ ]);
+
+ useEffect(() => {
+ if (itemRefs.current[emojiIndex]) {
+ itemRefs.current[emojiIndex].scrollIntoView({
+ block: 'nearest',
+ });
+ }
+ }, [emojiIndex]);
+
+ if (!filteredEmojis || filteredEmojis.length === 0) {
+ return null;
+ }
+
+ return (
+
+
+ {filteredEmojis.map((emoji, index) => (
+ - handleEmojiClick(emoji)}
+ ref={(el) => setItemRef(el, index)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ handleEmojiClick(emoji);
+ }
+ }}
+ style={{
+ backgroundColor: index === emojiIndex && 'rgba(0, 0, 0, 0.1)',
+ color: index === emojiIndex && theme.colors.foreground,
+ }}
+ >
+ {emoji.emoji}
+ :{emoji.shortname}:
+
+ ))}
+
+
+ );
+}
+
+EmojiList.propTypes = {
+ emojiIndex: PropTypes.number,
+ messageRef: PropTypes.object.isRequired,
+ filteredEmojis: PropTypes.array,
+ setFilteredEmojis: PropTypes.func.isRequired,
+ setEmojiIndex: PropTypes.func.isRequired,
+ setStartReadEmoji: PropTypes.func.isRequired,
+ setShowEmojiList: PropTypes.func.isRequired,
+};
+
+export default EmojiList;
diff --git a/packages/react/src/views/EmojiList/EmojiList.styles.js b/packages/react/src/views/EmojiList/EmojiList.styles.js
new file mode 100644
index 0000000000..098e0a2bd4
--- /dev/null
+++ b/packages/react/src/views/EmojiList/EmojiList.styles.js
@@ -0,0 +1,53 @@
+import { css } from '@emotion/react';
+
+const getEmojiListStyles = (theme) => {
+ const styles = {
+ main: css`
+ margin: 0.2rem 2rem;
+ display: block;
+ max-height: 10rem;
+ overflow-y: auto;
+ overflow-x: hidden;
+ border: 1px solid ${theme.colors.border};
+ border-radius: 0.2rem;
+ background-color: ${theme.colors.background};
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ z-index: 1000;
+ position: relative;
+ `,
+
+ listItem: css`
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ padding: 0.5rem 0.75rem;
+ font-size: 14px;
+ border-bottom: 1px solid ${theme.colors.border};
+ transition: background-color 0.2s ease;
+
+ &:hover {
+ background-color: ${theme.colors.secondary};
+ }
+
+ &:last-child {
+ border-bottom: none;
+ }
+ `,
+
+ emoji: css`
+ font-size: 16px;
+ margin-right: 0.5rem;
+ flex-shrink: 0;
+ `,
+
+ shortname: css`
+ font-family: monospace;
+ color: ${theme.colors.mutedForeground};
+ font-size: 12px;
+ `,
+ };
+
+ return styles;
+};
+
+export default getEmojiListStyles;
diff --git a/packages/react/src/views/EmojiList/index.js b/packages/react/src/views/EmojiList/index.js
new file mode 100644
index 0000000000..794f574143
--- /dev/null
+++ b/packages/react/src/views/EmojiList/index.js
@@ -0,0 +1 @@
+export { default as EmojiList } from './EmojiList';
From d18e390d5cd6fc34752e2f2e864c4b8951102499 Mon Sep 17 00:00:00 2001
From: R Pratheek <111165032+Pratheek555@users.noreply.github.com>
Date: Sat, 21 Mar 2026 12:54:35 +0530
Subject: [PATCH 134/153] Updated Deprecated Endpoints (#1035)
* Updated Deprecated Endpoints
* format checks
---
packages/api/src/EmbeddedChatApi.ts | 41 +++--------------------------
1 file changed, 3 insertions(+), 38 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index a3549af990..4b64e23d54 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -493,34 +493,7 @@ export default class EmbeddedChatApi {
async getRoomInfo() {
try {
- const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
- const response = await fetch(
- `${this.host}/api/v1/method.call/rooms%3Aget`,
- {
- body: JSON.stringify({
- message: JSON.stringify({
- msg: "method",
- id: null,
- method: "rooms/get",
- params: [],
- }),
- }),
- headers: {
- "Content-Type": "application/json",
- "X-Auth-Token": authToken,
- "X-User-Id": userId,
- },
- method: "POST",
- }
- );
-
- const result = await response.json();
-
- if (result.success && result.message) {
- const parsedMessage = JSON.parse(result.message);
- return parsedMessage;
- }
- return null;
+ return await this.channelInfo();
} catch (err) {
console.error(err);
}
@@ -699,22 +672,14 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(
- `${this.host}/api/v1/method.call/getUserRoles`,
+ `${this.host}/api/v1/roles.getUsersInPublicRoles`,
{
- body: JSON.stringify({
- message: JSON.stringify({
- msg: "method",
- id: null,
- method: "getUserRoles",
- params: [],
- }),
- }),
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
"X-User-Id": userId,
},
- method: "POST",
+ method: "GET",
}
);
From 31c86d7a7c9945513fdf8311568151cff3c0041d Mon Sep 17 00:00:00 2001
From: R Pratheek <111165032+Pratheek555@users.noreply.github.com>
Date: Sat, 21 Mar 2026 13:31:29 +0530
Subject: [PATCH 135/153] Pasting image directly from clipboard (#1040)
---
packages/react/src/hooks/useDropBox.js | 6 +++
.../react/src/views/ChatInput/ChatInput.js | 37 +++++++++++++++++++
2 files changed, 43 insertions(+)
diff --git a/packages/react/src/hooks/useDropBox.js b/packages/react/src/hooks/useDropBox.js
index 27002ce7c4..a78b395092 100644
--- a/packages/react/src/hooks/useDropBox.js
+++ b/packages/react/src/hooks/useDropBox.js
@@ -15,10 +15,16 @@ const useDropBox = () => {
setData(e.dataTransfer.files[0]);
};
+ const handlePaste = (file) => {
+ toggle();
+ setData(file);
+ };
+
return {
data,
handleDrag,
handleDragDrop,
+ handlePaste,
};
};
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 7d387ba2c5..f6fb0e111f 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -36,6 +36,7 @@ import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import useSearchEmoji from '../../hooks/useSearchEmoji';
import formatSelection from '../../lib/formatSelection';
import { parseEmoji } from '../../lib/emoji';
+import useDropBox from '../../hooks/useDropBox';
const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
@@ -150,6 +151,7 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
setShowMembersList
);
+ const { handlePaste } = useDropBox();
const searchEmoji = useSearchEmoji(
startReadEmoji,
setStartReadEmoji,
@@ -463,6 +465,40 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
}
};
+ const handlePasting = (event) => {
+ const { clipboardData } = event;
+
+ if (!clipboardData) {
+ return;
+ }
+
+ const items = Array.from(clipboardData.items);
+ if (
+ items.some(({ kind, type }) => kind === 'string' && type === 'text/plain')
+ ) {
+ return;
+ }
+
+ const files = items
+ .filter(
+ (item) => item.kind === 'file' && item.type.indexOf('image/') !== -1
+ )
+ .map((item) => {
+ const fileItem = item.getAsFile();
+
+ if (!fileItem) {
+ return;
+ }
+ return fileItem;
+ })
+ .filter((file) => !!file);
+
+ if (files.length) {
+ event.preventDefault();
+ handlePaste(files[0]);
+ }
+ };
+
const onKeyDown = (e) => {
switch (true) {
case e.ctrlKey && e.code === 'KeyI': {
@@ -666,6 +702,7 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
}}
onFocus={handleFocus}
onKeyDown={onKeyDown}
+ onPaste={handlePasting}
ref={messageRef}
/>
From 240152039e8287b2d22ed997f33a06ca63b53575 Mon Sep 17 00:00:00 2001
From: Deepak Bhagat <149673145+deepak0x@users.noreply.github.com>
Date: Sat, 21 Mar 2026 13:51:46 +0530
Subject: [PATCH 136/153] fix(react): add missing unique key props to
ChatInputFormattingToolbar components (#1102)
---
.../react/src/views/ChatInput/ChatInputFormattingToolbar.js | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 5d8c20a600..a930009255 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -116,6 +116,7 @@ const ChatInputFormattingToolbar = ({
audio: (
formatter.find((item) => item.name === name))
.map((item) =>
isPopoverOpen && popOverItems.includes('formatter') ? (
- <>
+
{item.name}
- >
+
) : (
Date: Sat, 21 Mar 2026 16:50:37 +0530
Subject: [PATCH 137/153] feat: keyboard shortcut info inside formatter's
tooltip (#1103)
---
packages/react/src/lib/textFormat.js | 14 +++++---------
.../views/ChatInput/ChatInputFormattingToolbar.js | 4 ++--
2 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/packages/react/src/lib/textFormat.js b/packages/react/src/lib/textFormat.js
index a1978c0033..4a435cf158 100644
--- a/packages/react/src/lib/textFormat.js
+++ b/packages/react/src/lib/textFormat.js
@@ -1,11 +1,7 @@
export const formatter = [
- { name: 'bold', pattern: '*{{text}}*', tooltip: 'Bold' },
- { name: 'italic', pattern: '_{{text}}_', tooltip: 'Italic' },
- { name: 'strike', pattern: '~{{text}}~', tooltip: 'Strikethrough' },
- { name: 'code', pattern: '`{{text}}`', tooltip: 'Inline code' },
- {
- name: 'multiline',
- pattern: '```\n{{text}}\n```',
- tooltip: 'Multi-line code',
- },
+ { name: 'bold', pattern: '*{{text}}*', tooltip: 'Bold', shortcut: 'Ctrl + B' },
+ { name: 'italic', pattern: '_{{text}}_', tooltip: 'Italic', shortcut: 'Ctrl + I' },
+ { name: 'strike', pattern: '~{{text}}~', tooltip: 'Strikethrough', shortcut: '' },
+ { name: 'code', pattern: '`{{text}}`', tooltip: 'Inline code', shortcut: '' },
+ { name: 'multiline', pattern: '```\n{{text}}\n```', tooltip: 'Multi-line code', shortcut: ''}
];
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index a930009255..9574bc27fa 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -216,7 +216,7 @@ const ChatInputFormattingToolbar = ({
) : (
@@ -296,7 +296,7 @@ const ChatInputFormattingToolbar = ({
if (itemInFormatter) {
return (
From 97fc430bde1a52ef0b37a8059efc0f19d3987ab1 Mon Sep 17 00:00:00 2001
From: Vivek Yadav <2428045@kiit.ac.in>
Date: Sat, 21 Mar 2026 16:53:55 +0530
Subject: [PATCH 138/153] fix: add user-friendly error notification for login
failures (#1107)
---
packages/react/src/hooks/useRCAuth.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/hooks/useRCAuth.js b/packages/react/src/hooks/useRCAuth.js
index 83b013353b..37c727a072 100644
--- a/packages/react/src/hooks/useRCAuth.js
+++ b/packages/react/src/hooks/useRCAuth.js
@@ -63,7 +63,11 @@ export const useRCAuth = () => {
}
}
} catch (e) {
- console.error('A error occurred while setting up user', e);
+ console.error('An error occurred while setting up user', e);
+ dispatchToastMessage({
+ type: 'error',
+ message: 'Unable to connect to server. Please check your connection and try again.',
+ });
}
};
From 2f988c4f0570dcf552159ee418c298857fab7453 Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sat, 21 Mar 2026 17:08:29 +0530
Subject: [PATCH 139/153] fix format check
Signed-off-by: Zishan Ahmad
---
packages/react/src/hooks/useRCAuth.js | 3 +-
packages/react/src/lib/textFormat.js | 28 ++++++++++++++++---
.../ChatInput/ChatInputFormattingToolbar.js | 4 ++-
3 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/packages/react/src/hooks/useRCAuth.js b/packages/react/src/hooks/useRCAuth.js
index 37c727a072..0402fb63d9 100644
--- a/packages/react/src/hooks/useRCAuth.js
+++ b/packages/react/src/hooks/useRCAuth.js
@@ -66,7 +66,8 @@ export const useRCAuth = () => {
console.error('An error occurred while setting up user', e);
dispatchToastMessage({
type: 'error',
- message: 'Unable to connect to server. Please check your connection and try again.',
+ message:
+ 'Unable to connect to server. Please check your connection and try again.',
});
}
};
diff --git a/packages/react/src/lib/textFormat.js b/packages/react/src/lib/textFormat.js
index 4a435cf158..7bdff292b0 100644
--- a/packages/react/src/lib/textFormat.js
+++ b/packages/react/src/lib/textFormat.js
@@ -1,7 +1,27 @@
export const formatter = [
- { name: 'bold', pattern: '*{{text}}*', tooltip: 'Bold', shortcut: 'Ctrl + B' },
- { name: 'italic', pattern: '_{{text}}_', tooltip: 'Italic', shortcut: 'Ctrl + I' },
- { name: 'strike', pattern: '~{{text}}~', tooltip: 'Strikethrough', shortcut: '' },
+ {
+ name: 'bold',
+ pattern: '*{{text}}*',
+ tooltip: 'Bold',
+ shortcut: 'Ctrl + B',
+ },
+ {
+ name: 'italic',
+ pattern: '_{{text}}_',
+ tooltip: 'Italic',
+ shortcut: 'Ctrl + I',
+ },
+ {
+ name: 'strike',
+ pattern: '~{{text}}~',
+ tooltip: 'Strikethrough',
+ shortcut: '',
+ },
{ name: 'code', pattern: '`{{text}}`', tooltip: 'Inline code', shortcut: '' },
- { name: 'multiline', pattern: '```\n{{text}}\n```', tooltip: 'Multi-line code', shortcut: ''}
+ {
+ name: 'multiline',
+ pattern: '```\n{{text}}\n```',
+ tooltip: 'Multi-line code',
+ shortcut: '',
+ },
];
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 9574bc27fa..909359f3c7 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -296,7 +296,9 @@ const ChatInputFormattingToolbar = ({
if (itemInFormatter) {
return (
From 189a6bc7dd07102e0c6858c2885ae7445e925699 Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sat, 21 Mar 2026 17:14:38 +0530
Subject: [PATCH 140/153] fix lint
Signed-off-by: Zishan Ahmad
---
.../react/src/views/ChatInput/ChatInputFormattingToolbar.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 909359f3c7..a68dc340f6 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -297,7 +297,7 @@ const ChatInputFormattingToolbar = ({
return (
Date: Sat, 21 Mar 2026 17:33:33 +0530
Subject: [PATCH 141/153] fix: replace deprecated getUserRoles method call with
REST API (#1104)
---
packages/api/src/EmbeddedChatApi.ts | 24 +++++-------------------
1 file changed, 5 insertions(+), 19 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 4b64e23d54..88eb4c23c2 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -670,28 +670,14 @@ export default class EmbeddedChatApi {
async getUserRoles() {
try {
- const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
- const response = await fetch(
- `${this.host}/api/v1/roles.getUsersInPublicRoles`,
- {
- headers: {
- "Content-Type": "application/json",
- "X-Auth-Token": authToken,
- "X-User-Id": userId,
- },
- method: "GET",
- }
- );
-
- const result = await response.json();
-
- if (result.success && result.message) {
- const parsedMessage = JSON.parse(result.message);
- return parsedMessage;
+ const response = await this.getUsersInRole("admin");
+ if (response && response.success) {
+ return { result: response.users };
}
- return null;
+ return { result: [] };
} catch (err) {
console.error(err);
+ return { result: [] };
}
}
From f38073c2436ac1226d2bb3bc8e561b0a9afbed67 Mon Sep 17 00:00:00 2001
From: Aryan Verma <121835781+Aryan-Verma-999@users.noreply.github.com>
Date: Sun, 17 May 2026 00:26:38 +0530
Subject: [PATCH 142/153] Upgrade to React 19, Storybook 8, and Node 22 (#1291)
* chore: upgrade to React 19, Storybook 8, Node 22, and fix LoginForm state
* bug fixes
* login bug fix
* fix: improve variable names in LoginForm and relax Node version check
* ci: upgrade Node.js from 16/18 to 22 in all workflows
* style: fix Prettier formatting in react package
* fix(e2e): bind Vite to 127.0.0.1 to fix Playwright webServer timeout in CI
* fix: use semver package for Node version check
* chore: add semver as root devDependency
* chore: update lockfile
* fix(docs): pin webpack to 5.96.1 and update Node/React versions in READMEs
---
.github/workflows/build-and-lint.yml | 4 +-
.github/workflows/build-pr.yml | 4 +-
.github/workflows/deploy.yml | 4 +-
.github/workflows/playwright.yml | 2 +-
.nvmrc | 2 +-
README.md | 2 +-
package.json | 5 +
packages/api/src/EmbeddedChatApi.ts | 17 +-
packages/auth/src/Api.ts | 3 +-
packages/auth/src/RocketChatAuth.ts | 11 +-
packages/docs/README.md | 8 +-
packages/docs/package.json | 9 +-
packages/docs/yarn.lock | 2345 +++++++--
packages/e2e-react/.gitignore | 1 +
packages/e2e-react/package.json | 8 +-
packages/e2e-react/playwright.config.ts | 3 +
packages/e2e-react/vite.config.ts | 5 +-
packages/htmlembed/package.json | 4 +-
packages/layout_editor/package.json | 4 +-
packages/markups/package.json | 8 +-
packages/react/.storybook/main.js | 10 +-
packages/react/package.json | 30 +-
packages/react/src/hooks/useShowCommands.js | 5 +-
.../AttachmentPreview/PreviewType/audio.js | 2 +-
.../AttachmentPreview/PreviewType/image.js | 2 +-
packages/react/src/views/ChatBody/ChatBody.js | 52 +-
.../react/src/views/ChatHeader/ChatHeader.js | 7 +-
.../react/src/views/ChatInput/ChatInput.js | 80 +-
packages/react/src/views/EmbeddedChat.js | 11 +-
.../react/src/views/LoginForm/LoginForm.js | 42 +-
.../react/src/views/Message/MessageToolbox.js | 18 +-
packages/ui-elements/.storybook/main.js | 10 +-
packages/ui-elements/package.json | 26 +-
packages/ui-kit/package.json | 8 +-
scripts/node-check.js | 6 +-
yarn.lock | 4617 ++++++-----------
36 files changed, 3775 insertions(+), 3600 deletions(-)
diff --git a/.github/workflows/build-and-lint.yml b/.github/workflows/build-and-lint.yml
index 4d85036e01..5f0e3b5ead 100644
--- a/.github/workflows/build-and-lint.yml
+++ b/.github/workflows/build-and-lint.yml
@@ -17,12 +17,12 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
- node-version: 16.19.0
+ node-version: 22
- name: Set up Yarn
uses: actions/setup-node@v4
with:
- node-version: 16.19.0
+ node-version: 22
cache: "yarn"
- name: Cache dependencies
diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
index b459fd0cc4..98624f2e04 100644
--- a/.github/workflows/build-pr.yml
+++ b/.github/workflows/build-pr.yml
@@ -25,7 +25,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
- node-version: "16.19.0"
+ node-version: "22"
- name: Install Dependencies
run: yarn install
@@ -36,7 +36,7 @@ jobs:
- name: Setup Node.js for Docs
uses: actions/setup-node@v4
with:
- node-version: "18.x"
+ node-version: "22"
- name: "Install dependencies for docs"
run: yarn install
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 4055f20ca6..08e6fddcf3 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -27,7 +27,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
- node-version: "16.19.0"
+ node-version: "22"
- name: Install Dependencies
run: yarn install
@@ -38,7 +38,7 @@ jobs:
- name: Setup Node.js for Docs
uses: actions/setup-node@v4
with:
- node-version: "18.x"
+ node-version: "22"
- name: "Install dependencies for docs"
run: yarn install
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 3d4b133a9e..3494052ebf 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -17,7 +17,7 @@ jobs:
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
- node-version: 16.19.0
+ node-version: 22
- name: Cache dependencies
uses: actions/cache@v4
diff --git a/.nvmrc b/.nvmrc
index d60d573ec6..5a60199693 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-v16.19.0
\ No newline at end of file
+v22.16.0
\ No newline at end of file
diff --git a/README.md b/README.md
index 455b2fa897..2c68bde9d8 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ Ensure that the "Enable CORS" option is turned on in your Rocket.Chat server. Yo
#### Prerequisites
-- **Node.js**: Version 16.19.0 is required. Use [Node Version Manager (NVM)](https://github.com/nvm-sh/nvm) for easy switching between Node.js versions.
+- **Node.js**: Version 22 (LTS) is required. Use [Node Version Manager (NVM)](https://github.com/nvm-sh/nvm) for easy switching between Node.js versions.
To install and use the correct Node.js version, execute the following commands with the specific version number:
diff --git a/package.json b/package.json
index c589243fe2..907cd18431 100644
--- a/package.json
+++ b/package.json
@@ -22,10 +22,15 @@
"esbuild": "^0.17.19",
"husky": "^9.0.11",
"lerna": "^6.6.2",
+ "semver": "^7.6.0",
"typescript": "^5.1.3"
},
"dependencies": {
"dompurify": "^3.1.6",
"validator": "^13.15.15"
+ },
+ "resolutions": {
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
}
}
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 88eb4c23c2..3c5c9a8b1c 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -20,6 +20,7 @@ export default class EmbeddedChatApi {
onUiInteractionCallbacks: ((data: any) => void)[];
typingUsers: string[];
auth: RocketChatAuth;
+ private _connectPromise: Promise | null = null;
constructor(
host: string,
@@ -186,6 +187,17 @@ export default class EmbeddedChatApi {
* TODO: Add logic to call thread message event listeners. To be done after thread implementation
*/
async connect() {
+ // Guard against concurrent connect() calls (e.g. React StrictMode double-invoke)
+ if (this._connectPromise) {
+ return this._connectPromise;
+ }
+ this._connectPromise = this._doConnect().finally(() => {
+ this._connectPromise = null;
+ });
+ return this._connectPromise;
+ }
+
+ private async _doConnect() {
try {
await this.close(); // before connection, all previous subscriptions should be cancelled
await this.rcClient.connect({});
@@ -198,7 +210,6 @@ export default class EmbeddedChatApi {
}
const message = JSON.parse(JSON.stringify(data));
if (message.ts?.$date) {
- console.log(message.ts?.$date);
message.ts = message.ts.$date;
}
if (!message.ts) {
@@ -683,14 +694,14 @@ export default class EmbeddedChatApi {
async sendTypingStatus(username: string, typing: boolean) {
try {
- this.rcClient.methodCall(
+ await this.rcClient.methodCall(
"stream-notify-room",
`${this.rid}/user-activity`,
username,
typing ? ["user-typing"] : []
);
} catch (err) {
- console.error(err);
+ // DDP typing indicator fails when connection is temporarily down — expected, safe to ignore
}
}
diff --git a/packages/auth/src/Api.ts b/packages/auth/src/Api.ts
index 78d6c82c7a..f8967ff486 100644
--- a/packages/auth/src/Api.ts
+++ b/packages/auth/src/Api.ts
@@ -44,7 +44,8 @@ export class Api {
if (!response.ok) {
throw new ApiError(response, "Failed Api Request for " + endpoint);
}
- const jsonData = await response.json();
+ const text = await response.text();
+ const jsonData = text.length ? JSON.parse(text) : {};
return { data: jsonData };
}
diff --git a/packages/auth/src/RocketChatAuth.ts b/packages/auth/src/RocketChatAuth.ts
index 0f2c55f196..769ca55778 100644
--- a/packages/auth/src/RocketChatAuth.ts
+++ b/packages/auth/src/RocketChatAuth.ts
@@ -36,7 +36,9 @@ class RocketChatAuth {
async onAuthChange(callback: (user: object | null) => void) {
this.authListeners.push(callback);
const user = await this.getCurrentUser();
- callback(user);
+ if (this.authListeners.includes(callback)) {
+ callback(user);
+ }
}
async removeAuthListener(callback: (user: object | null) => void) {
@@ -72,6 +74,7 @@ class RocketChatAuth {
}
);
this.setUser(response.data);
+ this.notifyAuthListeners();
return this.currentUser;
}
@@ -92,6 +95,7 @@ class RocketChatAuth {
credentials
);
this.setUser(response.data);
+ this.notifyAuthListeners();
return this.currentUser;
}
@@ -107,6 +111,7 @@ class RocketChatAuth {
api: this.api,
});
this.setUser(response.data);
+ this.notifyAuthListeners();
return this.currentUser;
}
@@ -190,10 +195,10 @@ class RocketChatAuth {
try {
const token = await this.getToken();
if (token) {
- const user = await this.loginWithResumeToken(token); // will notifyAuthListeners on successful login
+ const user = await this.loginWithResumeToken(token);
if (user) {
this.lastFetched = new Date();
- await this.getCurrentUser(); // refresh the token if needed
+ await this.getCurrentUser();
}
}
} catch (e) {
diff --git a/packages/docs/README.md b/packages/docs/README.md
index aaf7803b93..a063ab8a28 100644
--- a/packages/docs/README.md
+++ b/packages/docs/README.md
@@ -4,14 +4,14 @@ This is the official documentation website of EmbeddedChat.
> **Node.js Version Requirement**
>
-> The `docs/` folder requires **Node.js v18 or higher** to run correctly.
-> If you’re using a lower version (e.g., v16.19.0 from other parts of the monorepo), you may encounter errors.
+> The `docs/` folder requires **Node.js v22 or higher** to run correctly.
+> If you’re using a lower version (e.g., v18), you may encounter errors.
>
> Use [NVM](https://github.com/nvm-sh/nvm) to install and switch to the correct version:
>
> ```bash
-> nvm install 18
-> nvm use 18
+> nvm install 22
+> nvm use 22
> ```
### Installation
diff --git a/packages/docs/package.json b/packages/docs/package.json
index f14a34ce8a..a9f4bb2f0e 100644
--- a/packages/docs/package.json
+++ b/packages/docs/package.json
@@ -19,8 +19,8 @@
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0",
- "react": "^18.0.0",
- "react-dom": "^18.0.0"
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.5.1",
@@ -38,7 +38,10 @@
"last 5 safari version"
]
},
+ "resolutions": {
+ "webpack": "5.96.1"
+ },
"engines": {
- "node": ">=18.0"
+ "node": ">=22.0"
}
}
diff --git a/packages/docs/yarn.lock b/packages/docs/yarn.lock
index e12862dfd2..8950e7b7f2 100644
--- a/packages/docs/yarn.lock
+++ b/packages/docs/yarn.lock
@@ -5,126 +5,217 @@ __metadata:
version: 6
cacheKey: 8
-"@algolia/autocomplete-core@npm:1.9.3":
- version: 1.9.3
- resolution: "@algolia/autocomplete-core@npm:1.9.3"
+"@algolia/abtesting@npm:1.18.1":
+ version: 1.18.1
+ resolution: "@algolia/abtesting@npm:1.18.1"
dependencies:
- "@algolia/autocomplete-plugin-algolia-insights": 1.9.3
- "@algolia/autocomplete-shared": 1.9.3
- checksum: ce78048568660184a4fa3c6548f344a7f5ce0ba45d4cfc233f9756b6d4f360afd5ae3a18efefcd27a626d3a0d6cf22d9cba3e21b217afae62b8e9d11bc4960da
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: a74a4b921d33dc58568cbdffed079ae75d3c005b72eb43376a0c326a4e74599703bc1545a7db8b6bb4e5104e60db3b5504fe18d52ce1fe52612077971367dc0e
languageName: node
linkType: hard
-"@algolia/autocomplete-plugin-algolia-insights@npm:1.9.3":
- version: 1.9.3
- resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.9.3"
+"@algolia/autocomplete-core@npm:1.17.9":
+ version: 1.17.9
+ resolution: "@algolia/autocomplete-core@npm:1.17.9"
+ dependencies:
+ "@algolia/autocomplete-plugin-algolia-insights": 1.17.9
+ "@algolia/autocomplete-shared": 1.17.9
+ checksum: dde242b1a2d8485e6c7bc94d00e25d707aa66dcd276ee1dde13213f1620bf6a1d289a61c657e40c707ca726a8aa009ab5e8229f92ae5cf22266de490b0634d20
+ languageName: node
+ linkType: hard
+
+"@algolia/autocomplete-plugin-algolia-insights@npm:1.17.9":
+ version: 1.17.9
+ resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.17.9"
dependencies:
- "@algolia/autocomplete-shared": 1.9.3
+ "@algolia/autocomplete-shared": 1.17.9
peerDependencies:
search-insights: ">= 1 < 3"
- checksum: 030695bf692021c27f52a3d4931efed23032796e326d4ae7957ae91b51c36a10dc2d885fb043909e853f961c994b8e9ff087f50bb918cfa075370562251a199f
+ checksum: 32761d44a407d7c5ecfae98bb78b45a1ca85c59f44167ea36057315fb357c49684e9126bb7a67a513a27bda60a9661cecd6215f2daa903288860201b0b18c745
languageName: node
linkType: hard
-"@algolia/autocomplete-preset-algolia@npm:1.9.3":
- version: 1.9.3
- resolution: "@algolia/autocomplete-preset-algolia@npm:1.9.3"
+"@algolia/autocomplete-preset-algolia@npm:1.17.9":
+ version: 1.17.9
+ resolution: "@algolia/autocomplete-preset-algolia@npm:1.17.9"
dependencies:
- "@algolia/autocomplete-shared": 1.9.3
+ "@algolia/autocomplete-shared": 1.17.9
peerDependencies:
"@algolia/client-search": ">= 4.9.1 < 6"
algoliasearch: ">= 4.9.1 < 6"
- checksum: 1ab3273d3054b348eed286ad1a54b21807846326485507b872477b827dc688006d4f14233cebd0bf49b2932ec8e29eca6d76e48a3c9e9e963b25153b987549c0
+ checksum: 0dac2aae02121d37466b4ce1ca533420b25cd70e218a9e645e6194bd84a6012a0e94c22125437adb89599ecf14e4488882f91da382c6c9a8d9447e929b317522
languageName: node
linkType: hard
-"@algolia/autocomplete-shared@npm:1.9.3":
- version: 1.9.3
- resolution: "@algolia/autocomplete-shared@npm:1.9.3"
+"@algolia/autocomplete-shared@npm:1.17.9":
+ version: 1.17.9
+ resolution: "@algolia/autocomplete-shared@npm:1.17.9"
peerDependencies:
"@algolia/client-search": ">= 4.9.1 < 6"
algoliasearch: ">= 4.9.1 < 6"
- checksum: 06014c8b08d30c452de079f48c0235d8fa09904bf511da8dc1b7e491819940fd4ff36b9bf65340242b2e157a26799a3b9aea01feee9c5bf67be3c48d7dff43d7
+ checksum: f16223f5995db0deb014a066e3587ec2da76e62b861aa21411be92cb255b7023507803283803d8c960b396a2c6b690951337c32fef34f68c59ecfb3822dee577
+ languageName: node
+ linkType: hard
+
+"@algolia/cache-browser-local-storage@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/cache-browser-local-storage@npm:4.27.0"
+ dependencies:
+ "@algolia/cache-common": 4.27.0
+ checksum: f495cc5130caea73effcee371164fd6322deda3c2b78c26f688542e6c44e706925c148cf48675173b2e3ab7eafa8889bc5cccae07c300f2fd5e990d10cbc0b68
+ languageName: node
+ linkType: hard
+
+"@algolia/cache-common@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/cache-common@npm:4.27.0"
+ checksum: 0e3629d291ccd4b40919826450bc538a16ec0f1aa77a8f104639dee1de9263a1fa6ff982d1afabae7a14ac91807820d716ed4b8019c0d54dce2b7e9fa361887b
+ languageName: node
+ linkType: hard
+
+"@algolia/cache-in-memory@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/cache-in-memory@npm:4.27.0"
+ dependencies:
+ "@algolia/cache-common": 4.27.0
+ checksum: 055f6220a7ab4db328102d473bb0e4a40afcc1ad8ec215c401361d063865fde2cfab24c947b66080c2214f6168dbc7a289897513556e6bb74856e32c6a22a438
+ languageName: node
+ linkType: hard
+
+"@algolia/client-abtesting@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/client-abtesting@npm:5.52.1"
+ dependencies:
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: a65f92bcf4e4fb8a851b5f49bfa387d3a44c6d3753af539f83041d0cb40b5dead99474ac5ad6c07cb9301de72aacf294ec153157c92ddc9ead7e172a32432cb5
+ languageName: node
+ linkType: hard
+
+"@algolia/client-account@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/client-account@npm:4.27.0"
+ dependencies:
+ "@algolia/client-common": 4.27.0
+ "@algolia/client-search": 4.27.0
+ "@algolia/transporter": 4.27.0
+ checksum: c9afa59d111eb9fa17dc4ba235d17190845dbfb640a39e4e54e3d3146fb64072367d0b8d9d40694c143d99883c9c0ca226eea1b42b967c14e230d64d4ec72c34
+ languageName: node
+ linkType: hard
+
+"@algolia/client-analytics@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/client-analytics@npm:4.27.0"
+ dependencies:
+ "@algolia/client-common": 4.27.0
+ "@algolia/client-search": 4.27.0
+ "@algolia/requester-common": 4.27.0
+ "@algolia/transporter": 4.27.0
+ checksum: 76515fb1ef89480e50060dd723ff16818b9cb94193243f675dd10d1138ef567930a32c595189fe830c7a96aafc85dd3351c607e817b9e8d57f93fabf7e19c962
languageName: node
linkType: hard
-"@algolia/cache-browser-local-storage@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/cache-browser-local-storage@npm:4.24.0"
+"@algolia/client-analytics@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/client-analytics@npm:5.52.1"
dependencies:
- "@algolia/cache-common": 4.24.0
- checksum: f7f9bdb1fa37e788a5cb8c835e526caff2fa097f68736accd4c82ade5e5cb7f5bbd361cf8fc8c2a4628d979d81bd90597bdaed77ca72de8423593067b3d15040
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: d0572e7abc82642442a468918fb699fca4ca4c365093862d0b45b03a8c72511d2387585a353bd5a9618641f6893c3d37c2f0e35b5a6805b263f27bb314d46dd6
languageName: node
linkType: hard
-"@algolia/cache-common@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/cache-common@npm:4.24.0"
- checksum: bc1d0f8731713f7e6f10cd397b7d8f7464f14a2f4e1decc73a48e99ecbc0fe41bd4df1cc3eb0a4ecf286095e3eb3935b2ea40179de98e11676f8e7d78c622df8
+"@algolia/client-common@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/client-common@npm:4.27.0"
+ dependencies:
+ "@algolia/requester-common": 4.27.0
+ "@algolia/transporter": 4.27.0
+ checksum: c8da03a715799646c96e97bf9970192431e39ff8ae3d68e66fd704a8d047d5e417da720ad6110ab8038a178e4ed784d544c5d19651a35fcb97d02dd5d4203c64
+ languageName: node
+ linkType: hard
+
+"@algolia/client-common@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/client-common@npm:5.52.1"
+ checksum: f92954c9b7a9cae5129eaadfe07cff84244dea2b578e30736603826dcfb0a1c0cd2ef2c461202307e11096ba6c1be63a05d0951dfb408aa743e947ddd4b7f1ef
languageName: node
linkType: hard
-"@algolia/cache-in-memory@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/cache-in-memory@npm:4.24.0"
+"@algolia/client-insights@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/client-insights@npm:5.52.1"
dependencies:
- "@algolia/cache-common": 4.24.0
- checksum: 0476f65f4b622b1b38f050a03b9bf02cf6cc77fc69ec785d16e244770eb2c5eea581b089a346d24bdbc3561be78d383f2a8b81179b801b2af72d9795bc48fee2
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: a764e6884f7e38b0b1f18d83cb296749aa7d9c497defd2d165d99a9ca2ba6683551220a599551161873abcdae1f9dea52e23c0da54422a73da3fc1bef328fb01
languageName: node
linkType: hard
-"@algolia/client-account@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/client-account@npm:4.24.0"
+"@algolia/client-personalization@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/client-personalization@npm:4.27.0"
dependencies:
- "@algolia/client-common": 4.24.0
- "@algolia/client-search": 4.24.0
- "@algolia/transporter": 4.24.0
- checksum: 059cf39f3e48b2e77a26435267284d2d15a7a3c4e904feb2b2ad2dd207a3ca2e2b3597847ec9f3b1141749b25fb2e6091e9933f53cb86ab278b5b93836c85aad
+ "@algolia/client-common": 4.27.0
+ "@algolia/requester-common": 4.27.0
+ "@algolia/transporter": 4.27.0
+ checksum: 479c6dc8d275180aab93f92a33d685f306c7e8c7179c3c8ec4c0c5644b91d028aeb8c1c7ccaed75d95580d9786ca617d6eab82efc3928fa8ea3b416d376719d9
languageName: node
linkType: hard
-"@algolia/client-analytics@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/client-analytics@npm:4.24.0"
+"@algolia/client-personalization@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/client-personalization@npm:5.52.1"
dependencies:
- "@algolia/client-common": 4.24.0
- "@algolia/client-search": 4.24.0
- "@algolia/requester-common": 4.24.0
- "@algolia/transporter": 4.24.0
- checksum: 17540315bc7ed2ed962fe343129ffe6dcd535cd37d4893765b5b3306a5a2b0a32260d116e77c13541bbc932480b14e24cc640eeecae338bebe7b57bc2cf9cde5
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: 9188f721f32f7c8be597f837b47804a6c0fb5c7e2ea073c80eb6f6659791fedb47f45df11eff0731f3358e2993c5eaf8c6dd4da44847ff6d19a2cdaef144d23d
languageName: node
linkType: hard
-"@algolia/client-common@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/client-common@npm:4.24.0"
+"@algolia/client-query-suggestions@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/client-query-suggestions@npm:5.52.1"
dependencies:
- "@algolia/requester-common": 4.24.0
- "@algolia/transporter": 4.24.0
- checksum: 19c6615f9e1b0bbda7dd8ecd285c5bdf48d7067223b06e385a6c69a20a6d6500086619fa0f9e63403cf33220d5d7a288360df55452fdf00f5feca8ca9852758a
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: 302e9f11a8d445044e3231b6dbf6ca18c6d5c0a404f808d2cf5a0d04090d35f1fb5bda59a55eb10d6c6bbf112bce379c66419b4bc9aec9cde77663ab22b3a109
languageName: node
linkType: hard
-"@algolia/client-personalization@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/client-personalization@npm:4.24.0"
+"@algolia/client-search@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/client-search@npm:4.27.0"
dependencies:
- "@algolia/client-common": 4.24.0
- "@algolia/requester-common": 4.24.0
- "@algolia/transporter": 4.24.0
- checksum: 9c569c6d846f7c9cf3056b83f2c67d9e796b5afa7e7aa55b1e125a2cf5a7342c96d94e7e2005931145698a1d1fc9a56d692f56a5b09fc4a4291bcc83b73addba
+ "@algolia/client-common": 4.27.0
+ "@algolia/requester-common": 4.27.0
+ "@algolia/transporter": 4.27.0
+ checksum: 6bffce55cc46ee339c9d0d5493b8c11049c0c0a68d5a1687ceec149cf42e22abaec29c12348814d0663099312e9dc90316246d57595c2b12777046f37e971d0b
languageName: node
linkType: hard
-"@algolia/client-search@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/client-search@npm:4.24.0"
+"@algolia/client-search@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/client-search@npm:5.52.1"
dependencies:
- "@algolia/client-common": 4.24.0
- "@algolia/requester-common": 4.24.0
- "@algolia/transporter": 4.24.0
- checksum: 2d19823994e92490885115188d75994fbcc7a407fbe14f52034b191607a51081ed476e367a65c889666f6b337b00d700203204d55666f182809f01fbd29fd1fb
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: 4378e7e00884b118b602a5aba20a200e836f3847b3e9f55977c734827160116f622d7c21dc3c93189aeb2c648e802efcd34f4f5c8d065f5380dca843c2e2c1b0
languageName: node
linkType: hard
@@ -135,74 +226,137 @@ __metadata:
languageName: node
linkType: hard
-"@algolia/logger-common@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/logger-common@npm:4.24.0"
- checksum: 668fb5a2cbb6aaea7648ae522b5d088241589a9da9f8abb53e2daa89ca2d0bc04307291f57c65de7a332e092cc054cc98cc21b12af81620099632ca85c4ef074
+"@algolia/ingestion@npm:1.52.1":
+ version: 1.52.1
+ resolution: "@algolia/ingestion@npm:1.52.1"
+ dependencies:
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: eb198762f95480f694b32b548ab22367b8096baa45ae8418c92a63b9eb53b9fdf992733c6d2f38237521b116ab7595c4048a3da5b5a7f1e7104260775566e768
+ languageName: node
+ linkType: hard
+
+"@algolia/logger-common@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/logger-common@npm:4.27.0"
+ checksum: 1d3c7b445bda72a2696123fcc9bc4e2702908e258ee0596b738e92c169d2524c26b29c7a5eb1c979f1823f5fbb9537113fe3aa56e57c6240c2f51f1ed80f2ec2
+ languageName: node
+ linkType: hard
+
+"@algolia/logger-console@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/logger-console@npm:4.27.0"
+ dependencies:
+ "@algolia/logger-common": 4.27.0
+ checksum: ec187e61c07dd528ae059684dcb99bab1e6b530a8c717b5e5e124da1d998b85a8cd376d55540ea490c2aee2b3bdf24b5d4b41e3f72c4974a15b1bcb309de6189
+ languageName: node
+ linkType: hard
+
+"@algolia/monitoring@npm:1.52.1":
+ version: 1.52.1
+ resolution: "@algolia/monitoring@npm:1.52.1"
+ dependencies:
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: e51cf342fb80f95c38d1a4556d0ffef3f3cf007edd965077cd1071acebcd5d76ef11218e6c602f3d623ea93857f1b91fb11406df4edb022c01cb5281698df0b1
+ languageName: node
+ linkType: hard
+
+"@algolia/recommend@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/recommend@npm:4.27.0"
+ dependencies:
+ "@algolia/cache-browser-local-storage": 4.27.0
+ "@algolia/cache-common": 4.27.0
+ "@algolia/cache-in-memory": 4.27.0
+ "@algolia/client-common": 4.27.0
+ "@algolia/client-search": 4.27.0
+ "@algolia/logger-common": 4.27.0
+ "@algolia/logger-console": 4.27.0
+ "@algolia/requester-browser-xhr": 4.27.0
+ "@algolia/requester-common": 4.27.0
+ "@algolia/requester-node-http": 4.27.0
+ "@algolia/transporter": 4.27.0
+ checksum: f9e385ec1ac864acb9430710cae4cdb74e4c9627a83bbc1a9f929b33034998157b939df273dc6924f2665da6e3d986a1ab6d605b34b680a88d59cfca056c4369
+ languageName: node
+ linkType: hard
+
+"@algolia/recommend@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/recommend@npm:5.52.1"
+ dependencies:
+ "@algolia/client-common": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: 6f87737895f9e47ddcd2dafcda3086ac0a85cdcd50af6f159319d404cfda65895a86d98ef9e02ef427a25ee4d828932c9ccf756ad1d42531993aa9b428625bcf
languageName: node
linkType: hard
-"@algolia/logger-console@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/logger-console@npm:4.24.0"
+"@algolia/requester-browser-xhr@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/requester-browser-xhr@npm:4.27.0"
dependencies:
- "@algolia/logger-common": 4.24.0
- checksum: 846d94ecac2e914a2aa7d1ace301cca7371b2bc757c737405eca8d29fc1a26e788387862851c90f611c90f43755367ce676802a21fa37a3bf8531b1a16f5183b
+ "@algolia/requester-common": 4.27.0
+ checksum: 8ca2bc006b68cf703cd659f99db04abcf3ff3e89c0633ecab7eb0d26acad030121fcd3f7e2990efb7fa16f389d0109ee4d4aefc4f95d4d57dacd8ff16289eee9
languageName: node
linkType: hard
-"@algolia/recommend@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/recommend@npm:4.24.0"
+"@algolia/requester-browser-xhr@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/requester-browser-xhr@npm:5.52.1"
dependencies:
- "@algolia/cache-browser-local-storage": 4.24.0
- "@algolia/cache-common": 4.24.0
- "@algolia/cache-in-memory": 4.24.0
- "@algolia/client-common": 4.24.0
- "@algolia/client-search": 4.24.0
- "@algolia/logger-common": 4.24.0
- "@algolia/logger-console": 4.24.0
- "@algolia/requester-browser-xhr": 4.24.0
- "@algolia/requester-common": 4.24.0
- "@algolia/requester-node-http": 4.24.0
- "@algolia/transporter": 4.24.0
- checksum: 426468452186cbcf0653c3a8c8a4f911def6232dc262f0a310c4583939c6efc5a1c567dbff99b6c99a93f2ba05f9336a60d3fc6c9a74ad2d8d13f4c4fa55d3d8
+ "@algolia/client-common": 5.52.1
+ checksum: 6446631d19866f781570adaba883e987f538391e66e96ed2fc7449df4b90d557461d5ad733b3c4e96162b7774429bcad0e03643deb0e5cc2f4a90e739073a024
languageName: node
linkType: hard
-"@algolia/requester-browser-xhr@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/requester-browser-xhr@npm:4.24.0"
+"@algolia/requester-common@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/requester-common@npm:4.27.0"
+ checksum: ed02765be7d7a769c77efe0c418621fbe53c5800d678c7bd7d85c6b9e3eb3fb0009daa9f50d54257eabf39aec9d3da0d8de5e7a51519771cfd51e770be6a328d
+ languageName: node
+ linkType: hard
+
+"@algolia/requester-fetch@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/requester-fetch@npm:5.52.1"
dependencies:
- "@algolia/requester-common": 4.24.0
- checksum: 7c32d38d6c7a83357f52134f50271f1ee3df63888b28bc53040a3c74ef73458d80efaf44a5943a3769e84737c2ffd0743e1044a3b5e99ce69289f63e22b50f2a
+ "@algolia/client-common": 5.52.1
+ checksum: 625c6d803ba0b2f307da0a12c6a1cef1f3e2ca774be268825a5b00dc37ab33c7533aa153c1ff1c986c9d23788252d48ac8f133cd948c067ecc1c4c61cee6d102
languageName: node
linkType: hard
-"@algolia/requester-common@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/requester-common@npm:4.24.0"
- checksum: 8f4a49ef0fb4aca42fa3703ddf97ff7f6e9c8492928aa66704ca2f54d3785d2338b64917860a01a42dedb1621279558ca7d549c5b1eb5b7f2742f952fb9865e5
+"@algolia/requester-node-http@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/requester-node-http@npm:4.27.0"
+ dependencies:
+ "@algolia/requester-common": 4.27.0
+ checksum: 4dcce64b4918b9748db8ea97b6b10125269275b800a5cd9d2012aaae5df512ff06d2cba3ca5b69597a91e1bb0cac3d2b276f3858500f4c833ccc1e35871c0cc0
languageName: node
linkType: hard
-"@algolia/requester-node-http@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/requester-node-http@npm:4.24.0"
+"@algolia/requester-node-http@npm:5.52.1":
+ version: 5.52.1
+ resolution: "@algolia/requester-node-http@npm:5.52.1"
dependencies:
- "@algolia/requester-common": 4.24.0
- checksum: 387ee892bf35f46be269996de88f9ea12841796aa33cb5088ba6460a48733614a33300ee44bca0af22b6fded05c16ec92631fb998e9a7e1e6a30504d8b407c23
+ "@algolia/client-common": 5.52.1
+ checksum: 436b9bdb8b8d87b83217ecce4560654babc75e10da8a5b2861526a2521ec88b97ee43c3ea7bb43b5f1d66ebe74b6b10dd41f1269305114b12882e8bbb620b4f8
languageName: node
linkType: hard
-"@algolia/transporter@npm:4.24.0":
- version: 4.24.0
- resolution: "@algolia/transporter@npm:4.24.0"
+"@algolia/transporter@npm:4.27.0":
+ version: 4.27.0
+ resolution: "@algolia/transporter@npm:4.27.0"
dependencies:
- "@algolia/cache-common": 4.24.0
- "@algolia/logger-common": 4.24.0
- "@algolia/requester-common": 4.24.0
- checksum: 2c026a777de5dcb6f3cc94a0cf5f4650fbc7067f56eb98a1ae9b5750815179a73eb2b1d8ae75853a99823afd13584b62430d7649c65a456b2623123f355955b1
+ "@algolia/cache-common": 4.27.0
+ "@algolia/logger-common": 4.27.0
+ "@algolia/requester-common": 4.27.0
+ checksum: 50217ead18cb5ddbc097a43da2d770787ac8cff8930a3134751739c4666e782611b3bad1401dc912ba71836311ea8d9fdaaf25b50dddde60297c031a67bff7f0
languageName: node
linkType: hard
@@ -216,7 +370,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.8.3":
+"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/code-frame@npm:7.24.7"
dependencies:
@@ -226,6 +380,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.28.6, @babel/code-frame@npm:^7.29.0, @babel/code-frame@npm:^7.8.3":
+ version: 7.29.0
+ resolution: "@babel/code-frame@npm:7.29.0"
+ dependencies:
+ "@babel/helper-validator-identifier": ^7.28.5
+ js-tokens: ^4.0.0
+ picocolors: ^1.1.1
+ checksum: 39f5b303757e4d63bbff8133e251094cd4f952b46e3fa9febc7368d907583911d6a1eded6090876dc1feeff5cf6e134fb19b706f8d58d26c5402cd50e5e1aeb2
+ languageName: node
+ linkType: hard
+
"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.2":
version: 7.25.2
resolution: "@babel/compat-data@npm:7.25.2"
@@ -233,7 +398,14 @@ __metadata:
languageName: node
linkType: hard
-"@babel/core@npm:^7.21.3, @babel/core@npm:^7.23.3":
+"@babel/compat-data@npm:^7.28.6, @babel/compat-data@npm:^7.29.3":
+ version: 7.29.3
+ resolution: "@babel/compat-data@npm:7.29.3"
+ checksum: 977192bab334f66bc8150026340a33ed318c1a7ce18a9323f4c1b86f8ed1d8645bfe5600242bf682717c05c46a4ff06225242207c1d599f4296914b9b4e3efb5
+ languageName: node
+ linkType: hard
+
+"@babel/core@npm:^7.21.3":
version: 7.25.2
resolution: "@babel/core@npm:7.25.2"
dependencies:
@@ -256,7 +428,43 @@ __metadata:
languageName: node
linkType: hard
-"@babel/generator@npm:^7.23.3, @babel/generator@npm:^7.25.0":
+"@babel/core@npm:^7.23.3":
+ version: 7.29.0
+ resolution: "@babel/core@npm:7.29.0"
+ dependencies:
+ "@babel/code-frame": ^7.29.0
+ "@babel/generator": ^7.29.0
+ "@babel/helper-compilation-targets": ^7.28.6
+ "@babel/helper-module-transforms": ^7.28.6
+ "@babel/helpers": ^7.28.6
+ "@babel/parser": ^7.29.0
+ "@babel/template": ^7.28.6
+ "@babel/traverse": ^7.29.0
+ "@babel/types": ^7.29.0
+ "@jridgewell/remapping": ^2.3.5
+ convert-source-map: ^2.0.0
+ debug: ^4.1.0
+ gensync: ^1.0.0-beta.2
+ json5: ^2.2.3
+ semver: ^6.3.1
+ checksum: 85e1df6e213382c46dee27bcd07ed9202fa108a85bb74eb37be656308fd949349171ad2aa17cc84cf0720c908dc9ea6309d25e64d2a7fcdaa63721ce0c67c10b
+ languageName: node
+ linkType: hard
+
+"@babel/generator@npm:^7.23.3, @babel/generator@npm:^7.29.0":
+ version: 7.29.1
+ resolution: "@babel/generator@npm:7.29.1"
+ dependencies:
+ "@babel/parser": ^7.29.0
+ "@babel/types": ^7.29.0
+ "@jridgewell/gen-mapping": ^0.3.12
+ "@jridgewell/trace-mapping": ^0.3.28
+ jsesc: ^3.0.2
+ checksum: d8e6863b2d04f684e65ad72731049ac7d754d3a3d1a67cdfc20807b109ba3180ed90d7ccef58ce5d38ded2eaeb71983a76c711eecb9b6266118262378f6c7226
+ languageName: node
+ linkType: hard
+
+"@babel/generator@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/generator@npm:7.25.0"
dependencies:
@@ -277,6 +485,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-annotate-as-pure@npm:^7.27.1, @babel/helper-annotate-as-pure@npm:^7.27.3":
+ version: 7.27.3
+ resolution: "@babel/helper-annotate-as-pure@npm:7.27.3"
+ dependencies:
+ "@babel/types": ^7.27.3
+ checksum: 63863a5c936ef82b546ca289c9d1b18fabfc24da5c4ee382830b124e2e79b68d626207febc8d4bffc720f50b2ee65691d7d12cc0308679dee2cd6bdc926b7190
+ languageName: node
+ linkType: hard
+
"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.24.7"
@@ -300,6 +517,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-compilation-targets@npm:^7.27.1, @babel/helper-compilation-targets@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/helper-compilation-targets@npm:7.28.6"
+ dependencies:
+ "@babel/compat-data": ^7.28.6
+ "@babel/helper-validator-option": ^7.27.1
+ browserslist: ^4.24.0
+ lru-cache: ^5.1.1
+ semver: ^6.3.1
+ checksum: 8151e36b74eb1c5e414fe945c189436421f7bfa011884de5be3dd7fd77f12f1f733ff7c982581dfa0a49d8af724450243c2409427114b4a6cfeb8333259d001c
+ languageName: node
+ linkType: hard
+
"@babel/helper-create-class-features-plugin@npm:^7.24.7, @babel/helper-create-class-features-plugin@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/helper-create-class-features-plugin@npm:7.25.0"
@@ -317,6 +547,23 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-create-class-features-plugin@npm:^7.28.6":
+ version: 7.29.3
+ resolution: "@babel/helper-create-class-features-plugin@npm:7.29.3"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.27.3
+ "@babel/helper-member-expression-to-functions": ^7.28.5
+ "@babel/helper-optimise-call-expression": ^7.27.1
+ "@babel/helper-replace-supers": ^7.28.6
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.27.1
+ "@babel/traverse": ^7.29.0
+ semver: ^6.3.1
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: ed7e755d83a59679ea9554b733e2f4b41fd1dd68ef4d8d3e5009930d8ff323f7aabdb8577abea0d98e5cc62a7ce5d14aca501e4446ccfe397c6c2fa3d8164f4b
+ languageName: node
+ linkType: hard
+
"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.7, @babel/helper-create-regexp-features-plugin@npm:^7.25.0":
version: 7.25.2
resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.2"
@@ -330,6 +577,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-create-regexp-features-plugin@npm:^7.27.1, @babel/helper-create-regexp-features-plugin@npm:^7.28.5":
+ version: 7.28.5
+ resolution: "@babel/helper-create-regexp-features-plugin@npm:7.28.5"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.27.3
+ regexpu-core: ^6.3.1
+ semver: ^6.3.1
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: de202103e6ff8cd8da0d62eb269fcceb29857f3fa16173f0ff38188fd514e9ad4901aef1d590ff8ba25381644b42eaf70ad9ba91fda59fe7aa6a5e694cdde267
+ languageName: node
+ linkType: hard
+
"@babel/helper-define-polyfill-provider@npm:^0.6.2":
version: 0.6.2
resolution: "@babel/helper-define-polyfill-provider@npm:0.6.2"
@@ -345,6 +605,28 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-define-polyfill-provider@npm:^0.6.5, @babel/helper-define-polyfill-provider@npm:^0.6.8":
+ version: 0.6.8
+ resolution: "@babel/helper-define-polyfill-provider@npm:0.6.8"
+ dependencies:
+ "@babel/helper-compilation-targets": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ debug: ^4.4.3
+ lodash.debounce: ^4.0.8
+ resolve: ^1.22.11
+ peerDependencies:
+ "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
+ checksum: 39fef64ade79253836320c7826895d948ab5e8e21479cf29f5d6bb5284126693ca537b6ace9d9b7b515a8be66bd4a8a7d7687f9b25b7574a52dae7790fcd3a4e
+ languageName: node
+ linkType: hard
+
+"@babel/helper-globals@npm:^7.28.0":
+ version: 7.28.0
+ resolution: "@babel/helper-globals@npm:7.28.0"
+ checksum: d8d7b91c12dad1ee747968af0cb73baf91053b2bcf78634da2c2c4991fb45ede9bd0c8f9b5f3254881242bc0921218fcb7c28ae885477c25177147e978ce4397
+ languageName: node
+ linkType: hard
+
"@babel/helper-member-expression-to-functions@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/helper-member-expression-to-functions@npm:7.24.8"
@@ -355,6 +637,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-member-expression-to-functions@npm:^7.28.5":
+ version: 7.28.5
+ resolution: "@babel/helper-member-expression-to-functions@npm:7.28.5"
+ dependencies:
+ "@babel/traverse": ^7.28.5
+ "@babel/types": ^7.28.5
+ checksum: 447d385233bae2eea713df1785f819b5a5ca272950740da123c42d23f491045120f0fbbb5609c091f7a9bbd40f289a442846dde0cb1bf0c59440fa093690cf7c
+ languageName: node
+ linkType: hard
+
"@babel/helper-module-imports@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-module-imports@npm:7.24.7"
@@ -365,6 +657,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-module-imports@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/helper-module-imports@npm:7.28.6"
+ dependencies:
+ "@babel/traverse": ^7.28.6
+ "@babel/types": ^7.28.6
+ checksum: 437513aa029898b588a38f7991d7656c539b22f595207d85d0c407240c9e3f2aff8b9d0d7115fdedc91e7fdce4465100549a052024e2fba6a810bcbb7584296b
+ languageName: node
+ linkType: hard
+
"@babel/helper-module-transforms@npm:^7.24.7, @babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.25.0, @babel/helper-module-transforms@npm:^7.25.2":
version: 7.25.2
resolution: "@babel/helper-module-transforms@npm:7.25.2"
@@ -379,6 +681,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-module-transforms@npm:^7.27.1, @babel/helper-module-transforms@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/helper-module-transforms@npm:7.28.6"
+ dependencies:
+ "@babel/helper-module-imports": ^7.28.6
+ "@babel/helper-validator-identifier": ^7.28.5
+ "@babel/traverse": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 522f7d1d08b5e2ccd4ec912aca879bd1506af78d1fb30f46e3e6b4bb69c6ae6ab4e379a879723844230d27dc6d04a55b03f5215cd3141b7a2b40bb4a02f71a9f
+ languageName: node
+ linkType: hard
+
"@babel/helper-optimise-call-expression@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-optimise-call-expression@npm:7.24.7"
@@ -388,6 +703,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-optimise-call-expression@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/helper-optimise-call-expression@npm:7.27.1"
+ dependencies:
+ "@babel/types": ^7.27.1
+ checksum: 0fb7ee824a384529d6b74f8a58279f9b56bfe3cce332168067dddeab2552d8eeb56dc8eaf86c04a3a09166a316cb92dfc79c4c623cd034ad4c563952c98b464f
+ languageName: node
+ linkType: hard
+
"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3":
version: 7.24.8
resolution: "@babel/helper-plugin-utils@npm:7.24.8"
@@ -395,6 +719,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-plugin-utils@npm:^7.27.1, @babel/helper-plugin-utils@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/helper-plugin-utils@npm:7.28.6"
+ checksum: a0b4caab5e2180b215faa4d141ceac9e82fad9d446b8023eaeb8d82a6e62024726675b07fe8e616dd12f34e2bb59747e8d57aa8adab3e0717d1b8d691b118379
+ languageName: node
+ linkType: hard
+
"@babel/helper-remap-async-to-generator@npm:^7.24.7, @babel/helper-remap-async-to-generator@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/helper-remap-async-to-generator@npm:7.25.0"
@@ -408,6 +739,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-remap-async-to-generator@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/helper-remap-async-to-generator@npm:7.27.1"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.27.1
+ "@babel/helper-wrap-function": ^7.27.1
+ "@babel/traverse": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 0747397ba013f87dbf575454a76c18210d61c7c9af0f697546b4bcac670b54ddc156330234407b397f0c948738c304c228e0223039bc45eab4fbf46966a5e8cc
+ languageName: node
+ linkType: hard
+
"@babel/helper-replace-supers@npm:^7.24.7, @babel/helper-replace-supers@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/helper-replace-supers@npm:7.25.0"
@@ -421,6 +765,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-replace-supers@npm:^7.27.1, @babel/helper-replace-supers@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/helper-replace-supers@npm:7.28.6"
+ dependencies:
+ "@babel/helper-member-expression-to-functions": ^7.28.5
+ "@babel/helper-optimise-call-expression": ^7.27.1
+ "@babel/traverse": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: aa6530a52010883b6be88465e3b9e789509786a40203650a23a51c315f7442b196e5925fb8e2d66d1e3dc2c604cdc817bd8c5c170dbb322ab5ebc7486fd8a022
+ languageName: node
+ linkType: hard
+
"@babel/helper-simple-access@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-simple-access@npm:7.24.7"
@@ -441,6 +798,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-skip-transparent-expression-wrappers@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.27.1"
+ dependencies:
+ "@babel/traverse": ^7.27.1
+ "@babel/types": ^7.27.1
+ checksum: 4f380c5d0e0769fa6942a468b0c2d7c8f0c438f941aaa88f785f8752c103631d0904c7b4e76207a3b0e6588b2dec376595370d92ca8f8f1b422c14a69aa146d4
+ languageName: node
+ linkType: hard
+
"@babel/helper-string-parser@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/helper-string-parser@npm:7.24.8"
@@ -448,6 +815,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-string-parser@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/helper-string-parser@npm:7.27.1"
+ checksum: 0a8464adc4b39b138aedcb443b09f4005d86207d7126e5e079177e05c3116107d856ec08282b365e9a79a9872f40f4092a6127f8d74c8a01c1ef789dacfc25d6
+ languageName: node
+ linkType: hard
+
"@babel/helper-validator-identifier@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-validator-identifier@npm:7.24.7"
@@ -455,6 +829,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-validator-identifier@npm:^7.28.5":
+ version: 7.28.5
+ resolution: "@babel/helper-validator-identifier@npm:7.28.5"
+ checksum: 5a251a6848e9712aea0338f659a1a3bd334d26219d5511164544ca8ec20774f098c3a6661e9da65a0d085c745c00bb62c8fada38a62f08fa1f8053bc0aeb57e4
+ languageName: node
+ linkType: hard
+
"@babel/helper-validator-option@npm:^7.24.7, @babel/helper-validator-option@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/helper-validator-option@npm:7.24.8"
@@ -462,6 +843,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-validator-option@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/helper-validator-option@npm:7.27.1"
+ checksum: db73e6a308092531c629ee5de7f0d04390835b21a263be2644276cb27da2384b64676cab9f22cd8d8dbd854c92b1d7d56fc8517cf0070c35d1c14a8c828b0903
+ languageName: node
+ linkType: hard
+
"@babel/helper-wrap-function@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/helper-wrap-function@npm:7.25.0"
@@ -473,6 +861,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-wrap-function@npm:^7.27.1":
+ version: 7.28.6
+ resolution: "@babel/helper-wrap-function@npm:7.28.6"
+ dependencies:
+ "@babel/template": ^7.28.6
+ "@babel/traverse": ^7.28.6
+ "@babel/types": ^7.28.6
+ checksum: 1281f45d55ff291711de7cf05b8132fc28b8d2b30c6c9cf8fce68669bbe318503ed485057d434efa1a4f91ab55d62bf8f3ecb0a889a9f81d357ad4614cd0fa6c
+ languageName: node
+ linkType: hard
+
"@babel/helpers@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/helpers@npm:7.25.0"
@@ -483,6 +882,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helpers@npm:^7.28.6":
+ version: 7.29.2
+ resolution: "@babel/helpers@npm:7.29.2"
+ dependencies:
+ "@babel/template": ^7.28.6
+ "@babel/types": ^7.29.0
+ checksum: 2c8ce711a639ef334539d3bd48977f57493f71af99e13d3f685fe47b3bc32aa83dbc1380688e19d5df924d958f8f29072f3dcff8110257ba6399524907287189
+ languageName: node
+ linkType: hard
+
"@babel/highlight@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/highlight@npm:7.24.7"
@@ -506,6 +915,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0":
+ version: 7.29.3
+ resolution: "@babel/parser@npm:7.29.3"
+ dependencies:
+ "@babel/types": ^7.29.0
+ bin:
+ parser: ./bin/babel-parser.js
+ checksum: 046f46996bf4053b6e29f8a7f420f9e0a2878593c1c9a9914a36faca23fc544a307c78a0101ba3ae98936ade68bdde686a83e1ab2b74c2ebb80dc4a9df48476d
+ languageName: node
+ linkType: hard
+
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.3":
version: 7.25.3
resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.3"
@@ -518,6 +938,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.28.5":
+ version: 7.28.5
+ resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.28.5"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ "@babel/traverse": ^7.28.5
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 749b40a963d5633f554cad0336245cb6c1c1393c70a3fddcf302d86a1a42b35efdd2ed62056b88db66f3900887ae1cee9a3eeec89799c22e0cf65059f0dfd142
+ languageName: node
+ linkType: hard
+
"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.25.0"
@@ -529,6 +961,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: eb7f4146dc01f1198ce559a90b077e58b951a07521ec414e3c7d4593bf6c4ab5c2af22242a7e9fec085e20299e0ba6ea97f44a45e84ab148141bf9eb959ad25e
+ languageName: node
+ linkType: hard
+
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.25.0"
@@ -540,6 +983,29 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 621cfddfcc99a81e74f8b6f9101fd260b27500cb1a568e3ceae9cc8afe9aee45ac3bca3900a2b66c612b1a2366d29ef67d4df5a1c975be727eaad6906f98c2c6
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@npm:^7.29.3":
+ version: 7.29.3
+ resolution: "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@npm:7.29.3"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: fd13198afc9b72c6a4e4868f1592fc8010f390e7601148a71d2d6111664c0242d6d5ff27d8eb77ca4c35ef47f8416daf5dbc8d46a498ac706d69c6b3a0988cd7
+ languageName: node
+ linkType: hard
+
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.24.7"
@@ -553,6 +1019,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.27.1
+ "@babel/plugin-transform-optional-chaining": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.13.0
+ checksum: f07aa80272bd7a46b7ba11a4644da6c9b6a5a64e848dfaffdad6f02663adefd512e1aaebe664c4dd95f7ed4f80c872c7f8db8d8e34b47aae0930b412a28711a0
+ languageName: node
+ linkType: hard
+
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.25.0"
@@ -565,6 +1044,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/traverse": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: f1341f829f809c8685d839669953a478f8a40d1d53f4f5e1972bf39ff4e1ece148319340292d6e0c3641157268b435cbb99b3ac2f3cefe9fca9e81b8f62d6d71
+ languageName: node
+ linkType: hard
+
"@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2":
version: 7.21.0-placeholder-for-preset-env.2
resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2"
@@ -640,6 +1131,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-syntax-import-assertions@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-syntax-import-assertions@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 25017235e1e2c4ed892aa327a3fa10f4209cc618c6dd7806fc40c07d8d7d24a39743d3d5568b8d1c8f416cffe03c174e78874ded513c9338b07a7ab1dcbab050
+ languageName: node
+ linkType: hard
+
"@babel/plugin-syntax-import-attributes@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.7"
@@ -651,6 +1153,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-syntax-import-attributes@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-syntax-import-attributes@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 6c8c6a5988dbb9799d6027360d1a5ba64faabf551f2ef11ba4eade0c62253b5c85d44ddc8eb643c74b9acb2bcaa664a950bd5de9a5d4aef291c4f2a48223bb4b
+ languageName: node
+ linkType: hard
+
"@babel/plugin-syntax-import-meta@npm:^7.10.4":
version: 7.10.4
resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4"
@@ -684,6 +1197,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-syntax-jsx@npm:^7.27.1, @babel/plugin-syntax-jsx@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-syntax-jsx@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 572e38f5c1bb4b8124300e7e3dd13e82ae84a21f90d3f0786c98cd05e63c78ca1f32d1cfe462dfbaf5e7d5102fa7cd8fd741dfe4f3afc2e01a3b2877dcc8c866
+ languageName: node
+ linkType: hard
+
"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4":
version: 7.10.4
resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4"
@@ -783,6 +1307,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-syntax-typescript@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-syntax-typescript@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 5c55f9c63bd36cf3d7e8db892294c8f85000f9c1526c3a1cc310d47d1e174f5c6f6605e5cc902c4636d885faba7a9f3d5e5edc6b35e4f3b1fd4c2d58d0304fa5
+ languageName: node
+ linkType: hard
+
"@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6"
@@ -806,6 +1341,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-arrow-functions@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-arrow-functions@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 62c2cc0ae2093336b1aa1376741c5ed245c0987d9e4b4c5313da4a38155509a7098b5acce582b6781cc0699381420010da2e3086353344abe0a6a0ec38961eb7
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-async-generator-functions@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.0"
@@ -820,6 +1366,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-async-generator-functions@npm:^7.29.0":
+ version: 7.29.0
+ resolution: "@babel/plugin-transform-async-generator-functions@npm:7.29.0"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/helper-remap-async-to-generator": ^7.27.1
+ "@babel/traverse": ^7.29.0
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: bd549b54283034dd3e2f6c4b41b99a0caba0ddc8e9418490a611136ddb01e62235f14b233fcc172902fd1d18eec6e029245d22212566ea5cb5e24c7450d6005d
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-async-to-generator@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-async-to-generator@npm:7.24.7"
@@ -833,6 +1392,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-async-to-generator@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-async-to-generator@npm:7.28.6"
+ dependencies:
+ "@babel/helper-module-imports": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/helper-remap-async-to-generator": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: bca5774263ec01dd2bf71c74bbaf7baa183bf03576636b7826c3346be70c8c8cb15cff549112f2983c36885131a0afde6c443591278c281f733ee17f455aa9b1
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-block-scoped-functions@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.24.7"
@@ -844,9 +1416,20 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-block-scoping@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/plugin-transform-block-scoping@npm:7.25.0"
+"@babel/plugin-transform-block-scoped-functions@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 7fb4988ca80cf1fc8345310d5edfe38e86b3a72a302675cdd09404d5064fe1d1fe1283ebe658ad2b71445ecef857bfb29a748064306b5f6c628e0084759c2201
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-block-scoping@npm:^7.25.0":
+ version: 7.25.0
+ resolution: "@babel/plugin-transform-block-scoping@npm:7.25.0"
dependencies:
"@babel/helper-plugin-utils": ^7.24.8
peerDependencies:
@@ -855,6 +1438,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-block-scoping@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-block-scoping@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: cb4f71ac4fc7b32c2e3cc167eb9e7a1a11562127d702e3b5093567750e9a4eb11a29ae5a917f62741bf9d5792bfe3022cbcdcc7bb927ddb6f627b6749a38c118
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-class-properties@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-class-properties@npm:7.24.7"
@@ -867,6 +1461,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-class-properties@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-class-properties@npm:7.28.6"
+ dependencies:
+ "@babel/helper-create-class-features-plugin": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 200f30d44b36a768fa3a8cf690db9e333996af2ad14d9fa1b4c91a427ed9302907873b219b4ce87517ca1014a810eb2e929a6a66be68473f72b546fc64d04fbc
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-class-static-block@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-class-static-block@npm:7.24.7"
@@ -880,6 +1486,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-class-static-block@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-class-static-block@npm:7.28.6"
+ dependencies:
+ "@babel/helper-create-class-features-plugin": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.12.0
+ checksum: 3db326156f73a0c0d1e2ea4d73e082b9ace2f6a9c965db1c2e51f3a186751b8b91bafb184d05e046bf970b50ecfde1f74862dd895f9a5ea0fad328369d74cfc4
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-classes@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/plugin-transform-classes@npm:7.25.0"
@@ -896,6 +1514,22 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-classes@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-classes@npm:7.28.6"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.27.3
+ "@babel/helper-compilation-targets": ^7.28.6
+ "@babel/helper-globals": ^7.28.0
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/helper-replace-supers": ^7.28.6
+ "@babel/traverse": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: bddeefbfd1966272e5da6a0844d68369a0f43c286816c8b379dfd576cf835b8bc652089ef337b0334ff3ae6c9652d56d8332b78a7d29176534265c39856e4822
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-computed-properties@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-computed-properties@npm:7.24.7"
@@ -908,6 +1542,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-computed-properties@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-computed-properties@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/template": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: fd1fcc55003a2584c7461bf214ae9e9fce370ad09339319e99e29e5e55a8a3bd485d10805b3d69636a738208761b3a5b0dafdd023534396be45a36409082b014
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-destructuring@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/plugin-transform-destructuring@npm:7.24.8"
@@ -919,6 +1565,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-destructuring@npm:^7.28.5":
+ version: 7.28.5
+ resolution: "@babel/plugin-transform-destructuring@npm:7.28.5"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ "@babel/traverse": ^7.28.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 74a06e55e715cfda0fdd8be53d2655d64dfdc28dffaede329d42548fd5b1449ad26a4ce43a24c3fd277b96f8b2010c7b3915afa8297911cda740cc5cc3a81f38
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-dotall-regex@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.7"
@@ -931,6 +1589,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-dotall-regex@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-dotall-regex@npm:7.28.6"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.28.5
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 866ffbbdee77fa955063b37c75593db8dbbe46b1ebb64cc788ea437e3a9aa41cb7b9afcee617c678a32b6705baa0892ec8e5d4b8af3bbb0ab1b254514ccdbd37
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-duplicate-keys@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.7"
@@ -942,6 +1612,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-duplicate-keys@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-duplicate-keys@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: ef2112d658338e3ff0827f39a53c0cfa211f1cbbe60363bca833a5269df389598ec965e7283600b46533c39cdca82307d0d69c0f518290ec5b00bb713044715b
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.25.0"
@@ -954,6 +1635,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.29.0":
+ version: 7.29.0
+ resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.29.0"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.28.5
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 7fa7b773259a578c9e01c80946f75ecc074520064aa7a87a65db06c7df70766e2fa6be78cda55fa9418a14e30b2b9d595484a46db48074d495d9f877a4276065
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-dynamic-import@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.7"
@@ -966,6 +1659,29 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-dynamic-import@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-dynamic-import@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 7a9fbc8d17148b7f11a1d1ca3990d2c2cd44bd08a45dcaf14f20a017721235b9044b20e6168b6940282bb1b48fb78e6afbdfb9dd9d82fde614e15baa7d579932
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-explicit-resource-management@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-explicit-resource-management@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/plugin-transform-destructuring": ^7.28.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: be65403694d360793b1b626ac0dfa7c120cfe4dd1c95a81a30b6e7426dc317643e60a486d642e318a4d3d9a7193e72fdb36e2ec140c25c773dcb9c3b1e2854ef
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-exponentiation-operator@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.7"
@@ -978,6 +1694,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-exponentiation-operator@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: b232152499370435c7cd4bf3321f58e189150e35ca3722ea16533d33434b97294df1342f5499671ec48e62b71c34cdea0ca8cf317ad12594a10f6fc670315e62
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-export-namespace-from@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-export-namespace-from@npm:7.24.7"
@@ -990,6 +1717,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-export-namespace-from@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-export-namespace-from@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 85082923eca317094f08f4953d8ea2a6558b3117826c0b740676983902b7236df1f4213ad844cb38c2dae104753dbe8f1cc51f01567835d476d32f5f544a4385
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-for-of@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-for-of@npm:7.24.7"
@@ -1002,6 +1740,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-for-of@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-for-of@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: c9224e08de5d80b2c834383d4359aa9e519db434291711434dd996a4f86b7b664ad67b45d65459b7ec11fa582e3e11a3c769b8a8ca71594bdd4e2f0503f84126
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-function-name@npm:^7.25.1":
version: 7.25.1
resolution: "@babel/plugin-transform-function-name@npm:7.25.1"
@@ -1015,6 +1765,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-function-name@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-function-name@npm:7.27.1"
+ dependencies:
+ "@babel/helper-compilation-targets": ^7.27.1
+ "@babel/helper-plugin-utils": ^7.27.1
+ "@babel/traverse": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 26a2a183c3c52a96495967420a64afc5a09f743a230272a131668abf23001e393afa6371e6f8e6c60f4182bea210ed31d1caf866452d91009c1daac345a52f23
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-json-strings@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-json-strings@npm:7.24.7"
@@ -1027,6 +1790,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-json-strings@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-json-strings@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 69d82a1a0a72ed6e6f7969e09cf330516599d79b2b4e680e9dd3c57616a8c6af049b5103456e370ab56642815e80e46ed88bb81e9e059304a85c5fe0bf137c29
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-literals@npm:^7.25.2":
version: 7.25.2
resolution: "@babel/plugin-transform-literals@npm:7.25.2"
@@ -1038,6 +1812,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-literals@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-literals@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 0a76d12ab19f32dd139964aea7da48cecdb7de0b75e207e576f0f700121fe92367d788f328bf4fb44b8261a0f605c97b44e62ae61cddbb67b14e94c88b411f95
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.7"
@@ -1050,6 +1835,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-logical-assignment-operators@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 36095d5d1cfc680e95298b5389a16016da800ae3379b130dabf557e94652c47b06610407e9fa44aaa03e9b0a5aa7b4b93348123985d44a45e369bf5f3497d149
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-member-expression-literals@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-member-expression-literals@npm:7.24.7"
@@ -1061,6 +1857,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-member-expression-literals@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-member-expression-literals@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 804121430a6dcd431e6ffe99c6d1fbbc44b43478113b79c677629e7f877b4f78a06b69c6bfb2747fd84ee91879fe2eb32e4620b53124603086cf5b727593ebe8
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-modules-amd@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-modules-amd@npm:7.24.7"
@@ -1073,6 +1880,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-modules-amd@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-modules-amd@npm:7.27.1"
+ dependencies:
+ "@babel/helper-module-transforms": ^7.27.1
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 8bb36d448e438d5d30f4faf19120e8c18aa87730269e65d805bf6032824d175ed738057cc392c2c8a650028f1ae0f346cad8d6b723f31a037b586e2092a7be18
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-modules-commonjs@npm:^7.24.7, @babel/plugin-transform-modules-commonjs@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.8"
@@ -1086,6 +1905,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-modules-commonjs@npm:^7.27.1, @babel/plugin-transform-modules-commonjs@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-modules-commonjs@npm:7.28.6"
+ dependencies:
+ "@babel/helper-module-transforms": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: b48cab26fda72894c7002a9c783befbc8a643d827c52bdcc5adf83e418ca93224a15aaf7ed2d1e6284627be55913696cfa2119242686cfa77a473bf79314df26
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-modules-systemjs@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/plugin-transform-modules-systemjs@npm:7.25.0"
@@ -1100,6 +1931,20 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-modules-systemjs@npm:^7.29.4":
+ version: 7.29.4
+ resolution: "@babel/plugin-transform-modules-systemjs@npm:7.29.4"
+ dependencies:
+ "@babel/helper-module-transforms": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/helper-validator-identifier": ^7.28.5
+ "@babel/traverse": ^7.29.0
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: d9cbb30669077756048af990a08ad1ba149785c336024affa49848dc4ffc5948bfaaf52d90bbec711a1f320e19e2c60182dbeff40d81cc5b9a09a87919abe07d
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-modules-umd@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-modules-umd@npm:7.24.7"
@@ -1112,6 +1957,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-modules-umd@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-modules-umd@npm:7.27.1"
+ dependencies:
+ "@babel/helper-module-transforms": ^7.27.1
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: b007dd89231f2eeccf1c71a85629bcb692573303977a4b1c5f19a835ea6b5142c18ef07849bc6d752b874a11bc0ddf3c67468b77c8ee8310290b688a4f01ef31
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.24.7"
@@ -1124,6 +1981,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.29.0":
+ version: 7.29.0
+ resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.29.0"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.28.5
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: ed8c27699ca82a6c01cbfd39f3de16b90cfea4f8146a358057f76df290d308a66a8bd2e6734e6a87f68c18576e15d2d70548a84cd474d26fdf256c3f5ae44d8c
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-new-target@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-new-target@npm:7.24.7"
@@ -1135,6 +2004,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-new-target@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-new-target@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 32c8078d843bda001244509442d68fd3af088d7348ba883f45c262b2c817a27ffc553b0d78e7f7a763271b2ece7fac56151baad7a91fb21f5bb1d2f38e5acad7
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.7"
@@ -1147,6 +2027,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 1cdd3ca48a8fffa13dbb9949748d3dd2183cf24110cd55d702da4549205611fc12978b49886be809ec1929ff6304ac4eecc747a33dca2484f9dc655928ab5a89
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-numeric-separator@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.7"
@@ -1159,6 +2050,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-numeric-separator@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-numeric-separator@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 4b5ca60e481e22f0842761a3badca17376a230b5a7e5482338604eb95836c2d0c9c9bde53bdc5c2de1c6a12ae6c12de7464d098bf74b0943f85905ca358f0b68
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-object-rest-spread@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.7"
@@ -1173,6 +2075,21 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-object-rest-spread@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-object-rest-spread@npm:7.28.6"
+ dependencies:
+ "@babel/helper-compilation-targets": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/plugin-transform-destructuring": ^7.28.5
+ "@babel/plugin-transform-parameters": ^7.27.7
+ "@babel/traverse": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: ab85b1321f86db91aba22ad9d8e6ab65448c983214998012229f5302468527d27b908ad6b14755991c317e35d2f54ec8459a2a094a755999651fe0ac9bd2e9a6
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-object-super@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-object-super@npm:7.24.7"
@@ -1185,6 +2102,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-object-super@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-object-super@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ "@babel/helper-replace-supers": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 46b819cb9a6cd3cfefe42d07875fee414f18d5e66040366ae856116db560ad4e16f3899a0a7fddd6773e0d1458444f94b208b67c0e3b6977a27ea17a5c13dbf6
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-optional-catch-binding@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.7"
@@ -1197,6 +2126,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-optional-catch-binding@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: ee24a17defec056eb9ef01824d7e4a1f65d531af6b4b79acfd0bcb95ce0b47926e80c61897f36f8c01ce733b069c9acdb1c9ce5ec07a729d0dbf9e8d859fe992
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-optional-chaining@npm:^7.24.7, @babel/plugin-transform-optional-chaining@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.8"
@@ -1210,6 +2150,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-optional-chaining@npm:^7.27.1, @babel/plugin-transform-optional-chaining@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-optional-chaining@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: a40dbe709671a436bb69e14524805e10af81b44c422e4fc5dc905cb91adb92d650c9d266c3c2c0da0d410dea89ce784995d4118b7ab6a7544f4923e61590b386
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-parameters@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-parameters@npm:7.24.7"
@@ -1221,6 +2173,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-parameters@npm:^7.27.7":
+ version: 7.27.7
+ resolution: "@babel/plugin-transform-parameters@npm:7.27.7"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: d51f195e1d6ac5d9fce583e9a70a5bfe403e62386e5eb06db9fbc6533f895a98ff7e7c3dcaa311a8e6fa7a9794466e81cdabcba6af9f59d787fb767bfe7868b4
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-private-methods@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-private-methods@npm:7.24.7"
@@ -1233,6 +2196,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-private-methods@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-private-methods@npm:7.28.6"
+ dependencies:
+ "@babel/helper-create-class-features-plugin": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: b80179b28f6a165674d0b0d6c6349b13a01dd282b18f56933423c0a33c23fc0626c8f011f859fc20737d021fe966eb8474a5233e4596401482e9ee7fb00e2aa2
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-private-property-in-object@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.7"
@@ -1247,6 +2222,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-private-property-in-object@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-private-property-in-object@npm:7.28.6"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.27.3
+ "@babel/helper-create-class-features-plugin": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 32a935e44872e90607851be5bc2cd3365f29c0e0e3853ef3e2b6a7da4d08c647379bf2f2dc4f14a9064d7d72e2cf75da85e55baeeec1ffc25cf6088fe24422f7
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-property-literals@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-property-literals@npm:7.24.7"
@@ -1258,6 +2246,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-property-literals@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-property-literals@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 7caec27d5ed8870895c9faf4f71def72745d69da0d8e77903146a4e135fd7bed5778f5f9cebb36c5fba86338e6194dd67a08c033fc84b4299b7eceab6d9630cb
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-react-constant-elements@npm:^7.21.3":
version: 7.25.1
resolution: "@babel/plugin-transform-react-constant-elements@npm:7.25.1"
@@ -1280,6 +2279,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-react-display-name@npm:^7.28.0":
+ version: 7.28.0
+ resolution: "@babel/plugin-transform-react-display-name@npm:7.28.0"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 268b1a9192974439d17949e170b01cac2a2aa003c844e2fe3b8361146f42f66487178cffdfa8ce862aa9e6c814bc37f879a70300cb3f067815d15fa6aad04e6d
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-react-jsx-development@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-react-jsx-development@npm:7.24.7"
@@ -1291,6 +2301,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-react-jsx-development@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-react-jsx-development@npm:7.27.1"
+ dependencies:
+ "@babel/plugin-transform-react-jsx": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: b88865d5b8c018992f2332da939faa15c4d4a864c9435a5937beaff3fe43781432cc42e0a5d5631098e0bd4066fc33f5fa72203b388b074c3545fe7aaa21e474
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-react-jsx@npm:^7.24.7":
version: 7.25.2
resolution: "@babel/plugin-transform-react-jsx@npm:7.25.2"
@@ -1306,6 +2327,21 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-react-jsx@npm:^7.27.1":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-react-jsx@npm:7.28.6"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.27.3
+ "@babel/helper-module-imports": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/plugin-syntax-jsx": ^7.28.6
+ "@babel/types": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: e7d093b5ed6c06563e801d44d1212b451445d7600756efd7b8b8e6db4585c27fa8145176dcb3350968c59381af6c566dae9b6dc97ec15d2837493b238904d1c2
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-react-pure-annotations@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.24.7"
@@ -1318,6 +2354,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-react-pure-annotations@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.27.1"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.27.1
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: a6f591c5e85a1ab0685d4a25afe591fe8d11dc0b73c677cf9560ff8d540d036a1cce9efcb729fc9092def4d854dc304ffdc063a89a9247900b69c516bf971a4c
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-regenerator@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-regenerator@npm:7.24.7"
@@ -1330,6 +2378,29 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-regenerator@npm:^7.29.0":
+ version: 7.29.0
+ resolution: "@babel/plugin-transform-regenerator@npm:7.29.0"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: f48bc814f11239f2bfe010a6e29d5ac2443e7b1d8004e7c022effa111b743491127acf8644cfef475edb86b91f123829585867bc13762652aabd9b85ed6ce61e
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-regexp-modifiers@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-regexp-modifiers@npm:7.28.6"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.28.5
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 5aacc570034c085afa0165137bb9a04cd4299b86eb9092933a96dcc1132c8f591d9d534419988f5f762b2f70d43a3c719a6b8fa05fdd3b2b1820d01cf85500da
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-reserved-words@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-reserved-words@npm:7.24.7"
@@ -1341,19 +2412,30 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-runtime@npm:^7.22.9":
- version: 7.24.7
- resolution: "@babel/plugin-transform-runtime@npm:7.24.7"
+"@babel/plugin-transform-reserved-words@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-reserved-words@npm:7.27.1"
dependencies:
- "@babel/helper-module-imports": ^7.24.7
- "@babel/helper-plugin-utils": ^7.24.7
- babel-plugin-polyfill-corejs2: ^0.4.10
- babel-plugin-polyfill-corejs3: ^0.10.1
- babel-plugin-polyfill-regenerator: ^0.6.1
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: dea0b66742d2863b369c06c053e11e15ba785892ea19cccf7aef3c1bdaa38b6ab082e19984c5ea7810d275d9445c5400fcc385ad71ce707ed9256fadb102af3b
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-runtime@npm:^7.22.9":
+ version: 7.29.0
+ resolution: "@babel/plugin-transform-runtime@npm:7.29.0"
+ dependencies:
+ "@babel/helper-module-imports": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ babel-plugin-polyfill-corejs2: ^0.4.14
+ babel-plugin-polyfill-corejs3: ^0.13.0
+ babel-plugin-polyfill-regenerator: ^0.6.5
semver: ^6.3.1
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 98bcbbdc833d5c451189a6325f88820fe92973e119c59ce74bf28681cf4687c8280decb55b6c47f22e98c3973ae3a13521c4f51855a2b8577b230ecb1b4ca5b4
+ checksum: 1d3a5951396469372d954538fb188479b86afa8e02ca541da8f123250aaed8df65573b68f67087f4b15a5ccff9abc3a3fdb1d9a07fbb85bfcb807168d7364a37
languageName: node
linkType: hard
@@ -1368,6 +2450,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-shorthand-properties@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-shorthand-properties@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: fbba6e2aef0b69681acb68202aa249c0598e470cc0853d7ff5bd0171fd6a7ec31d77cfabcce9df6360fc8349eded7e4a65218c32551bd3fc0caaa1ac899ac6d4
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-spread@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-spread@npm:7.24.7"
@@ -1380,6 +2473,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-spread@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-spread@npm:7.28.6"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: e4782578904df68f7d2b3e865f20701c71d6aba0027c4794c1dc08a2f805a12892a078dab483714552398a689ad4ff6786cdf4e088b073452aee7db67e37a09c
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-sticky-regex@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.7"
@@ -1391,6 +2496,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-sticky-regex@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-sticky-regex@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: e1414a502efba92c7974681767e365a8cda6c5e9e5f33472a9eaa0ce2e75cea0a9bef881ff8dda37c7810ad902f98d3c00ead92a3ac3b73a79d011df85b5a189
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-template-literals@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-template-literals@npm:7.24.7"
@@ -1402,6 +2518,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-template-literals@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-template-literals@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 93aad782503b691faef7c0893372d5243df3219b07f1f22cfc32c104af6a2e7acd6102c128439eab15336d048f1b214ca134b87b0630d8cd568bf447f78b25ce
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-typeof-symbol@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.8"
@@ -1413,6 +2540,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-typeof-symbol@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-typeof-symbol@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: ed8048c8de72c60969a64cf2273cc6d9275d8fa8db9bd25a1268273a00fb9cbd79931140311411bda1443aa56cb3961fb911d1795abacde7f0482f1d8fdf0356
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-typescript@npm:^7.24.7":
version: 7.25.2
resolution: "@babel/plugin-transform-typescript@npm:7.25.2"
@@ -1428,6 +2566,21 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-typescript@npm:^7.28.5":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-typescript@npm:7.28.6"
+ dependencies:
+ "@babel/helper-annotate-as-pure": ^7.27.3
+ "@babel/helper-create-class-features-plugin": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/helper-skip-transparent-expression-wrappers": ^7.27.1
+ "@babel/plugin-syntax-typescript": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 029add39a37e4a1960a43c3a109680462f631bc63cc8457ea65add2cce3271c9fd4d6a1782177c65ea5f77731e2f8e2bc65a9aec9cc826346ba540ecd0b97e5a
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-unicode-escapes@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.7"
@@ -1439,6 +2592,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-unicode-escapes@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-unicode-escapes@npm:7.27.1"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: d817154bc10758ddd85b716e0bc1af1a1091e088400289ab6b78a1a4d609907ce3d2f1fd51a6fd0e0c8ecbb5f8e3aab4957e0747776d132d2379e85c3ef0520a
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-unicode-property-regex@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.24.7"
@@ -1451,6 +2615,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-unicode-property-regex@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.28.6"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.28.5
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: d14e8c51aa73f592575c1543400fd67d96df6410d75c9dc10dd640fd7eecb37366a2f2368bbdd7529842532eda4af181c921bda95146c6d373c64ea59c6e9991
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-unicode-regex@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.7"
@@ -1463,6 +2639,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/plugin-transform-unicode-regex@npm:^7.27.1":
+ version: 7.27.1
+ resolution: "@babel/plugin-transform-unicode-regex@npm:7.27.1"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.27.1
+ "@babel/helper-plugin-utils": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: a34d89a2b75fb78e66d97c3dc90d4877f7e31f43316b52176f95a5dee20e9bb56ecf158eafc42a001676ddf7b393d9e67650bad6b32f5405780f25fb83cd68e3
+ languageName: node
+ linkType: hard
+
"@babel/plugin-transform-unicode-sets-regex@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.24.7"
@@ -1475,7 +2663,19 @@ __metadata:
languageName: node
linkType: hard
-"@babel/preset-env@npm:^7.20.2, @babel/preset-env@npm:^7.22.9":
+"@babel/plugin-transform-unicode-sets-regex@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.28.6"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin": ^7.28.5
+ "@babel/helper-plugin-utils": ^7.28.6
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 423971fe2eef9d18782b1c30f5f42613ee510e5b9c08760c5538a0997b36c34495acce261e0e37a27831f81330359230bd1f33c2e1822de70241002b45b7d68e
+ languageName: node
+ linkType: hard
+
+"@babel/preset-env@npm:^7.20.2":
version: 7.25.3
resolution: "@babel/preset-env@npm:7.25.3"
dependencies:
@@ -1568,6 +2768,87 @@ __metadata:
languageName: node
linkType: hard
+"@babel/preset-env@npm:^7.22.9":
+ version: 7.29.5
+ resolution: "@babel/preset-env@npm:7.29.5"
+ dependencies:
+ "@babel/compat-data": ^7.29.3
+ "@babel/helper-compilation-targets": ^7.28.6
+ "@babel/helper-plugin-utils": ^7.28.6
+ "@babel/helper-validator-option": ^7.27.1
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ^7.28.5
+ "@babel/plugin-bugfix-safari-class-field-initializer-scope": ^7.27.1
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.27.1
+ "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": ^7.29.3
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.27.1
+ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.28.6
+ "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2
+ "@babel/plugin-syntax-import-assertions": ^7.28.6
+ "@babel/plugin-syntax-import-attributes": ^7.28.6
+ "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6
+ "@babel/plugin-transform-arrow-functions": ^7.27.1
+ "@babel/plugin-transform-async-generator-functions": ^7.29.0
+ "@babel/plugin-transform-async-to-generator": ^7.28.6
+ "@babel/plugin-transform-block-scoped-functions": ^7.27.1
+ "@babel/plugin-transform-block-scoping": ^7.28.6
+ "@babel/plugin-transform-class-properties": ^7.28.6
+ "@babel/plugin-transform-class-static-block": ^7.28.6
+ "@babel/plugin-transform-classes": ^7.28.6
+ "@babel/plugin-transform-computed-properties": ^7.28.6
+ "@babel/plugin-transform-destructuring": ^7.28.5
+ "@babel/plugin-transform-dotall-regex": ^7.28.6
+ "@babel/plugin-transform-duplicate-keys": ^7.27.1
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ^7.29.0
+ "@babel/plugin-transform-dynamic-import": ^7.27.1
+ "@babel/plugin-transform-explicit-resource-management": ^7.28.6
+ "@babel/plugin-transform-exponentiation-operator": ^7.28.6
+ "@babel/plugin-transform-export-namespace-from": ^7.27.1
+ "@babel/plugin-transform-for-of": ^7.27.1
+ "@babel/plugin-transform-function-name": ^7.27.1
+ "@babel/plugin-transform-json-strings": ^7.28.6
+ "@babel/plugin-transform-literals": ^7.27.1
+ "@babel/plugin-transform-logical-assignment-operators": ^7.28.6
+ "@babel/plugin-transform-member-expression-literals": ^7.27.1
+ "@babel/plugin-transform-modules-amd": ^7.27.1
+ "@babel/plugin-transform-modules-commonjs": ^7.28.6
+ "@babel/plugin-transform-modules-systemjs": ^7.29.4
+ "@babel/plugin-transform-modules-umd": ^7.27.1
+ "@babel/plugin-transform-named-capturing-groups-regex": ^7.29.0
+ "@babel/plugin-transform-new-target": ^7.27.1
+ "@babel/plugin-transform-nullish-coalescing-operator": ^7.28.6
+ "@babel/plugin-transform-numeric-separator": ^7.28.6
+ "@babel/plugin-transform-object-rest-spread": ^7.28.6
+ "@babel/plugin-transform-object-super": ^7.27.1
+ "@babel/plugin-transform-optional-catch-binding": ^7.28.6
+ "@babel/plugin-transform-optional-chaining": ^7.28.6
+ "@babel/plugin-transform-parameters": ^7.27.7
+ "@babel/plugin-transform-private-methods": ^7.28.6
+ "@babel/plugin-transform-private-property-in-object": ^7.28.6
+ "@babel/plugin-transform-property-literals": ^7.27.1
+ "@babel/plugin-transform-regenerator": ^7.29.0
+ "@babel/plugin-transform-regexp-modifiers": ^7.28.6
+ "@babel/plugin-transform-reserved-words": ^7.27.1
+ "@babel/plugin-transform-shorthand-properties": ^7.27.1
+ "@babel/plugin-transform-spread": ^7.28.6
+ "@babel/plugin-transform-sticky-regex": ^7.27.1
+ "@babel/plugin-transform-template-literals": ^7.27.1
+ "@babel/plugin-transform-typeof-symbol": ^7.27.1
+ "@babel/plugin-transform-unicode-escapes": ^7.27.1
+ "@babel/plugin-transform-unicode-property-regex": ^7.28.6
+ "@babel/plugin-transform-unicode-regex": ^7.27.1
+ "@babel/plugin-transform-unicode-sets-regex": ^7.28.6
+ "@babel/preset-modules": 0.1.6-no-external-plugins
+ babel-plugin-polyfill-corejs2: ^0.4.15
+ babel-plugin-polyfill-corejs3: ^0.14.0
+ babel-plugin-polyfill-regenerator: ^0.6.6
+ core-js-compat: ^3.48.0
+ semver: ^6.3.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 4241d9aa5488dc6df958fe866b747fcd2fd1c1385e95e05900bc6377b1c976cb5bc2057200e8a6c1f76dc99566983e27db927b768df09d7617f61d133f760b1a
+ languageName: node
+ linkType: hard
+
"@babel/preset-modules@npm:0.1.6-no-external-plugins":
version: 0.1.6-no-external-plugins
resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins"
@@ -1581,7 +2862,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/preset-react@npm:^7.18.6, @babel/preset-react@npm:^7.22.5":
+"@babel/preset-react@npm:^7.18.6":
version: 7.24.7
resolution: "@babel/preset-react@npm:7.24.7"
dependencies:
@@ -1597,7 +2878,23 @@ __metadata:
languageName: node
linkType: hard
-"@babel/preset-typescript@npm:^7.21.0, @babel/preset-typescript@npm:^7.22.5":
+"@babel/preset-react@npm:^7.22.5":
+ version: 7.28.5
+ resolution: "@babel/preset-react@npm:7.28.5"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ "@babel/helper-validator-option": ^7.27.1
+ "@babel/plugin-transform-react-display-name": ^7.28.0
+ "@babel/plugin-transform-react-jsx": ^7.27.1
+ "@babel/plugin-transform-react-jsx-development": ^7.27.1
+ "@babel/plugin-transform-react-pure-annotations": ^7.27.1
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 13bc1fe4dde0a29d00323e46749e5beb457844507cb3afa2fefbd85d283c2d4836f9e4a780be735de58a44c505870476dc2838f1f8faf9d6f056481e65f1a0fb
+ languageName: node
+ linkType: hard
+
+"@babel/preset-typescript@npm:^7.21.0":
version: 7.24.7
resolution: "@babel/preset-typescript@npm:7.24.7"
dependencies:
@@ -1612,6 +2909,21 @@ __metadata:
languageName: node
linkType: hard
+"@babel/preset-typescript@npm:^7.22.5":
+ version: 7.28.5
+ resolution: "@babel/preset-typescript@npm:7.28.5"
+ dependencies:
+ "@babel/helper-plugin-utils": ^7.27.1
+ "@babel/helper-validator-option": ^7.27.1
+ "@babel/plugin-syntax-jsx": ^7.27.1
+ "@babel/plugin-transform-modules-commonjs": ^7.27.1
+ "@babel/plugin-transform-typescript": ^7.28.5
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 22f889835d9db1e627846e71ca2f02e2d24e2eb9ebcf9845b3b1d37bd3a53787967bafabbbcb342f06aaf7627399a7102ba6ca18f9a0e17066c865d680d2ceb9
+ languageName: node
+ linkType: hard
+
"@babel/regjsgen@npm:^0.8.0":
version: 0.8.0
resolution: "@babel/regjsgen@npm:0.8.0"
@@ -1620,16 +2932,15 @@ __metadata:
linkType: hard
"@babel/runtime-corejs3@npm:^7.22.6":
- version: 7.25.0
- resolution: "@babel/runtime-corejs3@npm:7.25.0"
+ version: 7.29.2
+ resolution: "@babel/runtime-corejs3@npm:7.29.2"
dependencies:
- core-js-pure: ^3.30.2
- regenerator-runtime: ^0.14.0
- checksum: fb23e5afc7b9077f7cec3f17b58d63154a9f329b6746f8296e7b60ade07b4d7d67a90b23bd7196e7d207e8105dd1b847d1b22a0af5a1c681365004cd63244f63
+ core-js-pure: ^3.48.0
+ checksum: 950b38dce3814c076ebd97ed6b6dbe7d4dd165d32429208d954134df5e221e060320935e5d2316f6172355070056b87eb24b0c2b099f5aa1a6a81ae549a84a36
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.8.4":
+"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.8.4":
version: 7.25.0
resolution: "@babel/runtime@npm:7.25.0"
dependencies:
@@ -1638,6 +2949,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/runtime@npm:^7.22.6":
+ version: 7.29.2
+ resolution: "@babel/runtime@npm:7.29.2"
+ checksum: d5548d1165de8995f8afc93a5694b8625409be16cd1f2250ac13e331335858ddac3cb9fd278e6c43956a130101a2203f09417938a1a96f9fb70f02b4b4172e1d
+ languageName: node
+ linkType: hard
+
"@babel/template@npm:^7.24.7, @babel/template@npm:^7.25.0":
version: 7.25.0
resolution: "@babel/template@npm:7.25.0"
@@ -1649,7 +2967,33 @@ __metadata:
languageName: node
linkType: hard
-"@babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.1, @babel/traverse@npm:^7.25.2, @babel/traverse@npm:^7.25.3":
+"@babel/template@npm:^7.28.6":
+ version: 7.28.6
+ resolution: "@babel/template@npm:7.28.6"
+ dependencies:
+ "@babel/code-frame": ^7.28.6
+ "@babel/parser": ^7.28.6
+ "@babel/types": ^7.28.6
+ checksum: 8ab6383053e226025d9491a6e795293f2140482d14f60c1244bece6bf53610ed1e251d5e164de66adab765629881c7d9416e1e540c716541d2fd0f8f36a013d7
+ languageName: node
+ linkType: hard
+
+"@babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.5, @babel/traverse@npm:^7.28.6, @babel/traverse@npm:^7.29.0":
+ version: 7.29.0
+ resolution: "@babel/traverse@npm:7.29.0"
+ dependencies:
+ "@babel/code-frame": ^7.29.0
+ "@babel/generator": ^7.29.0
+ "@babel/helper-globals": ^7.28.0
+ "@babel/parser": ^7.29.0
+ "@babel/template": ^7.28.6
+ "@babel/types": ^7.29.0
+ debug: ^4.3.1
+ checksum: fbb5085aa525b5d4ecd9fe2f5885d88413fff6ad9c0fac244c37f96069b6d3af9ce825750cd16af1d97d26fa3d354b38dbbdb5f31430e0d99ed89660ab65430e
+ languageName: node
+ linkType: hard
+
+"@babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.1, @babel/traverse@npm:^7.25.2, @babel/traverse@npm:^7.25.3":
version: 7.25.3
resolution: "@babel/traverse@npm:7.25.3"
dependencies:
@@ -1675,6 +3019,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0":
+ version: 7.29.0
+ resolution: "@babel/types@npm:7.29.0"
+ dependencies:
+ "@babel/helper-string-parser": ^7.27.1
+ "@babel/helper-validator-identifier": ^7.28.5
+ checksum: 83f190438e94c22b2574aaeef7501830311ef266eaabfb06523409f64e2fe855e522951607085d71cad286719adef14e1ba37b671f334a7cd25b0f8506a01e0b
+ languageName: node
+ linkType: hard
+
"@colors/colors@npm:1.5.0":
version: 1.5.0
resolution: "@colors/colors@npm:1.5.0"
@@ -1689,25 +3043,25 @@ __metadata:
languageName: node
linkType: hard
-"@docsearch/css@npm:3.6.1":
- version: 3.6.1
- resolution: "@docsearch/css@npm:3.6.1"
- checksum: 313ca5a0394485d73b8be73ab2119913b68cf8f446e22a4b1a965123c34aba5a130f4dc5af7ec6880126a220d6040439bb95c11b163c4569f6e2ae18d89b4c3d
+"@docsearch/css@npm:3.9.0":
+ version: 3.9.0
+ resolution: "@docsearch/css@npm:3.9.0"
+ checksum: 8e6f5a995d17881c76b31e5364274b3387917ccbc417ba183009f2655dd507244f7009d27807675f09011efcd8e13d80505e7e17eff1a5d93bcd71324a5fc262
languageName: node
linkType: hard
"@docsearch/react@npm:^3.5.2":
- version: 3.6.1
- resolution: "@docsearch/react@npm:3.6.1"
+ version: 3.9.0
+ resolution: "@docsearch/react@npm:3.9.0"
dependencies:
- "@algolia/autocomplete-core": 1.9.3
- "@algolia/autocomplete-preset-algolia": 1.9.3
- "@docsearch/css": 3.6.1
- algoliasearch: ^4.19.1
+ "@algolia/autocomplete-core": 1.17.9
+ "@algolia/autocomplete-preset-algolia": 1.17.9
+ "@docsearch/css": 3.9.0
+ algoliasearch: ^5.14.2
peerDependencies:
- "@types/react": ">= 16.8.0 < 19.0.0"
- react: ">= 16.8.0 < 19.0.0"
- react-dom: ">= 16.8.0 < 19.0.0"
+ "@types/react": ">= 16.8.0 < 20.0.0"
+ react: ">= 16.8.0 < 20.0.0"
+ react-dom: ">= 16.8.0 < 20.0.0"
search-insights: ">= 1 < 3"
peerDependenciesMeta:
"@types/react":
@@ -1718,7 +3072,7 @@ __metadata:
optional: true
search-insights:
optional: true
- checksum: e3ad0a77932f99126933316b010a6bed30b9b3547a60269708482eea792856843c80df4b8476afb8a99e3b22a0bb37a6bd684992dccc3d277ad261a0bb27473a
+ checksum: af6c531af5f4c10fb57d4d29ae47fe297e4201c5130492e2c73c34306348bf87ab05b7eeae2cb83a6c33dbe8da3754b82275b86ae0116df65f34a9e51f9291bc
languageName: node
linkType: hard
@@ -2295,6 +3649,16 @@ __metadata:
languageName: node
linkType: hard
+"@jridgewell/gen-mapping@npm:^0.3.12":
+ version: 0.3.13
+ resolution: "@jridgewell/gen-mapping@npm:0.3.13"
+ dependencies:
+ "@jridgewell/sourcemap-codec": ^1.5.0
+ "@jridgewell/trace-mapping": ^0.3.24
+ checksum: f2105acefc433337145caa3c84bba286de954f61c0bc46279bbd85a9e6a02871089717fa060413cfb6a9d44189fe8313b2d1cabf3a2eb3284d208fd5f75c54ff
+ languageName: node
+ linkType: hard
+
"@jridgewell/gen-mapping@npm:^0.3.5":
version: 0.3.5
resolution: "@jridgewell/gen-mapping@npm:0.3.5"
@@ -2306,6 +3670,16 @@ __metadata:
languageName: node
linkType: hard
+"@jridgewell/remapping@npm:^2.3.5":
+ version: 2.3.5
+ resolution: "@jridgewell/remapping@npm:2.3.5"
+ dependencies:
+ "@jridgewell/gen-mapping": ^0.3.5
+ "@jridgewell/trace-mapping": ^0.3.24
+ checksum: 4a66a7397c3dc9c6b5c14a0024b1f98c5e1d90a0dbc1e5955b5038f2db339904df2a0ee8a66559fafb4fc23ff33700a2639fd40bbdd2e9e82b58b3bdf83738e3
+ languageName: node
+ linkType: hard
+
"@jridgewell/resolve-uri@npm:^3.1.0":
version: 3.1.2
resolution: "@jridgewell/resolve-uri@npm:3.1.2"
@@ -2337,6 +3711,13 @@ __metadata:
languageName: node
linkType: hard
+"@jridgewell/sourcemap-codec@npm:^1.5.0":
+ version: 1.5.5
+ resolution: "@jridgewell/sourcemap-codec@npm:1.5.5"
+ checksum: c2e36e67971f719a8a3a85ef5a5f580622437cc723c35d03ebd0c9c0b06418700ef006f58af742791f71f6a4fc68fcfaf1f6a74ec2f9a3332860e9373459dae7
+ languageName: node
+ linkType: hard
+
"@jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25":
version: 0.3.25
resolution: "@jridgewell/trace-mapping@npm:0.3.25"
@@ -2347,6 +3728,16 @@ __metadata:
languageName: node
linkType: hard
+"@jridgewell/trace-mapping@npm:^0.3.28":
+ version: 0.3.31
+ resolution: "@jridgewell/trace-mapping@npm:0.3.31"
+ dependencies:
+ "@jridgewell/resolve-uri": ^3.1.0
+ "@jridgewell/sourcemap-codec": ^1.4.14
+ checksum: af8fda2431348ad507fbddf8e25f5d08c79ecc94594061ce402cf41bc5aba1a7b3e59bf0fd70a619b35f33983a3f488ceeba8faf56bff784f98bb5394a8b7d47
+ languageName: node
+ linkType: hard
+
"@leichtgewicht/ip-codec@npm:^2.0.1":
version: 2.0.5
resolution: "@leichtgewicht/ip-codec@npm:2.0.5"
@@ -2770,7 +4161,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/eslint-scope@npm:^3.7.3":
+"@types/eslint-scope@npm:^3.7.7":
version: 3.7.7
resolution: "@types/eslint-scope@npm:3.7.7"
dependencies:
@@ -2799,13 +4190,20 @@ __metadata:
languageName: node
linkType: hard
-"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5":
+"@types/estree@npm:*, @types/estree@npm:^1.0.0":
version: 1.0.5
resolution: "@types/estree@npm:1.0.5"
checksum: dd8b5bed28e6213b7acd0fb665a84e693554d850b0df423ac8076cc3ad5823a6bc26b0251d080bdc545af83179ede51dd3f6fa78cad2c46ed1f29624ddf3e41a
languageName: node
linkType: hard
+"@types/estree@npm:^1.0.6":
+ version: 1.0.9
+ resolution: "@types/estree@npm:1.0.9"
+ checksum: 752c0afee3ec82b8e24484bf6a27dfa093bbf3de4ef1c20ed0364fb6ad2c0c7971e7504ed9a7aaff103a47e2d945ce7a17f74951743dd944782a0735f53170de
+ languageName: node
+ linkType: hard
+
"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.33":
version: 4.19.5
resolution: "@types/express-serve-static-core@npm:4.19.5"
@@ -3330,15 +4728,6 @@ __metadata:
languageName: node
linkType: hard
-"acorn-import-attributes@npm:^1.9.5":
- version: 1.9.5
- resolution: "acorn-import-attributes@npm:1.9.5"
- peerDependencies:
- acorn: ^8
- checksum: 1c0c49b6a244503964ae46ae850baccf306e84caf99bc2010ed6103c69a423987b07b520a6c619f075d215388bd4923eccac995886a54309eda049ab78a4be95
- languageName: node
- linkType: hard
-
"acorn-jsx@npm:^5.0.0":
version: 5.3.2
resolution: "acorn-jsx@npm:5.3.2"
@@ -3357,7 +4746,7 @@ __metadata:
languageName: node
linkType: hard
-"acorn@npm:^8.0.0, acorn@npm:^8.0.4, acorn@npm:^8.11.0, acorn@npm:^8.7.1, acorn@npm:^8.8.2":
+"acorn@npm:^8.0.0, acorn@npm:^8.0.4, acorn@npm:^8.11.0, acorn@npm:^8.8.2":
version: 8.12.1
resolution: "acorn@npm:8.12.1"
bin:
@@ -3366,6 +4755,15 @@ __metadata:
languageName: node
linkType: hard
+"acorn@npm:^8.14.0":
+ version: 8.16.0
+ resolution: "acorn@npm:8.16.0"
+ bin:
+ acorn: bin/acorn
+ checksum: bbfa466cd0dbd18b4460a85e9d0fc2f35db999380892403c573261beda91f23836db2aa71fd3ae65e94424ad14ff8e2b7bd37c7a2624278fd89137cd6e448c41
+ languageName: node
+ linkType: hard
+
"address@npm:^1.0.1, address@npm:^1.1.2":
version: 1.2.2
resolution: "address@npm:1.2.2"
@@ -3426,7 +4824,19 @@ __metadata:
languageName: node
linkType: hard
-"ajv@npm:^6.12.2, ajv@npm:^6.12.5":
+"ajv@npm:^6.12.2":
+ version: 6.15.0
+ resolution: "ajv@npm:6.15.0"
+ dependencies:
+ fast-deep-equal: ^3.1.1
+ fast-json-stable-stringify: ^2.0.0
+ json-schema-traverse: ^0.4.1
+ uri-js: ^4.2.2
+ checksum: a8e0308f1b44c3dfd1143911353be51bf8aedc2f2bcd595061755ad241c8450a10e4b657af8ba764c5ec9ae2162010f21d5e0d43763e20d782a8171da99b967a
+ languageName: node
+ linkType: hard
+
+"ajv@npm:^6.12.5":
version: 6.12.6
resolution: "ajv@npm:6.12.6"
dependencies:
@@ -3451,36 +4861,58 @@ __metadata:
linkType: hard
"algoliasearch-helper@npm:^3.13.3":
- version: 3.22.3
- resolution: "algoliasearch-helper@npm:3.22.3"
+ version: 3.29.1
+ resolution: "algoliasearch-helper@npm:3.29.1"
dependencies:
"@algolia/events": ^4.0.1
peerDependencies:
algoliasearch: ">= 3.1 < 6"
- checksum: 18ee77496e6e3aec6b3c1cab7a6c3e103172e3ac39d8dac076f654a28f66e5a7a3f609f694451705e606510b93c9e2c10f1fe738761ff007044c445318ffdb90
- languageName: node
- linkType: hard
-
-"algoliasearch@npm:^4.18.0, algoliasearch@npm:^4.19.1":
- version: 4.24.0
- resolution: "algoliasearch@npm:4.24.0"
- dependencies:
- "@algolia/cache-browser-local-storage": 4.24.0
- "@algolia/cache-common": 4.24.0
- "@algolia/cache-in-memory": 4.24.0
- "@algolia/client-account": 4.24.0
- "@algolia/client-analytics": 4.24.0
- "@algolia/client-common": 4.24.0
- "@algolia/client-personalization": 4.24.0
- "@algolia/client-search": 4.24.0
- "@algolia/logger-common": 4.24.0
- "@algolia/logger-console": 4.24.0
- "@algolia/recommend": 4.24.0
- "@algolia/requester-browser-xhr": 4.24.0
- "@algolia/requester-common": 4.24.0
- "@algolia/requester-node-http": 4.24.0
- "@algolia/transporter": 4.24.0
- checksum: 13cae6ea7ff05e068906dcb101b940bcf1a4ea41008757554c16a7951cdaa3af3094e547e3e51f9e751f68906b5654506e1dd4a1debb1b9d54cbb227ca83e8db
+ checksum: ce51481bba2f5c1f7ec0c98f8fa811a257057896ac22bbbd19bacaf5d5b91c7d0698feb3ce6d166feb7d2332a41aa62a055f7482e3150d28f90299d1393a8030
+ languageName: node
+ linkType: hard
+
+"algoliasearch@npm:^4.18.0":
+ version: 4.27.0
+ resolution: "algoliasearch@npm:4.27.0"
+ dependencies:
+ "@algolia/cache-browser-local-storage": 4.27.0
+ "@algolia/cache-common": 4.27.0
+ "@algolia/cache-in-memory": 4.27.0
+ "@algolia/client-account": 4.27.0
+ "@algolia/client-analytics": 4.27.0
+ "@algolia/client-common": 4.27.0
+ "@algolia/client-personalization": 4.27.0
+ "@algolia/client-search": 4.27.0
+ "@algolia/logger-common": 4.27.0
+ "@algolia/logger-console": 4.27.0
+ "@algolia/recommend": 4.27.0
+ "@algolia/requester-browser-xhr": 4.27.0
+ "@algolia/requester-common": 4.27.0
+ "@algolia/requester-node-http": 4.27.0
+ "@algolia/transporter": 4.27.0
+ checksum: ce222e3a1343d0ead630d7a4d3b04f01f60d06b56023591441d890a4a6b0e8ba9a08559831dff3e3e5030b60bdfbdec7db77ce34f8ecc53ee421e42d05a5fd34
+ languageName: node
+ linkType: hard
+
+"algoliasearch@npm:^5.14.2":
+ version: 5.52.1
+ resolution: "algoliasearch@npm:5.52.1"
+ dependencies:
+ "@algolia/abtesting": 1.18.1
+ "@algolia/client-abtesting": 5.52.1
+ "@algolia/client-analytics": 5.52.1
+ "@algolia/client-common": 5.52.1
+ "@algolia/client-insights": 5.52.1
+ "@algolia/client-personalization": 5.52.1
+ "@algolia/client-query-suggestions": 5.52.1
+ "@algolia/client-search": 5.52.1
+ "@algolia/ingestion": 1.52.1
+ "@algolia/monitoring": 1.52.1
+ "@algolia/recommend": 5.52.1
+ "@algolia/requester-browser-xhr": 5.52.1
+ "@algolia/requester-fetch": 5.52.1
+ "@algolia/requester-node-http": 5.52.1
+ checksum: 1412fc996c88aa948fa491eb6c128682ef27fa1edd2562452bf3d6615f0da5b0213bbae28bde76a3d78360647f6a8eb903a9a48f09739730b07c288b5f2e2761
languageName: node
linkType: hard
@@ -3604,7 +5036,24 @@ __metadata:
languageName: node
linkType: hard
-"autoprefixer@npm:^10.4.14, autoprefixer@npm:^10.4.19":
+"autoprefixer@npm:^10.4.14":
+ version: 10.5.0
+ resolution: "autoprefixer@npm:10.5.0"
+ dependencies:
+ browserslist: ^4.28.2
+ caniuse-lite: ^1.0.30001787
+ fraction.js: ^5.3.4
+ picocolors: ^1.1.1
+ postcss-value-parser: ^4.2.0
+ peerDependencies:
+ postcss: ^8.1.0
+ bin:
+ autoprefixer: bin/autoprefixer
+ checksum: e6475eb69ca7544a4abf5174b32e63b8d71aa5eb5618b7468b3c1a389b90596a6fdeab5c3fde7ebdb0b711047e307bd2a19c9f8011aa50ddb8b7eb91e71b7196
+ languageName: node
+ linkType: hard
+
+"autoprefixer@npm:^10.4.19":
version: 10.4.20
resolution: "autoprefixer@npm:10.4.20"
dependencies:
@@ -3623,15 +5072,15 @@ __metadata:
linkType: hard
"babel-loader@npm:^9.1.3":
- version: 9.1.3
- resolution: "babel-loader@npm:9.1.3"
+ version: 9.2.1
+ resolution: "babel-loader@npm:9.2.1"
dependencies:
find-cache-dir: ^4.0.0
schema-utils: ^4.0.0
peerDependencies:
"@babel/core": ^7.12.0
webpack: ">=5"
- checksum: b168dde5b8cf11206513371a79f86bb3faa7c714e6ec9fffd420876b61f3d7f5f4b976431095ef6a14bc4d324505126deb91045fd41e312ba49f4deaa166fe28
+ checksum: e1858d7625ad7cc8cabe6bbb8657f957041ffb1308375f359e92aa1654f413bfbb86a281bbf7cd4f7fff374d571c637b117551deac0231d779a198d4e4e78331
languageName: node
linkType: hard
@@ -3657,7 +5106,20 @@ __metadata:
languageName: node
linkType: hard
-"babel-plugin-polyfill-corejs3@npm:^0.10.1, babel-plugin-polyfill-corejs3@npm:^0.10.4":
+"babel-plugin-polyfill-corejs2@npm:^0.4.14, babel-plugin-polyfill-corejs2@npm:^0.4.15":
+ version: 0.4.17
+ resolution: "babel-plugin-polyfill-corejs2@npm:0.4.17"
+ dependencies:
+ "@babel/compat-data": ^7.28.6
+ "@babel/helper-define-polyfill-provider": ^0.6.8
+ semver: ^6.3.1
+ peerDependencies:
+ "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
+ checksum: 945f80f413706831b665322690c655f3782ca6fd8c1fbcccaf449d976ebe6151677fb9331442c72e85eae9a05d5e6633be4e15f75d3e788762d825d31f2964ce
+ languageName: node
+ linkType: hard
+
+"babel-plugin-polyfill-corejs3@npm:^0.10.4":
version: 0.10.6
resolution: "babel-plugin-polyfill-corejs3@npm:0.10.6"
dependencies:
@@ -3669,6 +5131,30 @@ __metadata:
languageName: node
linkType: hard
+"babel-plugin-polyfill-corejs3@npm:^0.13.0":
+ version: 0.13.0
+ resolution: "babel-plugin-polyfill-corejs3@npm:0.13.0"
+ dependencies:
+ "@babel/helper-define-polyfill-provider": ^0.6.5
+ core-js-compat: ^3.43.0
+ peerDependencies:
+ "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
+ checksum: cf526031acd97ff2124e7c10e15047e6eeb0620d029c687f1dca99916a8fe6cac0e634b84c913db6cb68b7a024f82492ba8fdcc2a6266e7b05bdac2cba0c2434
+ languageName: node
+ linkType: hard
+
+"babel-plugin-polyfill-corejs3@npm:^0.14.0":
+ version: 0.14.2
+ resolution: "babel-plugin-polyfill-corejs3@npm:0.14.2"
+ dependencies:
+ "@babel/helper-define-polyfill-provider": ^0.6.8
+ core-js-compat: ^3.48.0
+ peerDependencies:
+ "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
+ checksum: 4bcaf4da658aaeb7a6534e6b65a6a45539c5f53bec596fefd0b44eebd249e5db8bbf239a421ceaff5933a0a7eee11e45791e4f4e04886cdf47bb1d4b1a8015aa
+ languageName: node
+ linkType: hard
+
"babel-plugin-polyfill-regenerator@npm:^0.6.1":
version: 0.6.2
resolution: "babel-plugin-polyfill-regenerator@npm:0.6.2"
@@ -3680,6 +5166,17 @@ __metadata:
languageName: node
linkType: hard
+"babel-plugin-polyfill-regenerator@npm:^0.6.5, babel-plugin-polyfill-regenerator@npm:^0.6.6":
+ version: 0.6.8
+ resolution: "babel-plugin-polyfill-regenerator@npm:0.6.8"
+ dependencies:
+ "@babel/helper-define-polyfill-provider": ^0.6.8
+ peerDependencies:
+ "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
+ checksum: 974464353d6f974e97673385aff616a913c0b76039eab8c5317a2d07c661e080f3dcc213e86f3eae40010172a27ab793cda7a290a8a899716f9a22df9b1d92d2
+ languageName: node
+ linkType: hard
+
"bail@npm:^2.0.0":
version: 2.0.2
resolution: "bail@npm:2.0.2"
@@ -3694,6 +5191,15 @@ __metadata:
languageName: node
linkType: hard
+"baseline-browser-mapping@npm:^2.10.12":
+ version: 2.10.30
+ resolution: "baseline-browser-mapping@npm:2.10.30"
+ bin:
+ baseline-browser-mapping: dist/cli.cjs
+ checksum: 1ad8d9af3cebc4b91cf04b99c326fb0aab697ded642f3830deb96838c6dbb5d35ad2a2cad49064c6136b61bd962d77c23cd05db4f2e65f1fe1cfcca44ace9f4e
+ languageName: node
+ linkType: hard
+
"batch@npm:0.6.1":
version: 0.6.1
resolution: "batch@npm:0.6.1"
@@ -3812,7 +5318,7 @@ __metadata:
languageName: node
linkType: hard
-"browserslist@npm:^4.0.0, browserslist@npm:^4.18.1, browserslist@npm:^4.21.10, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1, browserslist@npm:^4.23.3":
+"browserslist@npm:^4.0.0, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1, browserslist@npm:^4.23.3":
version: 4.23.3
resolution: "browserslist@npm:4.23.3"
dependencies:
@@ -3826,6 +5332,21 @@ __metadata:
languageName: node
linkType: hard
+"browserslist@npm:^4.18.1, browserslist@npm:^4.24.0, browserslist@npm:^4.28.1, browserslist@npm:^4.28.2":
+ version: 4.28.2
+ resolution: "browserslist@npm:4.28.2"
+ dependencies:
+ baseline-browser-mapping: ^2.10.12
+ caniuse-lite: ^1.0.30001782
+ electron-to-chromium: ^1.5.328
+ node-releases: ^2.0.36
+ update-browserslist-db: ^1.2.3
+ bin:
+ browserslist: cli.js
+ checksum: 702cdd3462b5eb6f8a9bb3bf7bdc6d6a4141ced6935bb44edb7f3d40edd66198775f2b4a9178682535391293e04e625ba2b5943546d692f42ea080323cecb25e
+ languageName: node
+ linkType: hard
+
"buffer-from@npm:^1.0.0":
version: 1.1.2
resolution: "buffer-from@npm:1.1.2"
@@ -3952,6 +5473,13 @@ __metadata:
languageName: node
linkType: hard
+"caniuse-lite@npm:^1.0.30001782, caniuse-lite@npm:^1.0.30001787":
+ version: 1.0.30001792
+ resolution: "caniuse-lite@npm:1.0.30001792"
+ checksum: 25e2ba0feb792fbc99e98b236653dccec6387bf9351510b5401ffcb0c25193e47a2ba37e5ce44f92e0fb023670fe077b938ab8e1bad53bc03e95673e5bd5d439
+ languageName: node
+ linkType: hard
+
"ccount@npm:^2.0.0":
version: 2.0.1
resolution: "ccount@npm:2.0.1"
@@ -4398,10 +5926,19 @@ __metadata:
languageName: node
linkType: hard
-"core-js-pure@npm:^3.30.2":
- version: 3.38.0
- resolution: "core-js-pure@npm:3.38.0"
- checksum: 29aac7b56778370523f6a58f713c730975b097fea19838f93705730bd95d2da78b116e561e2cda637dde4cebe0a88baf9a5ce4e391732c39cbc5e55dc95bb38c
+"core-js-compat@npm:^3.43.0, core-js-compat@npm:^3.48.0":
+ version: 3.49.0
+ resolution: "core-js-compat@npm:3.49.0"
+ dependencies:
+ browserslist: ^4.28.1
+ checksum: 21afa75a64b30810f4cc61e90758346e8df6bd20dd8da5afe08fc041b5fb766cf7c41c9cbc63f8fb96bef4e4a2a90eb6f2d7bbd20ac53b8ff23a58bc87e40231
+ languageName: node
+ linkType: hard
+
+"core-js-pure@npm:^3.48.0":
+ version: 3.49.0
+ resolution: "core-js-pure@npm:3.49.0"
+ checksum: 6d717ad23665135f0ba5fd18645d3ae6c0647752982037e61e571b7bea3910ad67a9482bbb558461a72015679dd25a40d114249e23c4267a69df494d3d4349ab
languageName: node
linkType: hard
@@ -4715,6 +6252,18 @@ __metadata:
languageName: node
linkType: hard
+"debug@npm:^4.4.3":
+ version: 4.4.3
+ resolution: "debug@npm:4.4.3"
+ dependencies:
+ ms: ^2.1.3
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ checksum: 4805abd570e601acdca85b6aa3757186084a45cff9b2fa6eee1f3b173caa776b45f478b2a71a572d616d2010cea9211d0ac4a02a610e4c18ac4324bde3760834
+ languageName: node
+ linkType: hard
+
"decode-named-character-reference@npm:^1.0.0":
version: 1.0.2
resolution: "decode-named-character-reference@npm:1.0.2"
@@ -4907,8 +6456,8 @@ __metadata:
"@mdx-js/react": ^3.0.0
clsx: ^2.0.0
prism-react-renderer: ^2.3.0
- react: ^18.0.0
- react-dom: ^18.0.0
+ react: ^19.0.0
+ react-dom: ^19.0.0
languageName: unknown
linkType: soft
@@ -5030,6 +6579,13 @@ __metadata:
languageName: node
linkType: hard
+"electron-to-chromium@npm:^1.5.328":
+ version: 1.5.358
+ resolution: "electron-to-chromium@npm:1.5.358"
+ checksum: cab5eb95a6b7a7fac04018004ffe01072a51c079d3bf0d7f7fda4fb18f0972ba1e198d7822af9ec0072a19a85668dae01b4d787ab9b2a086e3ef47ff61c9468b
+ languageName: node
+ linkType: hard
+
"electron-to-chromium@npm:^1.5.4":
version: 1.5.6
resolution: "electron-to-chromium@npm:1.5.6"
@@ -5088,13 +6644,13 @@ __metadata:
languageName: node
linkType: hard
-"enhanced-resolve@npm:^5.17.0":
- version: 5.17.1
- resolution: "enhanced-resolve@npm:5.17.1"
+"enhanced-resolve@npm:^5.17.1":
+ version: 5.21.3
+ resolution: "enhanced-resolve@npm:5.21.3"
dependencies:
graceful-fs: ^4.2.4
- tapable: ^2.2.0
- checksum: 4bc38cf1cea96456f97503db7280394177d1bc46f8f87c267297d04f795ac5efa81e48115a2f5b6273c781027b5b6bfc5f62b54df629e4d25fa7001a86624f59
+ tapable: ^2.3.3
+ checksum: 54e48bde85d57937749765b8e32a17392be6b495a5e576f0c382b7340e095b8cbec224cae65fb8408f73fa68095d71e95fba5f10948072ef6fd26fa4dc5d6aeb
languageName: node
linkType: hard
@@ -5165,6 +6721,13 @@ __metadata:
languageName: node
linkType: hard
+"escalade@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "escalade@npm:3.2.0"
+ checksum: 47b029c83de01b0d17ad99ed766347b974b0d628e848de404018f3abee728e987da0d2d370ad4574aa3d5b5bfc368754fd085d69a30f8e75903486ec4b5b709e
+ languageName: node
+ linkType: hard
+
"escape-goat@npm:^4.0.0":
version: 4.0.0
resolution: "escape-goat@npm:4.0.0"
@@ -5468,15 +7031,6 @@ __metadata:
languageName: node
linkType: hard
-"fast-url-parser@npm:1.1.3":
- version: 1.1.3
- resolution: "fast-url-parser@npm:1.1.3"
- dependencies:
- punycode: ^1.3.2
- checksum: 5043d0c4a8d775ff58504d56c096563c11b113e4cb8a2668c6f824a1cd4fb3812e2fdf76537eb24a7ce4ae7def6bd9747da630c617cf2a4b6ce0c42514e4f21c
- languageName: node
- linkType: hard
-
"fastq@npm:^1.6.0":
version: 1.17.1
resolution: "fastq@npm:1.17.1"
@@ -5683,6 +7237,13 @@ __metadata:
languageName: node
linkType: hard
+"fraction.js@npm:^5.3.4":
+ version: 5.3.4
+ resolution: "fraction.js@npm:5.3.4"
+ checksum: 6ac88ecfdb5fabe3566ae30f79828d448288efbb852cd43ad83afc961fb6923e1d77bc65fbcba8ccda10894114edd419581a050c73d61e368fdd4c3ff416a65a
+ languageName: node
+ linkType: hard
+
"fresh@npm:0.5.2":
version: 0.5.2
resolution: "fresh@npm:0.5.2"
@@ -6053,6 +7614,15 @@ __metadata:
languageName: node
linkType: hard
+"hasown@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "hasown@npm:2.0.3"
+ dependencies:
+ function-bind: ^1.1.2
+ checksum: bb06756a13dc4e6d1f45993c86c23f12d167c6c30a7dcc907aec5042300b4eb255615a0e5ed2c65014b93bf8bfcff111d991032c5c01ddefb340aa64b329bd55
+ languageName: node
+ linkType: hard
+
"hast-util-from-parse5@npm:^8.0.0":
version: 8.0.1
resolution: "hast-util-from-parse5@npm:8.0.1"
@@ -6290,8 +7860,8 @@ __metadata:
linkType: hard
"html-webpack-plugin@npm:^5.5.3":
- version: 5.6.0
- resolution: "html-webpack-plugin@npm:5.6.0"
+ version: 5.6.7
+ resolution: "html-webpack-plugin@npm:5.6.7"
dependencies:
"@types/html-minifier-terser": ^6.0.0
html-minifier-terser: ^6.0.2
@@ -6306,7 +7876,7 @@ __metadata:
optional: true
webpack:
optional: true
- checksum: 32a6e41da538e798fd0be476637d7611a5e8a98a3508f031996e9eb27804dcdc282cb01f847cf5d066f21b49cfb8e21627fcf977ffd0c9bea81cf80e5a65070d
+ checksum: 043d17f0988fb173dd1a03159fc2e0c9a4d528f7f439b5318c72ec239e3c2be8267167c23a5a09f034c2c14ae0fccf8ab3055bee91151bb832744da2df29bfb6
languageName: node
linkType: hard
@@ -6481,13 +8051,13 @@ __metadata:
linkType: hard
"image-size@npm:^1.0.2":
- version: 1.1.1
- resolution: "image-size@npm:1.1.1"
+ version: 1.2.1
+ resolution: "image-size@npm:1.2.1"
dependencies:
queue: 6.0.2
bin:
image-size: bin/image-size.js
- checksum: 23b3a515dded89e7f967d52b885b430d6a5a903da954fce703130bfb6069d738d80e6588efd29acfaf5b6933424a56535aa7bf06867e4ebd0250c2ee51f19a4a
+ checksum: 8601ddd4edc1db16f097f5cf585c23214e29c3b8f4d8a8f8d59b8e3bae2338c8a5073236bfff421d8541091a98a38b802ed049203c745286a69d1aac4e5bc4c7
languageName: node
linkType: hard
@@ -6498,7 +8068,17 @@ __metadata:
languageName: node
linkType: hard
-"import-fresh@npm:^3.1.0, import-fresh@npm:^3.3.0":
+"import-fresh@npm:^3.1.0":
+ version: 3.3.1
+ resolution: "import-fresh@npm:3.3.1"
+ dependencies:
+ parent-module: ^1.0.0
+ resolve-from: ^4.0.0
+ checksum: a06b19461b4879cc654d46f8a6244eb55eb053437afd4cbb6613cad6be203811849ed3e4ea038783092879487299fda24af932b86bdfff67c9055ba3612b8c87
+ languageName: node
+ linkType: hard
+
+"import-fresh@npm:^3.3.0":
version: 3.3.0
resolution: "import-fresh@npm:3.3.0"
dependencies:
@@ -6681,6 +8261,15 @@ __metadata:
languageName: node
linkType: hard
+"is-core-module@npm:^2.16.1":
+ version: 2.16.2
+ resolution: "is-core-module@npm:2.16.2"
+ dependencies:
+ hasown: ^2.0.3
+ checksum: 9317844b4959f8fb268bfc1b4e24033d60058235c2e7273499c2abfd8e4510e7059b1339bd9109766293747daa3e0b5a89095fb2825a866a4093563fe8fdf16f
+ languageName: node
+ linkType: hard
+
"is-decimal@npm:^2.0.0":
version: 2.0.1
resolution: "is-decimal@npm:2.0.1"
@@ -7022,6 +8611,15 @@ __metadata:
languageName: node
linkType: hard
+"jsesc@npm:^3.0.2, jsesc@npm:~3.1.0":
+ version: 3.1.0
+ resolution: "jsesc@npm:3.1.0"
+ bin:
+ jsesc: bin/jsesc
+ checksum: 19c94095ea026725540c0d29da33ab03144f6bcf2d4159e4833d534976e99e0c09c38cefa9a575279a51fc36b31166f8d6d05c9fe2645d5f15851d690b41f17f
+ languageName: node
+ linkType: hard
+
"jsesc@npm:~0.5.0":
version: 0.5.0
resolution: "jsesc@npm:0.5.0"
@@ -7232,7 +8830,7 @@ __metadata:
languageName: node
linkType: hard
-"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0":
+"loose-envify@npm:^1.0.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
dependencies:
@@ -8198,14 +9796,14 @@ __metadata:
linkType: hard
"mini-css-extract-plugin@npm:^2.7.6":
- version: 2.9.0
- resolution: "mini-css-extract-plugin@npm:2.9.0"
+ version: 2.10.2
+ resolution: "mini-css-extract-plugin@npm:2.10.2"
dependencies:
schema-utils: ^4.0.0
tapable: ^2.2.1
peerDependencies:
webpack: ^5.0.0
- checksum: ae192c67ba85ac8bffeab66774635bf90181f00d5dd6cf95412426192599ddf5506fb4b1550acbd7a5476476e39db53c770dd40f8378f7baf5de96e3fec4e6e9
+ checksum: eb64d835d50fce8c181153b580f989661c37c0e56ddff7c1362051643180a31c8f8055d0d8dccc0dd2b022b1010d2957fe3097010f37acd33edfeb29bfc3734e
languageName: node
linkType: hard
@@ -8216,7 +9814,16 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:3.1.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1":
+"minimatch@npm:3.1.5, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5":
+ version: 3.1.5
+ resolution: "minimatch@npm:3.1.5"
+ dependencies:
+ brace-expansion: ^1.1.7
+ checksum: 47ef6f412c08be045a7291d11b1c40777925accf7252dc6d3caa39b1bfbb3a7ea390ba7aba464d762d783265c644143d2c8a204e6b5763145024d52ee65a1941
+ languageName: node
+ linkType: hard
+
+"minimatch@npm:^3.1.1":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
dependencies:
@@ -8355,7 +9962,7 @@ __metadata:
languageName: node
linkType: hard
-"ms@npm:2.1.3":
+"ms@npm:2.1.3, ms@npm:^2.1.3":
version: 2.1.3
resolution: "ms@npm:2.1.3"
checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d
@@ -8374,6 +9981,15 @@ __metadata:
languageName: node
linkType: hard
+"nanoid@npm:^3.3.11":
+ version: 3.3.12
+ resolution: "nanoid@npm:3.3.12"
+ bin:
+ nanoid: bin/nanoid.cjs
+ checksum: 38699257447dc59e21e73e0510d0dfb16b7a610d9ca80633d5c3a68f9b4298c990513d30404ca8f163c2d03225ee01695ff8898bea6179183f38f0477b7635ac
+ languageName: node
+ linkType: hard
+
"nanoid@npm:^3.3.7":
version: 3.3.7
resolution: "nanoid@npm:3.3.7"
@@ -8453,6 +10069,13 @@ __metadata:
languageName: node
linkType: hard
+"node-releases@npm:^2.0.36":
+ version: 2.0.44
+ resolution: "node-releases@npm:2.0.44"
+ checksum: a96278a9ec8f3d67b796693047499fc64724f97cb7fb8aa50e8e5a9408f4f2c1e2eb8f3ee44c43bfd34b0331514d9a8ad5efc7a98e7b720a4b9cd9b4d0f0c2da
+ languageName: node
+ linkType: hard
+
"nopt@npm:^7.0.0":
version: 7.2.1
resolution: "nopt@npm:7.2.1"
@@ -8866,10 +10489,10 @@ __metadata:
languageName: node
linkType: hard
-"path-to-regexp@npm:2.2.1":
- version: 2.2.1
- resolution: "path-to-regexp@npm:2.2.1"
- checksum: b921a74e7576e25b06ad1635abf7e8125a29220d2efc2b71d74b9591f24a27e6f09078fa9a1b27516a097ea0637b7cab79d19b83d7f36a8ef3ef5422770e89d9
+"path-to-regexp@npm:3.3.0":
+ version: 3.3.0
+ resolution: "path-to-regexp@npm:3.3.0"
+ checksum: bb249d08804f7961dd44fb175466c900b893c56e909db8e2a66ec12b9d9a964af269eb7a50892c933f52b47315953dfdb4279639fbce20977c3625a9ef3055fe
languageName: node
linkType: hard
@@ -8907,6 +10530,13 @@ __metadata:
languageName: node
linkType: hard
+"picocolors@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "picocolors@npm:1.1.1"
+ checksum: e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045
+ languageName: node
+ linkType: hard
+
"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1":
version: 2.3.1
resolution: "picomatch@npm:2.3.1"
@@ -9365,7 +10995,7 @@ __metadata:
languageName: node
linkType: hard
-"postcss@npm:^8.4.21, postcss@npm:^8.4.24, postcss@npm:^8.4.26, postcss@npm:^8.4.33, postcss@npm:^8.4.38":
+"postcss@npm:^8.4.21, postcss@npm:^8.4.24, postcss@npm:^8.4.33":
version: 8.4.41
resolution: "postcss@npm:8.4.41"
dependencies:
@@ -9376,6 +11006,17 @@ __metadata:
languageName: node
linkType: hard
+"postcss@npm:^8.4.26, postcss@npm:^8.4.38":
+ version: 8.5.14
+ resolution: "postcss@npm:8.5.14"
+ dependencies:
+ nanoid: ^3.3.11
+ picocolors: ^1.1.1
+ source-map-js: ^1.2.1
+ checksum: ec17d1519cd997b43aceb82bfa959f380085591269e286c53d5ba76eb1989525e7cde106a44f1565516fcbb50f206eb1858cc2cd5e5aaea3a8ee793886c8232c
+ languageName: node
+ linkType: hard
+
"pretty-error@npm:^4.0.0":
version: 4.0.0
resolution: "pretty-error@npm:4.0.0"
@@ -9481,13 +11122,6 @@ __metadata:
languageName: node
linkType: hard
-"punycode@npm:^1.3.2":
- version: 1.4.1
- resolution: "punycode@npm:1.4.1"
- checksum: fa6e698cb53db45e4628559e557ddaf554103d2a96a1d62892c8f4032cd3bc8871796cae9eabc1bc700e2b6677611521ce5bb1d9a27700086039965d0cf34518
- languageName: node
- linkType: hard
-
"punycode@npm:^2.1.0":
version: 2.3.1
resolution: "punycode@npm:2.3.1"
@@ -9617,22 +11251,21 @@ __metadata:
languageName: node
linkType: hard
-"react-dom@npm:^18.0.0":
- version: 18.3.1
- resolution: "react-dom@npm:18.3.1"
+"react-dom@npm:^19.0.0":
+ version: 19.2.6
+ resolution: "react-dom@npm:19.2.6"
dependencies:
- loose-envify: ^1.1.0
- scheduler: ^0.23.2
+ scheduler: ^0.27.0
peerDependencies:
- react: ^18.3.1
- checksum: 298954ecd8f78288dcaece05e88b570014d8f6dce5db6f66e6ee91448debeb59dcd31561dddb354eee47e6c1bb234669459060deb238ed0213497146e555a0b9
+ react: ^19.2.6
+ checksum: 9ecaff123867286a8fd18fb1028f0b493da4a48faacd38d97d4bde16c756d314869836ae74cd95733c5ebcff8e2cb568d0c06a1b18e2e7482eb898cc5b8dd92f
languageName: node
linkType: hard
"react-error-overlay@npm:^6.0.11":
- version: 6.0.11
- resolution: "react-error-overlay@npm:6.0.11"
- checksum: ce7b44c38fadba9cedd7c095cf39192e632daeccf1d0747292ed524f17dcb056d16bc197ddee5723f9dd888f0b9b19c3b486c430319e30504289b9296f2d2c42
+ version: 6.1.0
+ resolution: "react-error-overlay@npm:6.1.0"
+ checksum: 4f0785ea14390e333d040e7d7d6f8b915ad9bd4b8ae6eb28e1a5338f23a0325798d20deea7572c3c129bd1d32c432b01e7a4d40ca99710e2fa1f8157929e6cda
languageName: node
linkType: hard
@@ -9644,15 +11277,15 @@ __metadata:
linkType: hard
"react-helmet-async@npm:*":
- version: 2.0.5
- resolution: "react-helmet-async@npm:2.0.5"
+ version: 3.0.0
+ resolution: "react-helmet-async@npm:3.0.0"
dependencies:
invariant: ^2.2.4
react-fast-compare: ^3.2.2
shallowequal: ^1.1.0
peerDependencies:
- react: ^16.6.0 || ^17.0.0 || ^18.0.0
- checksum: cc2d13496f6fdee6b5f9472d3f7369db3e70e4fc1a55793708c2bbd90d48b0dedc725fd066f987c7a3d74b03a29bd5e65b9f40fa29bd8239e7cfb526aff4d4b6
+ react: ^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ checksum: 78273903cbdbbf4ed555b38ec95e9080d7526e4194845f664c0374146fcdeb6ab4e02aee70b3b852b88272a3992c8c1dae2bf3fed188ccfa2d19b8e5e2432545
languageName: node
linkType: hard
@@ -9680,11 +11313,11 @@ __metadata:
linkType: hard
"react-json-view-lite@npm:^1.2.0":
- version: 1.4.0
- resolution: "react-json-view-lite@npm:1.4.0"
+ version: 1.5.0
+ resolution: "react-json-view-lite@npm:1.5.0"
peerDependencies:
react: ^16.13.1 || ^17.0.0 || ^18.0.0
- checksum: 420921258478da46a54887b6e4740e6cf21c7264eba95c33d6264fdf71c482f0746c1345eb187a4a52b31d2a3a951f88c7af338b9fccbced2a918751dd98c844
+ checksum: e298621f6437ee06545bdb9e11265d92a60a6394ca8ea40bf12b50422a62f7a485998bf96d0b8b7cb95658d0122dbc900a814a572ddaaf59053657a27ccc7f33
languageName: node
linkType: hard
@@ -9759,12 +11392,10 @@ __metadata:
languageName: node
linkType: hard
-"react@npm:^18.0.0":
- version: 18.3.1
- resolution: "react@npm:18.3.1"
- dependencies:
- loose-envify: ^1.1.0
- checksum: a27bcfa8ff7c15a1e50244ad0d0c1cb2ad4375eeffefd266a64889beea6f6b64c4966c9b37d14ee32d6c9fcd5aa6ba183b6988167ab4d127d13e7cb5b386a376
+"react@npm:^19.0.0":
+ version: 19.2.6
+ resolution: "react@npm:19.2.6"
+ checksum: e250029064bff3f3308ee61e52c44bc9a0c938f6ef11a3f39c31db487ca173eb9b4b0cd3261e32613d3498df0da5586f3c582bc83cef54ad99bc5643772c4535
languageName: node
linkType: hard
@@ -9837,6 +11468,15 @@ __metadata:
languageName: node
linkType: hard
+"regenerate-unicode-properties@npm:^10.2.2":
+ version: 10.2.2
+ resolution: "regenerate-unicode-properties@npm:10.2.2"
+ dependencies:
+ regenerate: ^1.4.2
+ checksum: 7ae4c1c32460c4360e3118c45eec0621424908f430fdd6f162c9172067786bf2b1682fbc885a33b26bc85e76e06f4d3f398b52425e801b0bb0cbae147dafb0b2
+ languageName: node
+ linkType: hard
+
"regenerate@npm:^1.4.2":
version: 1.4.2
resolution: "regenerate@npm:1.4.2"
@@ -9874,6 +11514,20 @@ __metadata:
languageName: node
linkType: hard
+"regexpu-core@npm:^6.3.1":
+ version: 6.4.0
+ resolution: "regexpu-core@npm:6.4.0"
+ dependencies:
+ regenerate: ^1.4.2
+ regenerate-unicode-properties: ^10.2.2
+ regjsgen: ^0.8.0
+ regjsparser: ^0.13.0
+ unicode-match-property-ecmascript: ^2.0.0
+ unicode-match-property-value-ecmascript: ^2.2.1
+ checksum: a316eb988599b7fb9d77f4adb937c41c022504dc91ddd18175c11771addc7f1d9dce550f34e36038395e459a2cf9ffc0d663bfe8d3c6c186317ca000ba79a8cf
+ languageName: node
+ linkType: hard
+
"registry-auth-token@npm:^5.0.1":
version: 5.0.2
resolution: "registry-auth-token@npm:5.0.2"
@@ -9892,6 +11546,24 @@ __metadata:
languageName: node
linkType: hard
+"regjsgen@npm:^0.8.0":
+ version: 0.8.0
+ resolution: "regjsgen@npm:0.8.0"
+ checksum: a1d925ff14a4b2be774e45775ee6b33b256f89c42d480e6d85152d2133f18bd3d6af662161b226fa57466f7efec367eaf7ccd2a58c0ec2a1306667ba2ad07b0d
+ languageName: node
+ linkType: hard
+
+"regjsparser@npm:^0.13.0":
+ version: 0.13.1
+ resolution: "regjsparser@npm:0.13.1"
+ dependencies:
+ jsesc: ~3.1.0
+ bin:
+ regjsparser: bin/parser
+ checksum: 7a4e60e1487b6a0702e35540f882c0c6e0151f7f567c6a4c480c5397a3cab05f6d2bf5f64cdbcdf341e41caf232cae801a4db9b531c26eed3ca946b3c50ccb34
+ languageName: node
+ linkType: hard
+
"regjsparser@npm:^0.9.1":
version: 0.9.1
resolution: "regjsparser@npm:0.9.1"
@@ -10073,7 +11745,21 @@ __metadata:
languageName: node
linkType: hard
-"resolve@npm:^1.1.6, resolve@npm:^1.14.2":
+"resolve@npm:^1.1.6, resolve@npm:^1.22.11":
+ version: 1.22.12
+ resolution: "resolve@npm:1.22.12"
+ dependencies:
+ es-errors: ^1.3.0
+ is-core-module: ^2.16.1
+ path-parse: ^1.0.7
+ supports-preserve-symlinks-flag: ^1.0.0
+ bin:
+ resolve: bin/resolve
+ checksum: 4dc5a614b32142ef9ab455b242ed33c472c4ea50df17dbe1e9dac5fe0eebd7d5fdb7cb9cc8ad2165e5e0f07694498a74e7fbd6cc1599e20d84682cce1b80a4dc
+ languageName: node
+ linkType: hard
+
+"resolve@npm:^1.14.2":
version: 1.22.8
resolution: "resolve@npm:1.22.8"
dependencies:
@@ -10086,7 +11772,21 @@ __metadata:
languageName: node
linkType: hard
-"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.14.2#~builtin":
+"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.22.11#~builtin":
+ version: 1.22.12
+ resolution: "resolve@patch:resolve@npm%3A1.22.12#~builtin::version=1.22.12&hash=c3c19d"
+ dependencies:
+ es-errors: ^1.3.0
+ is-core-module: ^2.16.1
+ path-parse: ^1.0.7
+ supports-preserve-symlinks-flag: ^1.0.0
+ bin:
+ resolve: bin/resolve
+ checksum: 0cc5b060cbe081c85c331ac2eb08e8a54f0a195b899d5001822e5d3e2b335da651b1eed3d259fea904c22a0da9324a061e0e7ceab5dbeb5bcab5250b625754e1
+ languageName: node
+ linkType: hard
+
+"resolve@patch:resolve@^1.14.2#~builtin":
version: 1.22.8
resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d"
dependencies:
@@ -10198,12 +11898,10 @@ __metadata:
languageName: node
linkType: hard
-"scheduler@npm:^0.23.2":
- version: 0.23.2
- resolution: "scheduler@npm:0.23.2"
- dependencies:
- loose-envify: ^1.1.0
- checksum: 3e82d1f419e240ef6219d794ff29c7ee415fbdc19e038f680a10c067108e06284f1847450a210b29bbaf97b9d8a97ced5f624c31c681248ac84c80d56ad5a2c4
+"scheduler@npm:^0.27.0":
+ version: 0.27.0
+ resolution: "scheduler@npm:0.27.0"
+ checksum: 92644ead0a9443e20f9d24132fe93675b156209b9eeb35ea245f8a86768d0cc0fcca56f341eeef21d9b6dd8e72d6d5e260eb5a41d34b05cd605dd45a29f572ef
languageName: node
linkType: hard
@@ -10286,7 +11984,16 @@ __metadata:
languageName: node
linkType: hard
-"semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.4":
+"semver@npm:^7.3.2":
+ version: 7.8.0
+ resolution: "semver@npm:7.8.0"
+ bin:
+ semver: bin/semver.js
+ checksum: 68e38bc26ed1191d7c78d2b711bdffc2f8b1d05a1caadda41a1d7e1a9d32e1da5ae5b645de5c5f2b27bde830d7e9c1cbeeafcb8fda091830411df7d40be405b1
+ languageName: node
+ linkType: hard
+
+"semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.4":
version: 7.6.3
resolution: "semver@npm:7.6.3"
bin:
@@ -10326,18 +12033,17 @@ __metadata:
linkType: hard
"serve-handler@npm:^6.1.5":
- version: 6.1.5
- resolution: "serve-handler@npm:6.1.5"
+ version: 6.1.7
+ resolution: "serve-handler@npm:6.1.7"
dependencies:
bytes: 3.0.0
content-disposition: 0.5.2
- fast-url-parser: 1.1.3
mime-types: 2.1.18
- minimatch: 3.1.2
+ minimatch: 3.1.5
path-is-inside: 1.0.2
- path-to-regexp: 2.2.1
+ path-to-regexp: 3.3.0
range-parser: 1.2.0
- checksum: 7a98ca9cbf8692583b6cde4deb3941cff900fa38bf16adbfccccd8430209bab781e21d9a1f61c9c03e226f9f67689893bbce25941368f3ddaf985fc3858b49dc
+ checksum: eb03d807336f8186257a28cb48fd03b3ddb2dda918896fbe190e8f721354d276c3ff35506f20728aa89f6962f73fb721b3e1e4fe92847a4e758b95980d5c3daa
languageName: node
linkType: hard
@@ -10428,7 +12134,14 @@ __metadata:
languageName: node
linkType: hard
-"shell-quote@npm:^1.7.3, shell-quote@npm:^1.8.1":
+"shell-quote@npm:^1.7.3":
+ version: 1.8.3
+ resolution: "shell-quote@npm:1.8.3"
+ checksum: 550dd84e677f8915eb013d43689c80bb114860649ec5298eb978f40b8f3d4bc4ccb072b82c094eb3548dc587144bb3965a8676f0d685c1cf4c40b5dc27166242
+ languageName: node
+ linkType: hard
+
+"shell-quote@npm:^1.8.1":
version: 1.8.1
resolution: "shell-quote@npm:1.8.1"
checksum: 5f01201f4ef504d4c6a9d0d283fa17075f6770bfbe4c5850b074974c68062f37929ca61700d95ad2ac8822e14e8c4b990ca0e6e9272e64befd74ce5e19f0736b
@@ -10592,6 +12305,13 @@ __metadata:
languageName: node
linkType: hard
+"source-map-js@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "source-map-js@npm:1.2.1"
+ checksum: 4eb0cd997cdf228bc253bcaff9340afeb706176e64868ecd20efbe6efea931465f43955612346d6b7318789e5265bdc419bc7669c1cebe3db0eb255f57efa76b
+ languageName: node
+ linkType: hard
+
"source-map-support@npm:~0.5.20":
version: 0.5.21
resolution: "source-map-support@npm:0.5.21"
@@ -10695,9 +12415,9 @@ __metadata:
linkType: hard
"std-env@npm:^3.0.1":
- version: 3.7.0
- resolution: "std-env@npm:3.7.0"
- checksum: 4f489d13ff2ab838c9acd4ed6b786b51aa52ecacdfeaefe9275fcb220ff2ac80c6e95674723508fd29850a694569563a8caaaea738eb82ca16429b3a0b50e510
+ version: 3.10.0
+ resolution: "std-env@npm:3.10.0"
+ checksum: 51d641b36b0fae494a546fb8446d39a837957fbf902c765c62bd12af8e50682d141c4087ca032f1192fa90330c4f6ff23fd6c9795324efacd1684e814471e0e0
languageName: node
linkType: hard
@@ -10903,13 +12623,20 @@ __metadata:
languageName: node
linkType: hard
-"tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.0, tapable@npm:^2.2.1":
+"tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.1":
version: 2.2.1
resolution: "tapable@npm:2.2.1"
checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51
languageName: node
linkType: hard
+"tapable@npm:^2.3.3":
+ version: 2.3.3
+ resolution: "tapable@npm:2.3.3"
+ checksum: 6f37a59e82a2daedd0fbfc231f6e6004389a9d4bcf8ab8f2d61f96f9f4fd4cbb087799627c5d644d75f518df2abbbc9b9ac699945e0c9a0c610f2a3ca92e0265
+ languageName: node
+ linkType: hard
+
"tar@npm:^6.1.11, tar@npm:^6.2.1":
version: 6.2.1
resolution: "tar@npm:6.2.1"
@@ -11110,6 +12837,13 @@ __metadata:
languageName: node
linkType: hard
+"unicode-match-property-value-ecmascript@npm:^2.2.1":
+ version: 2.2.1
+ resolution: "unicode-match-property-value-ecmascript@npm:2.2.1"
+ checksum: e6c73e07bb4dc4aa399797a14b170e84a30ed290bcf97cc4305cf67dde8744119721ce17cef03f4f9d4ff48654bfa26eadc7fe1e8dd4b71b8f3b2e9a9742f013
+ languageName: node
+ linkType: hard
+
"unicode-property-aliases-ecmascript@npm:^2.0.0":
version: 2.1.0
resolution: "unicode-property-aliases-ecmascript@npm:2.1.0"
@@ -11254,6 +12988,20 @@ __metadata:
languageName: node
linkType: hard
+"update-browserslist-db@npm:^1.2.3":
+ version: 1.2.3
+ resolution: "update-browserslist-db@npm:1.2.3"
+ dependencies:
+ escalade: ^3.2.0
+ picocolors: ^1.1.1
+ peerDependencies:
+ browserslist: ">= 4.21.0"
+ bin:
+ update-browserslist-db: cli.js
+ checksum: 6f209a97ae8eacdd3a1ef2eb365adf49d1e2a757e5b2dd4ac87dc8c99236cbe3e572d3e605a87dd7b538a11751b71d9f93edc47c7405262a293a493d155316cd
+ languageName: node
+ linkType: hard
+
"update-notifier@npm:^6.0.2":
version: 6.0.2
resolution: "update-notifier@npm:6.0.2"
@@ -11512,20 +13260,19 @@ __metadata:
languageName: node
linkType: hard
-"webpack@npm:^5.88.1":
- version: 5.93.0
- resolution: "webpack@npm:5.93.0"
+"webpack@npm:5.96.1":
+ version: 5.96.1
+ resolution: "webpack@npm:5.96.1"
dependencies:
- "@types/eslint-scope": ^3.7.3
- "@types/estree": ^1.0.5
+ "@types/eslint-scope": ^3.7.7
+ "@types/estree": ^1.0.6
"@webassemblyjs/ast": ^1.12.1
"@webassemblyjs/wasm-edit": ^1.12.1
"@webassemblyjs/wasm-parser": ^1.12.1
- acorn: ^8.7.1
- acorn-import-attributes: ^1.9.5
- browserslist: ^4.21.10
+ acorn: ^8.14.0
+ browserslist: ^4.24.0
chrome-trace-event: ^1.0.2
- enhanced-resolve: ^5.17.0
+ enhanced-resolve: ^5.17.1
es-module-lexer: ^1.2.1
eslint-scope: 5.1.1
events: ^3.2.0
@@ -11545,7 +13292,7 @@ __metadata:
optional: true
bin:
webpack: bin/webpack.js
- checksum: c93bd73d9e1ab49b07e139582187f1c3760ee2cf0163b6288fab2ae210e39e59240a26284e7e5d29bec851255ef4b43c51642c882fa5a94e16ce7cb906deeb47
+ checksum: ec3662f64895fae408440a997f87299e374c9d9f911f77b880bab46402f52221c7836bdf101fc2556338d07fc7cb86da50661f944eb1d1041a8361a5b9247876
languageName: node
linkType: hard
@@ -11734,9 +13481,9 @@ __metadata:
linkType: hard
"yaml@npm:^1.7.2":
- version: 1.10.2
- resolution: "yaml@npm:1.10.2"
- checksum: ce4ada136e8a78a0b08dc10b4b900936912d15de59905b2bf415b4d33c63df1d555d23acb2a41b23cf9fb5da41c256441afca3d6509de7247daa062fd2c5ea5f
+ version: 1.10.3
+ resolution: "yaml@npm:1.10.3"
+ checksum: 6a2dd3582f4fbcc8d0e32dc26d1a42f72a901eb6ae8fad616bd720514b11a53a64eabc21dba97fbcd951c7c0e1963502313789d93a753e7786e7452376498be5
languageName: node
linkType: hard
diff --git a/packages/e2e-react/.gitignore b/packages/e2e-react/.gitignore
index b88c8135ab..f79792577c 100644
--- a/packages/e2e-react/.gitignore
+++ b/packages/e2e-react/.gitignore
@@ -26,3 +26,4 @@ dist-ssr
/playwright-report/
/blob-report/
/playwright/.cache/
+/tests/.auth/
diff --git a/packages/e2e-react/package.json b/packages/e2e-react/package.json
index 1e34c0276c..d9d96ffb4c 100644
--- a/packages/e2e-react/package.json
+++ b/packages/e2e-react/package.json
@@ -14,14 +14,14 @@
},
"dependencies": {
"@embeddedchat/react": "workspace:*",
- "react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
},
"devDependencies": {
"@playwright/test": "^1.41.2",
"@types/node": "^20.11.19",
- "@types/react": "^18.2.55",
- "@types/react-dom": "^18.2.19",
+ "@types/react": "^19.0.0",
+ "@types/react-dom": "^19.0.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^4.2.1",
diff --git a/packages/e2e-react/playwright.config.ts b/packages/e2e-react/playwright.config.ts
index a91deee96a..9bbe41df51 100644
--- a/packages/e2e-react/playwright.config.ts
+++ b/packages/e2e-react/playwright.config.ts
@@ -73,5 +73,8 @@ export default defineConfig({
command: 'yarn dev',
url: 'http://127.0.0.1:5173',
reuseExistingServer: !process.env.CI,
+ timeout: 120000,
+ stdout: 'pipe',
+ stderr: 'pipe',
},
});
diff --git a/packages/e2e-react/vite.config.ts b/packages/e2e-react/vite.config.ts
index 028287cd5a..d89dc27b4a 100644
--- a/packages/e2e-react/vite.config.ts
+++ b/packages/e2e-react/vite.config.ts
@@ -6,5 +6,8 @@ export default defineConfig({
plugins: [react()],
define: {
'process.env': {}
- }
+ },
+ server: {
+ host: '127.0.0.1',
+ },
})
diff --git a/packages/htmlembed/package.json b/packages/htmlembed/package.json
index 82beecd43a..9d433d5554 100644
--- a/packages/htmlembed/package.json
+++ b/packages/htmlembed/package.json
@@ -14,8 +14,8 @@
},
"dependencies": {
"@embeddedchat/react": "workspace:^",
- "react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^3.1.0",
diff --git a/packages/layout_editor/package.json b/packages/layout_editor/package.json
index e8e9827e39..5cc6d09171 100644
--- a/packages/layout_editor/package.json
+++ b/packages/layout_editor/package.json
@@ -14,9 +14,9 @@
"@dnd-kit/sortable": "^8.0.0",
"@embeddedchat/markups": "workspace:^",
"@embeddedchat/ui-elements": "workspace:^",
- "react": "^18.2.0",
+ "react": "^19.0.0",
"react-color": "^2.19.3",
- "react-dom": "^18.2.0",
+ "react-dom": "^19.0.0",
"react-resizable-panels": "^2.0.20",
"react-syntax-highlighter": "^15.5.0"
},
diff --git a/packages/markups/package.json b/packages/markups/package.json
index ab60f023f7..25b6b57032 100644
--- a/packages/markups/package.json
+++ b/packages/markups/package.json
@@ -53,8 +53,8 @@
"lint-staged": "^12.4.2",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.1",
- "react": "^17.0.2",
- "react-dom": "^17.0.2",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
"rimraf": "^5.0.1",
"rollup": "^2.70.1",
"rollup-plugin-analyzer": "^4.0.0",
@@ -67,8 +67,8 @@
"typescript": "^5.5.3"
},
"peerDependencies": {
- "react": ">=17.0.2 <19.0.0",
- "react-dom": ">=17.0.2 <19.0.0"
+ "react": ">=19.0.0 <20.0.0",
+ "react-dom": ">=19.0.0 <20.0.0"
},
"dependencies": {
"@embeddedchat/ui-elements": "workspace:^",
diff --git a/packages/react/.storybook/main.js b/packages/react/.storybook/main.js
index 7c981da605..0db593a3da 100644
--- a/packages/react/.storybook/main.js
+++ b/packages/react/.storybook/main.js
@@ -5,15 +5,7 @@ const config = {
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
- {
- name: '@storybook/addon-styling',
- options: {
- sass: {
- // Require your Sass preprocessor here
- implementation: require('sass'),
- },
- },
- },
+ '@storybook/addon-webpack5-compiler-babel',
],
framework: {
name: '@storybook/react-webpack5',
diff --git a/packages/react/package.json b/packages/react/package.json
index 82cc802682..9c60c6a4f4 100644
--- a/packages/react/package.json
+++ b/packages/react/package.json
@@ -13,8 +13,8 @@
],
"scripts": {
"prebuild": "rimraf dist",
- "build": "rollup -c --context=window --environment NODE_ENV:production",
- "watch": "rollup -c --watch --context=window",
+ "build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 rollup -c --context=window --environment NODE_ENV:production",
+ "watch": "cross-env NODE_OPTIONS=--max-old-space-size=4096 rollup -c --watch --context=window",
"test:lint": "eslint src/**/*.js",
"format": "prettier --write 'src/' ",
"format:check": "prettier --check 'src/' ",
@@ -37,14 +37,14 @@
"@rollup/plugin-commonjs": "^21.0.2",
"@rollup/plugin-node-resolve": "^13.1.3",
"@rollup/plugin-replace": "^5.0.2",
- "@storybook/addon-essentials": "^7.0.26",
- "@storybook/addon-interactions": "^7.0.26",
- "@storybook/addon-links": "^7.0.26",
- "@storybook/addon-styling": "^1.3.6",
- "@storybook/blocks": "^7.0.26",
- "@storybook/react": "^7.0.26",
- "@storybook/react-webpack5": "^7.0.26",
- "@storybook/testing-library": "^0.2.0",
+ "@storybook/addon-essentials": "^8.0.0",
+ "@storybook/addon-interactions": "^8.0.0",
+ "@storybook/addon-links": "^8.0.0",
+ "@storybook/addon-webpack5-compiler-babel": "^3.0.0",
+ "@storybook/blocks": "^8.0.0",
+ "@storybook/react": "^8.0.0",
+ "@storybook/react-webpack5": "^8.0.0",
+ "@storybook/test": "^8.0.0",
"@testing-library/react": "^12.1.4",
"babel-jest": "^27.5.1",
"concurrently": "^7.2.0",
@@ -65,8 +65,8 @@
"lint-staged": "^12.4.2",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.1",
- "react": "^17.0.2",
- "react-dom": "^17.0.2",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
"rimraf": "^5.0.1",
"rollup": "^2.70.1",
"rollup-plugin-analyzer": "^4.0.0",
@@ -76,11 +76,11 @@
"rollup-plugin-terser": "^7.0.2",
"sass": "^1.66.1",
"schedule": "^0.4.0",
- "storybook": "^7.0.26"
+ "storybook": "^8.0.0"
},
"peerDependencies": {
- "react": ">=17.0.2 <19.0.0",
- "react-dom": ">=17.0.2 <19.0.0"
+ "react": ">=19.0.0 <20.0.0",
+ "react-dom": ">=19.0.0 <20.0.0"
},
"dependencies": {
"@embeddedchat/api": "workspace:^",
diff --git a/packages/react/src/hooks/useShowCommands.js b/packages/react/src/hooks/useShowCommands.js
index 1379f267c4..05115b6ce4 100644
--- a/packages/react/src/hooks/useShowCommands.js
+++ b/packages/react/src/hooks/useShowCommands.js
@@ -2,12 +2,11 @@ import { useCallback } from 'react';
const useShowCommands = (commands, setFilteredCommands, setShowCommandList) =>
useCallback(
- async (e) => {
+ async (cursor, value) => {
const getFilteredCommands = (cmd) =>
commands.filter((c) => c.command.startsWith(cmd.replace('/', '')));
- const cursor = e.target.selectionStart;
- const tokens = e.target.value.slice(0, cursor).split(/\s+/);
+ const tokens = value.slice(0, cursor).split(/\s+/);
if (tokens.length === 1 && tokens[0].startsWith('/')) {
setFilteredCommands(getFilteredCommands(tokens[0]));
diff --git a/packages/react/src/views/AttachmentPreview/PreviewType/audio.js b/packages/react/src/views/AttachmentPreview/PreviewType/audio.js
index da4bbe9fff..7dc902b32b 100644
--- a/packages/react/src/views/AttachmentPreview/PreviewType/audio.js
+++ b/packages/react/src/views/AttachmentPreview/PreviewType/audio.js
@@ -5,7 +5,7 @@ import { Box } from '@embeddedchat/ui-elements';
function PreviewAudio({ previewURL }) {
return (
-
+
);
}
diff --git a/packages/react/src/views/AttachmentPreview/PreviewType/image.js b/packages/react/src/views/AttachmentPreview/PreviewType/image.js
index 5c2d3b4d8a..60573d75af 100644
--- a/packages/react/src/views/AttachmentPreview/PreviewType/image.js
+++ b/packages/react/src/views/AttachmentPreview/PreviewType/image.js
@@ -7,7 +7,7 @@ function PreviewImage({ previewURL }) {
return (
{
- RCInstance.auth.onAuthChange((user) => {
- if (user) {
- RCInstance.addMessageListener(addMessage);
- RCInstance.addMessageDeleteListener(removeMessage);
- RCInstance.addActionTriggeredListener(onActionTriggerResponse);
- RCInstance.addUiInteractionListener(onActionTriggerResponse);
- }
- });
+ if (isUserAuthenticated) {
+ RCInstance.addMessageListener(addMessage);
+ RCInstance.addMessageDeleteListener(removeMessage);
+ RCInstance.addActionTriggeredListener(onActionTriggerResponse);
+ RCInstance.addUiInteractionListener(onActionTriggerResponse);
+ }
return () => {
RCInstance.removeMessageListener(addMessage);
@@ -161,28 +159,30 @@ const ChatBody = ({
RCInstance.removeActionTriggeredListener(onActionTriggerResponse);
RCInstance.removeUiInteractionListener(onActionTriggerResponse);
};
- }, [RCInstance, addMessage, removeMessage, onActionTriggerResponse]);
+ }, [
+ RCInstance,
+ isUserAuthenticated,
+ addMessage,
+ removeMessage,
+ onActionTriggerResponse,
+ ]);
useEffect(() => {
- RCInstance.auth.onAuthChange((user) => {
- if (user) {
- getMessagesAndRoles();
- setHasMoreMessages(true);
- } else {
- getMessagesAndRoles(anonymousMode);
- }
- });
- }, [RCInstance, anonymousMode, getMessagesAndRoles]);
+ if (isUserAuthenticated) {
+ getMessagesAndRoles();
+ setHasMoreMessages(true);
+ } else {
+ getMessagesAndRoles(anonymousMode);
+ }
+ }, [RCInstance, isUserAuthenticated, anonymousMode, getMessagesAndRoles]);
useEffect(() => {
- RCInstance.auth.onAuthChange((user) => {
- if (user) {
- fetchAndSetPermissions();
- } else {
- permissionsRef.current = null;
- }
- });
- }, []);
+ if (isUserAuthenticated) {
+ fetchAndSetPermissions();
+ } else {
+ permissionsRef.current = null;
+ }
+ }, [isUserAuthenticated, fetchAndSetPermissions, permissionsRef]);
// Expose clearUnreadDivider function via ref for ChatInput to call
useEffect(() => {
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index a310e538fd..c28e9ad39e 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -436,7 +436,12 @@ const ChatHeader = ({
{avatarUrl && (
-
+
)}
{surfaceOptions.length > 0 && (
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index f6fb0e111f..0a8d0d7cd8 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -107,6 +107,7 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
isRecordingMessage,
upsertMessage,
replaceMessage,
+ removeMessage,
clearQuoteMessages,
threadId,
deletedMessage,
@@ -119,6 +120,7 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
replaceMessage: state.replaceMessage,
threadId: state.threadMainMessage?._id,
clearQuoteMessages: state.clearQuoteMessages,
+ removeMessage: state.removeMessage,
deletedMessage: state.deletedMessage,
}));
@@ -161,20 +163,15 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
);
useEffect(() => {
- RCInstance.auth.onAuthChange((user) => {
- if (user) {
- RCInstance.getCommandsList()
- .then((response) => setCommands(response.commands || []))
- .catch(console.error);
-
- RCInstance.getChannelMembers(isChannelPrivate)
- .then((channelMembers) =>
- setMembersHandler(channelMembers.members || [])
- )
- .catch(console.error);
- }
- });
- }, [RCInstance, isChannelPrivate, setMembersHandler]);
+ if (!isUserAuthenticated) return;
+ RCInstance.getCommandsList()
+ .then((response) => setCommands(response.commands || []))
+ .catch(console.error);
+
+ RCInstance.getChannelMembers(isChannelPrivate)
+ .then((channelMembers) => setMembersHandler(channelMembers.members || []))
+ .catch(console.error);
+ }, [RCInstance, isUserAuthenticated, isChannelPrivate, setMembersHandler]);
useEffect(() => {
if (editMessage.attachments) {
@@ -275,34 +272,26 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
}
};
- const sendTypingStart = async () => {
- try {
- if (typingRef.current && messageRef.current.value?.length) {
- return;
- }
- if (messageRef.current.value?.length) {
- typingRef.current = true;
- timerRef.current = setTimeout(() => {
- typingRef.current = false;
- }, [15000]);
- await RCInstance.sendTypingStatus(username, true);
- } else {
- clearTimeout(timerRef.current);
+ const sendTypingStart = () => {
+ if (typingRef.current && messageRef.current.value?.length) {
+ return;
+ }
+ if (messageRef.current.value?.length) {
+ typingRef.current = true;
+ timerRef.current = setTimeout(() => {
typingRef.current = false;
- await RCInstance.sendTypingStatus(username, false);
- }
- } catch (e) {
- console.error(e);
+ }, [15000]);
+ RCInstance.sendTypingStatus(username, true).catch(() => {});
+ } else {
+ clearTimeout(timerRef.current);
+ typingRef.current = false;
+ RCInstance.sendTypingStatus(username, false).catch(() => {});
}
};
- const sendTypingStop = async () => {
- try {
- typingRef.current = false;
- await RCInstance.sendTypingStatus(username, false);
- } catch (e) {
- console.error(e);
- }
+ const sendTypingStop = () => {
+ typingRef.current = false;
+ RCInstance.sendTypingStatus(username, false).catch(() => {});
};
const handleSendNewMessage = async (message) => {
@@ -354,9 +343,12 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
ECOptions.enableThreads ? threadId : undefined
);
- if (res.success) {
+ if (res?.success) {
clearQuoteMessages();
- replaceMessage(pendingMessage, res.message);
+ replaceMessage(pendingMessage._id, res.message);
+ } else {
+ // If REST send failed, remove the pending message so it doesn't stay grey
+ removeMessage(pendingMessage._id);
}
};
@@ -448,7 +440,7 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
if (e !== null) {
handleNewLine(e, false);
searchMentionUser(message);
- showCommands(e);
+ showCommands(e.target.selectionStart, e.target.value);
searchEmoji(message);
}
};
@@ -724,7 +716,11 @@ const ChatInput = ({ scrollToBottom, clearUnreadDividerRef }) => {
/>
) : null
) : (
-
+ onJoin()}
+ type="primary"
+ disabled={isLoginIn}
+ >
{isLoginIn ? : 'JOIN'}
)}
diff --git a/packages/react/src/views/EmbeddedChat.js b/packages/react/src/views/EmbeddedChat.js
index f3b94c7b48..b2dc687247 100644
--- a/packages/react/src/views/EmbeddedChat.js
+++ b/packages/react/src/views/EmbeddedChat.js
@@ -134,7 +134,7 @@ const EmbeddedChat = (props) => {
}, [RCInstance, auth, setIsLoginIn]);
useEffect(() => {
- RCInstance.auth.onAuthChange((user) => {
+ const handleAuthChange = (user) => {
if (user) {
RCInstance.connect()
.then(() => {
@@ -149,9 +149,16 @@ const EmbeddedChat = (props) => {
})
.catch(console.error);
} else {
+ // Close the DDP connection on logout so the next login gets a fresh connection.
+ RCInstance.close().catch(console.error);
setIsUserAuthenticated(false);
}
- });
+ };
+ RCInstance.auth.onAuthChange(handleAuthChange);
+
+ return () => {
+ RCInstance.auth.removeAuthListener(handleAuthChange);
+ };
}, [
RCInstance,
setAuthenticatedName,
diff --git a/packages/react/src/views/LoginForm/LoginForm.js b/packages/react/src/views/LoginForm/LoginForm.js
index 1285e5e1eb..abf6e6e33a 100644
--- a/packages/react/src/views/LoginForm/LoginForm.js
+++ b/packages/react/src/views/LoginForm/LoginForm.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React, { useState, useRef } from 'react';
import { css } from '@emotion/react';
import {
GenericModal,
@@ -13,8 +13,8 @@ import { useRCAuth } from '../../hooks/useRCAuth';
import styles from './LoginForm.styles';
export default function LoginForm() {
- const [userOrEmail, setUserOrEmail] = useState(null);
- const [password, setPassword] = useState(null);
+ const userRef = useRef(null);
+ const passRef = useRef(null);
const [showPassword, setShowPassword] = useState(false);
const [usernameError, setUsernameError] = useState(false);
const [passwordError, setPasswordError] = useState(false);
@@ -26,36 +26,40 @@ export default function LoginForm() {
const { theme } = useTheme();
- useEffect(() => {
- if (userOrEmail !== null && userOrEmail.trim() === '') {
+ const handleSubmit = (e) => {
+ if (e && e.preventDefault) e.preventDefault();
+ const userOrEmail = userRef.current?.value || '';
+ const password = passRef.current?.value || '';
+
+ let hasError = false;
+ if (userOrEmail.trim() === '') {
setUsernameError(true);
+ hasError = true;
} else {
setUsernameError(false);
}
- if (password !== null && password.trim() === '') {
+ if (password.trim() === '') {
setPasswordError(true);
+ hasError = true;
} else {
setPasswordError(false);
}
- }, [userOrEmail, password]);
- const handleSubmit = () => {
- if (!userOrEmail) setUserOrEmail('');
- if (!password) setPassword('');
- handleLogin(userOrEmail, password);
+ if (!hasError) {
+ handleLogin(userOrEmail, password);
+ }
};
+
const handleClose = () => {
- setUserOrEmail(null);
- setPassword(null);
setIsLoginModalOpen(false);
};
- const handleEdituserOrEmail = (e) => {
- setUserOrEmail(e.target.value);
+ const handleEdituserOrEmail = () => {
+ if (usernameError) setUsernameError(false);
};
- const handleEditPassword = (e) => {
- setPassword(e.target.value);
+ const handleEditPassword = () => {
+ if (passwordError) setPasswordError(false);
};
const handleTogglePassword = () => {
setShowPassword(!showPassword);
@@ -69,15 +73,18 @@ export default function LoginForm() {
const fields = [
{
label: 'Email or username',
+ ref: userRef,
onChange: handleEdituserOrEmail,
placeholder: 'example@example.com',
error: usernameError,
},
{
label: 'Password',
+ ref: passRef,
type: showPassword ? 'text' : 'password',
onChange: handleEditPassword,
error: passwordError,
+ autoComplete: 'new-password',
},
];
@@ -96,6 +103,7 @@ export default function LoginForm() {
@@ -320,7 +324,11 @@ export const MessageToolbox = ({
style={{ maxWidth: '100%', maxHeight: '200px' }}
>
Your browser does not support the video tag.
@@ -328,7 +336,11 @@ export const MessageToolbox = ({
) : message.file.type.startsWith('audio/') ? (