@xipkg/calls-chat 0.1.53 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -1
- package/dist/index.mjs +9 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
+
import { CSSProperties } from 'react';
|
|
2
3
|
import { JSONContent } from '@tiptap/core';
|
|
3
4
|
import * as zustand from 'zustand';
|
|
4
5
|
|
|
5
6
|
type ChatProps = {
|
|
6
7
|
/** В компакт-режиме: классы позиционирования (как у CompactCall: top-16 bottom-4 left-4 и т.д.) */
|
|
7
8
|
compactPositionClassName?: string;
|
|
9
|
+
/** В компакт-режиме: отступы от краёв. Нужны, когда тулбар доски занимает не только низ. */
|
|
10
|
+
compactPositionStyle?: CSSProperties;
|
|
8
11
|
/** Встроить чат в родителя (PiP): без fixed/modal, на всю доступную высоту */
|
|
9
12
|
embedded?: boolean;
|
|
10
13
|
};
|
|
11
|
-
declare const Chat: ({ compactPositionClassName, embedded }?: ChatProps) => react.JSX.Element | null;
|
|
14
|
+
declare const Chat: ({ compactPositionClassName, compactPositionStyle, embedded, }?: ChatProps) => react.JSX.Element | null;
|
|
12
15
|
|
|
13
16
|
type ChatButtonProps = {
|
|
14
17
|
/** Дополнительные классы (например, для компактной панели: h-8 w-8 rounded-xl) */
|
package/dist/index.mjs
CHANGED
|
@@ -370,7 +370,7 @@ var ChatBubbleMenu = ({ editor }) => {
|
|
|
370
370
|
strategy: "fixed",
|
|
371
371
|
offset: 8
|
|
372
372
|
},
|
|
373
|
-
className: "border-border-default bg-background-surface z-200 flex gap-1 rounded-lg border p-1 shadow-lg",
|
|
373
|
+
className: "calls-portaled-overlay border-border-default bg-background-surface z-200 flex gap-1 rounded-lg border p-1 shadow-lg",
|
|
374
374
|
children: [
|
|
375
375
|
/* @__PURE__ */ jsx(
|
|
376
376
|
FormatButton,
|
|
@@ -594,7 +594,11 @@ var parseLinks = (message) => {
|
|
|
594
594
|
var ChatMessageContent = ({ text, content, className }) => {
|
|
595
595
|
return /* @__PURE__ */ jsx("div", { className: cn(chatMessageProseClassName, className), children: content ? renderChatJsonContent(content) : parseLinks(text) });
|
|
596
596
|
};
|
|
597
|
-
var Chat = ({
|
|
597
|
+
var Chat = ({
|
|
598
|
+
compactPositionClassName,
|
|
599
|
+
compactPositionStyle,
|
|
600
|
+
embedded = false
|
|
601
|
+
} = {}) => {
|
|
598
602
|
const { t, i18n } = useTranslation("calls");
|
|
599
603
|
const messagesEndRef = useRef(null);
|
|
600
604
|
const { sendChatMessage, deleteChatMessage, closeChat } = useChat();
|
|
@@ -711,14 +715,15 @@ var Chat = ({ compactPositionClassName, embedded = false } = {}) => {
|
|
|
711
715
|
}
|
|
712
716
|
) });
|
|
713
717
|
}
|
|
714
|
-
if (compactPositionClassName) {
|
|
718
|
+
if (compactPositionClassName || compactPositionStyle) {
|
|
715
719
|
return /* @__PURE__ */ jsx(
|
|
716
720
|
"div",
|
|
717
721
|
{
|
|
718
722
|
className: cn(
|
|
719
|
-
"border-border-default bg-background-surface fixed z-
|
|
723
|
+
"border-border-default bg-background-surface fixed z-20 flex min-h-0 w-[328px] flex-col overflow-hidden rounded-2xl border p-4 pr-1 shadow-lg",
|
|
720
724
|
compactPositionClassName
|
|
721
725
|
),
|
|
726
|
+
style: compactPositionStyle,
|
|
722
727
|
children: chatContent
|
|
723
728
|
}
|
|
724
729
|
);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/editor/sanitizeContent.ts","../src/store/chatStore.ts","../src/hooks/useChat.ts","../src/editor/discordMarks.ts","../src/editor/extensions.ts","../src/editor/proseClassName.ts","../src/ui/ChatBubbleMenu.tsx","../src/ui/ChatComposer.tsx","../src/editor/renderJsonContent.tsx","../src/utils/chat.tsx","../src/ui/ChatMessageContent.tsx","../src/ui/Chat.tsx","../src/ui/ChatButton.tsx"],"names":["sanitized","cn","Bold","UnderlineIcon","useCallback","useEditorState","jsx","jsxs","Button","LINK_CLASS","useTranslation","useRef","useEffect","Chat"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { JSONContent } from '@tiptap/core';\n\nconst ALLOWED_NODES = new Set(['doc', 'paragraph', 'text', 'hardBreak', 'codeBlock', 'blockquote']);\n\nconst ALLOWED_MARKS = new Set(['bold', 'italic', 'strike', 'underline', 'code', 'link']);\n\nconst MAX_NODES = 400;\nconst MAX_TEXT = 8000;\nconst MAX_DEPTH = 16;\nconst MAX_HREF_LENGTH = 2000;\n\nconst isSafeHref = (href: unknown): href is string => {\n if (typeof href !== 'string' || href.length === 0 || href.length > MAX_HREF_LENGTH) {\n return false;\n }\n\n try {\n const url = new URL(href);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n};\n\nexport const sanitizeChatContent = (input: unknown): JSONContent | undefined => {\n if (!input || typeof input !== 'object') return undefined;\n\n let nodeCount = 0;\n let textLength = 0;\n\n const walk = (node: unknown, depth: number): JSONContent | null => {\n if (nodeCount > MAX_NODES || textLength > MAX_TEXT || depth > MAX_DEPTH) return null;\n if (!node || typeof node !== 'object') return null;\n\n const raw = node as JSONContent;\n if (typeof raw.type !== 'string' || !ALLOWED_NODES.has(raw.type)) return null;\n\n nodeCount += 1;\n const result: JSONContent = { type: raw.type };\n\n if (raw.type === 'text') {\n if (typeof raw.text !== 'string') return null;\n textLength += raw.text.length;\n result.text = raw.text;\n }\n\n if (raw.type === 'codeBlock' && raw.attrs && typeof raw.attrs.language === 'string') {\n result.attrs = { language: raw.attrs.language.slice(0, 32) };\n }\n\n if (Array.isArray(raw.marks) && raw.marks.length > 0) {\n const marks: NonNullable<JSONContent['marks']> = [];\n\n for (const mark of raw.marks) {\n if (!mark || typeof mark !== 'object' || typeof mark.type !== 'string') continue;\n if (!ALLOWED_MARKS.has(mark.type)) continue;\n\n if (mark.type === 'link') {\n const href = mark.attrs?.href;\n if (!isSafeHref(href)) continue;\n marks.push({\n type: 'link',\n attrs: { href, target: '_blank', rel: 'noopener noreferrer' },\n });\n continue;\n }\n\n marks.push({ type: mark.type });\n }\n\n if (marks.length > 0) result.marks = marks;\n }\n\n if (Array.isArray(raw.content)) {\n const content: JSONContent[] = [];\n for (const child of raw.content) {\n const sanitized = walk(child, depth + 1);\n if (sanitized) content.push(sanitized);\n }\n if (content.length > 0) result.content = content;\n }\n\n return result;\n };\n\n const sanitized = walk(input, 0);\n if (!sanitized || sanitized.type !== 'doc') return undefined;\n return sanitized;\n};\n","import { create } from 'zustand';\nimport type { ChatMessageT } from '../types';\n\nexport type { ChatMessageT };\n\nexport type useChatStoreT = {\n isChatOpen: boolean;\n chatMessages: ChatMessageT[];\n unreadMessagesCount: number;\n addChatMessage: (message: ChatMessageT) => void;\n removeChatMessage: (messageId: string) => void;\n clearUnreadMessages: () => void;\n updateStore: (type: keyof useChatStoreT, value: unknown) => void;\n};\n\n// Чат передаётся только через LiveKit DataChannel (P2P/broadcast в рамках текущего звонка),\n// серверной истории сообщений нет. Раньше стор персистился в localStorage без привязки\n// к конкретному звонку — сообщения предыдущего звонка «утекали» в следующий на том же\n// устройстве (и только у того пользователя, у кого localStorage не был очищен штатным\n// disconnect-флоу). Стор намеренно НЕ персистится: чат живёт только в памяти на время\n// звонка и одинаково пуст у всех при входе в новый звонок.\nexport const useChatStore = create<useChatStoreT>()((set, get) => ({\n isChatOpen: false,\n chatMessages: [],\n unreadMessagesCount: 0,\n updateStore: (type: keyof useChatStoreT, value: unknown) => set({ [type]: value }),\n\n addChatMessage: (message: ChatMessageT) => {\n const { isChatOpen, unreadMessagesCount, chatMessages } = get();\n\n // Проверяем, нет ли уже сообщения с таким ID (дедупликация)\n const messageExists = chatMessages.some((msg) => msg.id === message.id);\n if (messageExists) {\n return;\n }\n\n set((state) => ({\n chatMessages: [...state.chatMessages, message],\n unreadMessagesCount: isChatOpen ? unreadMessagesCount : unreadMessagesCount + 1,\n }));\n },\n\n removeChatMessage: (messageId: string) => {\n set((state) => ({\n chatMessages: state.chatMessages.filter((msg) => msg.id !== messageId),\n }));\n },\n\n clearUnreadMessages: () => set({ unreadMessagesCount: 0 }),\n}));\n","import { useCallback } from 'react';\nimport type { JSONContent } from '@tiptap/core';\nimport { useLiveKitDataChannel, useLiveKitDataChannelListener } from '@xipkg/calls-hooks';\nimport { useRoom } from '@xipkg/calls-providers';\nimport { useSoundEffectsStore } from '@xipkg/calls-store';\nimport { playSound } from '@xipkg/calls-utils';\nimport { sanitizeChatContent } from '../editor/sanitizeContent';\nimport { useChatStore } from '../store';\nimport type { ChatMessageT } from '../types';\n\nconst CHAT_MESSAGE_TYPE = 'chat_message';\nconst CHAT_MESSAGE_DELETE_TYPE = 'chat_message_delete';\n\ntype ChatMessagePayload = ChatMessageT;\n\ntype ChatMessageDeletePayload = {\n id: string;\n senderId: string;\n};\n\nexport const useChat = () => {\n const { sendMessage } = useLiveKitDataChannel();\n const { addChatMessage, removeChatMessage, clearUnreadMessages, updateStore } = useChatStore();\n const chatSoundVolume = useSoundEffectsStore((s) => s.chatMessageVolume);\n const { room } = useRoom();\n\n // Получаем информацию о текущем участнике из LiveKit\n const getCurrentParticipantInfo = useCallback(() => {\n if (!room?.localParticipant) {\n return {\n senderId: 'unknown',\n senderName: 'Unknown User',\n };\n }\n\n const participant = room.localParticipant;\n\n try {\n // Парсим метаданные участника\n const metadata = participant.metadata;\n if (metadata) {\n const userInfo = JSON.parse(metadata);\n return {\n senderId: userInfo?.user_id || userInfo?.id || participant.identity,\n senderName:\n userInfo?.display_name ||\n userInfo?.name ||\n userInfo?.username ||\n participant.name ||\n participant.identity,\n };\n }\n } catch (error) {\n console.warn('⚠️ Failed to parse participant metadata:', error);\n }\n\n // Fallback на стандартные поля LiveKit\n return {\n senderId: participant.identity,\n senderName: participant.name || participant.identity,\n };\n }, [room]);\n\n const handleChatMessage = useCallback(\n (message: { type: string; payload: unknown }) => {\n if (message.type === CHAT_MESSAGE_TYPE) {\n const payload = message.payload as ChatMessagePayload;\n\n // Проверяем, что это не наше собственное сообщение\n const currentParticipantInfo = getCurrentParticipantInfo();\n if (payload.senderId === currentParticipantInfo.senderId) {\n return;\n }\n\n addChatMessage({\n ...payload,\n content: sanitizeChatContent(payload.content),\n });\n playSound('chatMessage', chatSoundVolume);\n return;\n }\n\n if (message.type === CHAT_MESSAGE_DELETE_TYPE) {\n const payload = message.payload as ChatMessageDeletePayload;\n if (!payload?.id || !payload?.senderId) return;\n\n // Удаляем только если автор удаления совпадает с автором сообщения —\n // чужой клиент не может удалить чужие сообщения через поддельный payload.\n const existing = useChatStore.getState().chatMessages.find((msg) => msg.id === payload.id);\n if (!existing) return;\n if (String(existing.senderId) !== String(payload.senderId)) return;\n\n removeChatMessage(payload.id);\n }\n },\n [addChatMessage, removeChatMessage, getCurrentParticipantInfo, chatSoundVolume],\n );\n\n // Слушаем сообщения чата\n useLiveKitDataChannelListener(handleChatMessage);\n\n const sendChatMessage = useCallback(\n (text: string, content?: JSONContent) => {\n if (!text.trim()) return;\n\n const participantInfo = getCurrentParticipantInfo();\n const sanitizedContent = sanitizeChatContent(content);\n const message: ChatMessagePayload = {\n id: `${Date.now()}-${Math.random()}`,\n text: text.trim(),\n ...(sanitizedContent ? { content: sanitizedContent } : {}),\n senderId: participantInfo.senderId,\n senderName: participantInfo.senderName,\n timestamp: Date.now(),\n };\n\n // Добавляем сообщение в локальный store отправителя\n addChatMessage(message);\n\n // Отправляем через DataChannel\n sendMessage(CHAT_MESSAGE_TYPE, message);\n },\n [sendMessage, getCurrentParticipantInfo, addChatMessage],\n );\n\n const deleteChatMessage = useCallback(\n (messageId: string) => {\n const existing = useChatStore.getState().chatMessages.find((msg) => msg.id === messageId);\n if (!existing) return;\n\n const participantInfo = getCurrentParticipantInfo();\n if (String(existing.senderId) !== String(participantInfo.senderId)) return;\n\n const payload: ChatMessageDeletePayload = {\n id: messageId,\n senderId: participantInfo.senderId,\n };\n\n // Optimistic: сразу убираем у себя, затем broadcast для остальных\n removeChatMessage(messageId);\n sendMessage(CHAT_MESSAGE_DELETE_TYPE, payload);\n },\n [sendMessage, getCurrentParticipantInfo, removeChatMessage],\n );\n\n const toggleChat = useCallback(() => {\n updateStore('isChatOpen', !useChatStore.getState().isChatOpen);\n clearUnreadMessages();\n }, [updateStore, clearUnreadMessages]);\n\n const openChat = useCallback(() => {\n updateStore('isChatOpen', true);\n clearUnreadMessages();\n }, [updateStore, clearUnreadMessages]);\n\n const closeChat = useCallback(() => {\n updateStore('isChatOpen', false);\n }, [updateStore]);\n\n return {\n sendChatMessage,\n deleteChatMessage,\n toggleChat,\n openChat,\n closeChat,\n };\n};\n","import { markInputRule, markPasteRule } from '@tiptap/core';\nimport { Bold, starInputRegex, starPasteRegex } from '@tiptap/extension-bold';\nimport { Underline } from '@tiptap/extension-underline';\n\n/**\n * Discord: `**жирный**`, `__подчёркнутый__`.\n * Стандартный markdown / StarterKit мапит `__` на bold — переназначаем.\n */\nconst underlineInputRegex = /(?:^|\\s)(__(?!\\s+__)((?:[^_]+))__(?!\\s+__))$/;\nconst underlinePasteRegex = /(?:^|\\s)(__(?!\\s+__)((?:[^_]+))__(?!\\s+__))/g;\n\nexport const DiscordBold = Bold.extend({\n addInputRules() {\n return [\n markInputRule({\n find: starInputRegex,\n type: this.type,\n }),\n ];\n },\n addPasteRules() {\n return [\n markPasteRule({\n find: starPasteRegex,\n type: this.type,\n }),\n ];\n },\n});\n\nexport const DiscordUnderline = Underline.extend({\n addInputRules() {\n return [\n markInputRule({\n find: underlineInputRegex,\n type: this.type,\n }),\n ];\n },\n addPasteRules() {\n return [\n markPasteRule({\n find: underlinePasteRegex,\n type: this.type,\n }),\n ];\n },\n});\n","import StarterKit from '@tiptap/starter-kit';\nimport { DiscordBold, DiscordUnderline } from './discordMarks';\n\nconst LINK_CLASS = 'text-text-link hover:text-text-link cursor-pointer underline';\n\n/** Схема чата: Discord-шорткаты + тот же набор марок, что у текста на доске. */\nexport const chatExtensions = [\n StarterKit.configure({\n bold: false,\n underline: false,\n heading: false,\n horizontalRule: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n listKeymap: false,\n trailingNode: false,\n link: {\n openOnClick: false,\n autolink: true,\n defaultProtocol: 'https',\n HTMLAttributes: {\n target: '_blank',\n rel: 'noopener noreferrer',\n class: LINK_CLASS,\n },\n },\n }),\n DiscordBold,\n DiscordUnderline,\n];\n","import { cn } from '@xipkg/utils';\n\n/**\n * Жирный — 700, не 600: при синтезе начертания (нет файла Inter Bold) 600 почти неотличим от 400.\n */\nconst chatInlineMarksClassName = cn(\n '[&_strong]:font-bold',\n '[&_em]:italic',\n '[&_s]:line-through',\n '[&_u]:underline',\n);\n\n/** Общие стили ProseMirror для композера и пузырьков сообщений. */\nexport const chatProseClassName = cn(\n '[&_.ProseMirror]:min-h-6 [&_.ProseMirror]:text-sm [&_.ProseMirror]:break-words [&_.ProseMirror]:outline-none',\n '[&_.ProseMirror_p]:m-0 [&_.ProseMirror_p+p]:mt-1',\n '[&_.ProseMirror_strong]:font-bold',\n '[&_.ProseMirror_em]:italic',\n '[&_.ProseMirror_s]:line-through',\n '[&_.ProseMirror_u]:underline',\n '[&_.ProseMirror_code]:bg-background-page [&_.ProseMirror_code]:rounded [&_.ProseMirror_code]:px-1 [&_.ProseMirror_code]:py-0.5 [&_.ProseMirror_code]:font-mono [&_.ProseMirror_code]:text-[0.85em]',\n '[&_.ProseMirror_pre]:bg-background-page [&_.ProseMirror_pre]:my-1 [&_.ProseMirror_pre]:overflow-x-auto [&_.ProseMirror_pre]:rounded-lg [&_.ProseMirror_pre]:p-2 [&_.ProseMirror_pre]:font-mono [&_.ProseMirror_pre]:text-xs [&_.ProseMirror_pre]:whitespace-pre-wrap',\n '[&_.ProseMirror_blockquote]:border-border-default [&_.ProseMirror_blockquote]:text-text-secondary [&_.ProseMirror_blockquote]:my-1 [&_.ProseMirror_blockquote]:border-l-2 [&_.ProseMirror_blockquote]:pl-2',\n '[&_.ProseMirror_a]:text-text-link [&_.ProseMirror_a]:cursor-pointer [&_.ProseMirror_a]:underline',\n);\n\nexport const chatMessageProseClassName = cn(\n 'text-sm wrap-break-word',\n '[&_p]:m-0 [&_p+p]:mt-1',\n chatInlineMarksClassName,\n);\n","import type { Editor } from '@tiptap/core';\nimport { TextSelection } from '@tiptap/pm/state';\nimport type { EditorState } from '@tiptap/pm/state';\nimport { BubbleMenu } from '@tiptap/react/menus';\nimport { useEditorState } from '@tiptap/react';\nimport { Bold, Italic, Stroke, Underline as UnderlineIcon } from '@xipkg/icons';\nimport { Button } from '@xipkg/button';\nimport { cn } from '@xipkg/utils';\nimport { useTranslation } from 'react-i18next';\nimport type { ReactNode } from 'react';\n\ntype FormatTypeT = 'bold' | 'italic' | 'underline' | 'strike';\n\ntype ChatBubbleMenuProps = {\n editor: Editor;\n};\n\nconst isValidTextSelection = (state: EditorState): boolean => {\n const { doc, selection } = state;\n if (!(selection instanceof TextSelection) || selection.empty) return false;\n if (selection.from === 0 || selection.to === 0) return false;\n\n try {\n const $from = doc.resolve(selection.from);\n const $to = doc.resolve(selection.to);\n return $from.parent.isTextblock && $to.parent.isTextblock;\n } catch {\n return false;\n }\n};\n\ntype FormatButtonProps = {\n editor: Editor;\n type: FormatTypeT;\n isActive: boolean;\n ariaLabel: string;\n children: ReactNode;\n};\n\nconst FormatButton = ({ editor, type, isActive, ariaLabel, children }: FormatButtonProps) => {\n return (\n <Button\n type=\"button\"\n variant=\"none\"\n aria-label={ariaLabel}\n aria-pressed={isActive}\n className={cn(\n '[&_svg]:fill-icon-primary h-6 w-6 rounded-sm p-1',\n isActive && 'bg-status-info-background [&_svg]:fill-icon-brand',\n )}\n onMouseDown={(event) => {\n event.preventDefault();\n editor.chain().focus().toggleMark(type).run();\n }}\n >\n {children}\n </Button>\n );\n};\n\nexport const ChatBubbleMenu = ({ editor }: ChatBubbleMenuProps) => {\n const { t } = useTranslation('calls');\n const activeStates = useEditorState({\n editor,\n selector: ({ editor: current }) => ({\n bold: current.isActive('bold'),\n italic: current.isActive('italic'),\n underline: current.isActive('underline'),\n strike: current.isActive('strike'),\n }),\n });\n\n return (\n <BubbleMenu\n editor={editor}\n appendTo={() => editor.view.dom.ownerDocument.body}\n shouldShow={({ state }) => isValidTextSelection(state)}\n options={{\n placement: 'top',\n strategy: 'fixed',\n offset: 8,\n }}\n className=\"border-border-default bg-background-surface z-200 flex gap-1 rounded-lg border p-1 shadow-lg\"\n >\n <FormatButton\n editor={editor}\n type=\"bold\"\n isActive={activeStates.bold}\n ariaLabel={t('chat.formatBold')}\n >\n <Bold />\n </FormatButton>\n <FormatButton\n editor={editor}\n type=\"italic\"\n isActive={activeStates.italic}\n ariaLabel={t('chat.formatItalic')}\n >\n <Italic />\n </FormatButton>\n <FormatButton\n editor={editor}\n type=\"underline\"\n isActive={activeStates.underline}\n ariaLabel={t('chat.formatUnderline')}\n >\n <UnderlineIcon />\n </FormatButton>\n <FormatButton\n editor={editor}\n type=\"strike\"\n isActive={activeStates.strike}\n ariaLabel={t('chat.formatStrike')}\n >\n <Stroke />\n </FormatButton>\n </BubbleMenu>\n );\n};\n","import { useCallback, useEffect, useRef } from 'react';\nimport type { Editor, JSONContent } from '@tiptap/core';\nimport { EditorContent, useEditor, useEditorState } from '@tiptap/react';\nimport { Button } from '@xipkg/button';\nimport { Send } from '@xipkg/icons';\nimport { cn } from '@xipkg/utils';\nimport { chatExtensions } from '../editor/extensions';\nimport { chatProseClassName } from '../editor/proseClassName';\nimport { ChatBubbleMenu } from './ChatBubbleMenu';\n\ntype ChatComposerProps = {\n placeholder: string;\n onSend: (text: string, content: JSONContent) => void;\n};\n\nexport const ChatComposer = ({ placeholder, onSend }: ChatComposerProps) => {\n const onSendRef = useRef(onSend);\n onSendRef.current = onSend;\n\n const editorRef = useRef<Editor | null>(null);\n\n const sendFromEditor = useCallback(() => {\n const current = editorRef.current;\n if (!current || current.isDestroyed) return;\n\n const text = current.getText({ blockSeparator: '\\n' }).trim();\n if (!text) return;\n\n onSendRef.current(text, current.getJSON());\n current.commands.clearContent(true);\n current.commands.focus();\n }, []);\n\n const sendFromEditorRef = useRef(sendFromEditor);\n sendFromEditorRef.current = sendFromEditor;\n\n const editor = useEditor({\n immediatelyRender: false,\n extensions: chatExtensions,\n autofocus: true,\n editorProps: {\n attributes: {\n class: 'min-h-6 text-sm break-words outline-none',\n 'aria-label': placeholder,\n },\n handleKeyDown: (_view, event) => {\n if (\n event.key !== 'Enter' ||\n event.shiftKey ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey\n ) {\n return false;\n }\n if (event.isComposing || event.keyCode === 229) return false;\n\n event.preventDefault();\n sendFromEditorRef.current();\n return true;\n },\n },\n });\n\n useEffect(() => {\n editorRef.current = editor;\n }, [editor]);\n\n const isEmpty =\n useEditorState({\n editor,\n selector: ({ editor: current }) => !current?.getText({ blockSeparator: '\\n' }).trim(),\n }) ?? true;\n\n return (\n <div className=\"flex shrink-0 items-end gap-2 pr-3\">\n <div\n className={cn(\n 'border-border-default flex max-h-40 w-full flex-1 items-center rounded-xl border pl-4',\n chatProseClassName,\n )}\n >\n <div className=\"relative min-w-0 flex-1\">\n {isEmpty && (\n <span className=\"text-text-secondary pointer-events-none absolute top-3 left-0 text-sm\">\n {placeholder}\n </span>\n )}\n <EditorContent editor={editor} className=\"my-3 max-h-32 overflow-y-auto pr-2\" />\n {editor && <ChatBubbleMenu editor={editor} />}\n </div>\n <div className=\"pr-1\">\n <Button\n size=\"icon\"\n variant=\"primary\"\n onClick={sendFromEditor}\n disabled={isEmpty}\n className=\"rounded-xl p-2\"\n >\n <Send\n className={cn(\n 'fill-action-primary-text group-hover:fill-action-primary-text h-6 w-6',\n isEmpty && 'fill-icon-secondary',\n )}\n />\n </Button>\n </div>\n </div>\n </div>\n );\n};\n","import type { JSONContent } from '@tiptap/core';\nimport type { ReactNode } from 'react';\n\nconst LINK_CLASS = 'text-text-link hover:text-text-link cursor-pointer underline';\n\nconst wrapMarks = (text: string, marks: JSONContent['marks']): ReactNode => {\n return (marks ?? []).reduce<ReactNode>((acc, mark) => {\n switch (mark.type) {\n case 'bold':\n return <strong className=\"font-bold\">{acc}</strong>;\n case 'italic':\n return <em className=\"italic\">{acc}</em>;\n case 'strike':\n return <s>{acc}</s>;\n case 'underline':\n return <u>{acc}</u>;\n case 'code':\n return (\n <code className=\"bg-background-page rounded px-1 py-0.5 font-mono text-[0.85em]\">\n {acc}\n </code>\n );\n case 'link': {\n const href = typeof mark.attrs?.href === 'string' ? mark.attrs.href : undefined;\n if (!href) return acc;\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={LINK_CLASS}\n onClick={(event) => event.stopPropagation()}\n data-umami-event=\"outbound-link-click\"\n data-umami-event-url={href}\n data-umami-event-source=\"chat\"\n >\n {acc}\n </a>\n );\n }\n default:\n return acc;\n }\n }, text);\n};\n\nconst renderNode = (node: JSONContent, key: string): ReactNode => {\n const children = node.content?.map((child, index) => renderNode(child, `${key}-${index}`));\n\n switch (node.type) {\n case 'doc':\n return children;\n case 'paragraph':\n return (\n <p key={key} className=\"m-0 min-h-[1em]\">\n {children ?? <br />}\n </p>\n );\n case 'blockquote':\n return (\n <blockquote\n key={key}\n className=\"border-border-default text-text-secondary my-1 border-l-2 pl-2\"\n >\n {children}\n </blockquote>\n );\n case 'codeBlock':\n return (\n <pre\n key={key}\n className=\"bg-background-page my-1 overflow-x-auto rounded-lg p-2 font-mono text-xs whitespace-pre-wrap\"\n >\n <code>{children}</code>\n </pre>\n );\n case 'hardBreak':\n return <br key={key} />;\n case 'text':\n return <span key={key}>{wrapMarks(node.text ?? '', node.marks)}</span>;\n default:\n return children;\n }\n};\n\nexport const renderChatJsonContent = (content: JSONContent): ReactNode => {\n return renderNode(content, 'chat-doc');\n};\n","export const parseLinks = (message: string) => {\n const urlRegex = /(https?:\\/\\/[^\\s]+)/g;\n const messageParts = message.split(urlRegex);\n\n return messageParts.map((messagePart, index) => {\n if (urlRegex.test(messagePart)) {\n return (\n <a\n key={index}\n href={messagePart}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-text-link hover:text-text-link cursor-pointer underline\"\n onClick={(e) => e.stopPropagation()}\n data-umami-event=\"outbound-link-click\"\n data-umami-event-url={messagePart}\n data-umami-event-source=\"chat\"\n >\n {messagePart}\n </a>\n );\n }\n\n return messagePart;\n });\n};\n","import type { JSONContent } from '@tiptap/core';\nimport { cn } from '@xipkg/utils';\nimport { renderChatJsonContent } from '../editor/renderJsonContent';\nimport { chatMessageProseClassName } from '../editor/proseClassName';\nimport { parseLinks } from '../utils/chat';\n\ntype ChatMessageContentProps = {\n text: string;\n content?: JSONContent;\n className?: string;\n};\n\nexport const ChatMessageContent = ({ text, content, className }: ChatMessageContentProps) => {\n return (\n <div className={cn(chatMessageProseClassName, className)}>\n {content ? renderChatJsonContent(content) : parseLinks(text)}\n </div>\n );\n};\n","import { useRef, useEffect } from 'react';\nimport type { JSONContent } from '@tiptap/core';\nimport { Button } from '@xipkg/button';\nimport { Close, Trash } from '@xipkg/icons';\nimport { UserProfile } from '@xipkg/userprofile';\nimport { ScrollArea } from '@xipkg/scrollarea';\nimport { Modal, ModalContent, ModalTitle } from '@xipkg/modal';\nimport { useTranslation } from 'react-i18next';\nimport { useChat } from '../hooks';\nimport { useCalls } from '@xipkg/calls-providers';\nimport { useChatStore } from '../store';\nimport { cn, useMediaQuery } from '@xipkg/utils';\nimport { ChatComposer } from './ChatComposer';\nimport { ChatMessageContent } from './ChatMessageContent';\n\ntype ChatProps = {\n /** В компакт-режиме: классы позиционирования (как у CompactCall: top-16 bottom-4 left-4 и т.д.) */\n compactPositionClassName?: string;\n /** Встроить чат в родителя (PiP): без fixed/modal, на всю доступную высоту */\n embedded?: boolean;\n};\n\nexport const Chat = ({ compactPositionClassName, embedded = false }: ChatProps = {}) => {\n const { t, i18n } = useTranslation('calls');\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const { sendChatMessage, deleteChatMessage, closeChat } = useChat();\n const { chatMessages, isChatOpen } = useChatStore();\n const { data: currentUser } = useCalls().auth.useCurrentUser();\n const timeLocale = i18n.language?.startsWith('ru')\n ? 'ru-RU'\n : i18n.language?.startsWith('en')\n ? 'en-US'\n : i18n.language;\n\n const scrollToBottom = (behavior: ScrollBehavior = 'smooth') => {\n messagesEndRef.current?.scrollIntoView({ behavior });\n };\n\n useEffect(() => {\n if (isChatOpen) {\n requestAnimationFrame(() => {\n scrollToBottom('auto');\n });\n }\n }, [isChatOpen]);\n\n // Автоматическая прокрутка при получении новых сообщений\n useEffect(() => {\n if (isChatOpen && chatMessages.length > 0) {\n requestAnimationFrame(() => {\n scrollToBottom('smooth');\n });\n }\n }, [chatMessages.length, isChatOpen]);\n\n const handleSendMessage = (text: string, content?: JSONContent) => {\n sendChatMessage(text, content);\n requestAnimationFrame(() => {\n scrollToBottom('smooth');\n });\n };\n\n const isMobile = useMediaQuery('(max-width: 639px)');\n if (!isChatOpen) return null;\n\n const chatPanelClassName =\n 'border-border-default bg-background-surface flex min-h-0 flex-col overflow-hidden rounded-2xl border p-4 pr-1';\n\n const chatContent = (\n <>\n {/* Заголовок */}\n <div className=\"border-border-default flex shrink-0 items-center justify-between pr-3\">\n <h3 className=\"text-text-primary text-lg font-medium\">{t('chat.title')}</h3>\n <Button size=\"icon\" variant=\"none\" onClick={closeChat}>\n <Close className=\"h-6 w-6\" aria-label={t('chat.close')} />\n </Button>\n </div>\n\n {/* Сообщения */}\n <ScrollArea className=\"h-full min-h-0 flex-1 py-2 pr-3\">\n <div className=\"space-y-4\">\n {chatMessages.length === 0 ? (\n <div className=\"text-text-secondary text-center\">\n <p>{t('chat.empty')}</p>\n </div>\n ) : (\n chatMessages.map((message) => {\n const isOwnMessage = Number(message.senderId) === Number(currentUser?.id);\n return (\n <div\n key={message.id}\n className={`group flex ${isOwnMessage ? 'justify-end' : 'justify-start'}`}\n >\n <div className=\"text-text-primary flex max-w-[90%] flex-col gap-1 rounded-lg select-text\">\n <div className=\"text-text-primary flex flex-row items-center gap-1 text-xs font-medium\">\n {!isOwnMessage && (\n <UserProfile\n size=\"s\"\n userId={Number(message.senderId)}\n text={message.senderName}\n src={`https://api.sovlium.ru/files/users/${message.senderId}/avatar.webp`}\n />\n )}\n <div\n className={`text-xs-base ${isOwnMessage ? 'text-text-disabled ml-auto' : 'text-text-secondary'}`}\n >\n {new Date(message.timestamp).toLocaleTimeString(timeLocale, {\n hour: '2-digit',\n minute: '2-digit',\n })}\n </div>\n </div>\n <div className=\"relative\">\n <ChatMessageContent\n text={message.text}\n content={message.content}\n className={cn(\n 'cursor-text rounded-lg px-3 py-2 select-text',\n isOwnMessage\n ? 'bg-action-primary-background-disabled'\n : 'bg-background-page',\n )}\n />\n {isOwnMessage && (\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"none\"\n className=\"bg-background-surface border-border-default absolute -top-2 -left-2 h-7 w-7 rounded-full border p-1 opacity-100 shadow-sm sm:opacity-0 sm:group-focus-within:opacity-100 sm:group-hover:opacity-100\"\n onClick={() => deleteChatMessage(message.id)}\n aria-label={t('chat.deleteAria')}\n >\n <Trash className=\"fill-icon-secondary h-4 w-4\" />\n </Button>\n )}\n </div>\n </div>\n </div>\n );\n })\n )}\n <div ref={messagesEndRef} />\n </div>\n </ScrollArea>\n\n <ChatComposer placeholder={t('chat.placeholder')} onSend={handleSendMessage} />\n </>\n );\n\n if (embedded) {\n return (\n <div className={cn(chatPanelClassName, 'h-full min-h-0 w-full min-w-0')}>{chatContent}</div>\n );\n }\n\n if (isMobile) {\n return (\n <Modal open={isChatOpen} onOpenChange={(open) => !open && closeChat()}>\n <ModalContent\n className=\"border-border-default bg-background-surface flex h-[85dvh] max-h-[85dvh] w-[calc(100vw-32px)] max-w-[calc(100vw-32px)] flex-col gap-0 overflow-hidden rounded-2xl border p-4 pr-1\"\n aria-describedby={undefined}\n >\n <ModalTitle className=\"sr-only\">{t('chat.title')}</ModalTitle>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">{chatContent}</div>\n </ModalContent>\n </Modal>\n );\n }\n\n if (compactPositionClassName) {\n return (\n <div\n className={cn(\n 'border-border-default bg-background-surface fixed z-100 flex min-h-0 w-[328px] flex-col overflow-hidden rounded-2xl border p-4 pr-1 shadow-lg',\n compactPositionClassName,\n )}\n >\n {chatContent}\n </div>\n );\n }\n\n return (\n <div className=\"bg-background-surface border-border-default sm:border-border-default fixed flex h-full min-h-0 w-full max-w-none min-w-[328px] flex-col overflow-hidden rounded-2xl border p-4 pr-1 sm:relative sm:max-w-[328px]\">\n {chatContent}\n </div>\n );\n};\n","import { Button } from '@xipkg/button';\nimport { Chat } from '@xipkg/icons';\nimport { cn } from '@xipkg/utils';\nimport { useChat } from '../hooks/useChat';\nimport { useChatStore } from '../store/chatStore';\n\ntype ChatButtonProps = {\n /** Дополнительные классы (например, для компактной панели: h-8 w-8 rounded-xl) */\n className?: string;\n};\n\nexport const ChatButton = ({ className }: ChatButtonProps) => {\n const { toggleChat } = useChat();\n const { isChatOpen, unreadMessagesCount } = useChatStore();\n\n return (\n <Button\n size=\"icon\"\n variant=\"none\"\n onClick={toggleChat}\n className={cn(\n 'bg-background-surface hover:bg-background-page text-text-primary relative m-0 rounded-xl p-0',\n !className && 'h-10 w-10 min-w-10',\n isChatOpen && 'text-text-link',\n className,\n )}\n data-umami-event=\"call-toggle-chat\"\n data-umami-event-state={isChatOpen ? 'close' : 'open'}\n >\n <Chat className={cn('h-6 w-6', isChatOpen ? 'fill-icon-brand' : 'fill-icon-primary')} />\n {unreadMessagesCount > 0 && (\n <div className=\"bg-action-primary-background-default text-action-primary-text absolute -top-1 -right-1 flex h-5 min-w-5 items-center justify-center rounded-full px-1 text-xs font-medium\">\n {unreadMessagesCount > 99 ? '99+' : unreadMessagesCount}\n </div>\n )}\n </Button>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/editor/sanitizeContent.ts","../src/store/chatStore.ts","../src/hooks/useChat.ts","../src/editor/discordMarks.ts","../src/editor/extensions.ts","../src/editor/proseClassName.ts","../src/ui/ChatBubbleMenu.tsx","../src/ui/ChatComposer.tsx","../src/editor/renderJsonContent.tsx","../src/utils/chat.tsx","../src/ui/ChatMessageContent.tsx","../src/ui/Chat.tsx","../src/ui/ChatButton.tsx"],"names":["sanitized","cn","Bold","UnderlineIcon","useCallback","useEditorState","jsx","jsxs","Button","LINK_CLASS","useTranslation","useRef","useEffect","Chat"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { JSONContent } from '@tiptap/core';\n\nconst ALLOWED_NODES = new Set(['doc', 'paragraph', 'text', 'hardBreak', 'codeBlock', 'blockquote']);\n\nconst ALLOWED_MARKS = new Set(['bold', 'italic', 'strike', 'underline', 'code', 'link']);\n\nconst MAX_NODES = 400;\nconst MAX_TEXT = 8000;\nconst MAX_DEPTH = 16;\nconst MAX_HREF_LENGTH = 2000;\n\nconst isSafeHref = (href: unknown): href is string => {\n if (typeof href !== 'string' || href.length === 0 || href.length > MAX_HREF_LENGTH) {\n return false;\n }\n\n try {\n const url = new URL(href);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n};\n\nexport const sanitizeChatContent = (input: unknown): JSONContent | undefined => {\n if (!input || typeof input !== 'object') return undefined;\n\n let nodeCount = 0;\n let textLength = 0;\n\n const walk = (node: unknown, depth: number): JSONContent | null => {\n if (nodeCount > MAX_NODES || textLength > MAX_TEXT || depth > MAX_DEPTH) return null;\n if (!node || typeof node !== 'object') return null;\n\n const raw = node as JSONContent;\n if (typeof raw.type !== 'string' || !ALLOWED_NODES.has(raw.type)) return null;\n\n nodeCount += 1;\n const result: JSONContent = { type: raw.type };\n\n if (raw.type === 'text') {\n if (typeof raw.text !== 'string') return null;\n textLength += raw.text.length;\n result.text = raw.text;\n }\n\n if (raw.type === 'codeBlock' && raw.attrs && typeof raw.attrs.language === 'string') {\n result.attrs = { language: raw.attrs.language.slice(0, 32) };\n }\n\n if (Array.isArray(raw.marks) && raw.marks.length > 0) {\n const marks: NonNullable<JSONContent['marks']> = [];\n\n for (const mark of raw.marks) {\n if (!mark || typeof mark !== 'object' || typeof mark.type !== 'string') continue;\n if (!ALLOWED_MARKS.has(mark.type)) continue;\n\n if (mark.type === 'link') {\n const href = mark.attrs?.href;\n if (!isSafeHref(href)) continue;\n marks.push({\n type: 'link',\n attrs: { href, target: '_blank', rel: 'noopener noreferrer' },\n });\n continue;\n }\n\n marks.push({ type: mark.type });\n }\n\n if (marks.length > 0) result.marks = marks;\n }\n\n if (Array.isArray(raw.content)) {\n const content: JSONContent[] = [];\n for (const child of raw.content) {\n const sanitized = walk(child, depth + 1);\n if (sanitized) content.push(sanitized);\n }\n if (content.length > 0) result.content = content;\n }\n\n return result;\n };\n\n const sanitized = walk(input, 0);\n if (!sanitized || sanitized.type !== 'doc') return undefined;\n return sanitized;\n};\n","import { create } from 'zustand';\nimport type { ChatMessageT } from '../types';\n\nexport type { ChatMessageT };\n\nexport type useChatStoreT = {\n isChatOpen: boolean;\n chatMessages: ChatMessageT[];\n unreadMessagesCount: number;\n addChatMessage: (message: ChatMessageT) => void;\n removeChatMessage: (messageId: string) => void;\n clearUnreadMessages: () => void;\n updateStore: (type: keyof useChatStoreT, value: unknown) => void;\n};\n\n// Чат передаётся только через LiveKit DataChannel (P2P/broadcast в рамках текущего звонка),\n// серверной истории сообщений нет. Раньше стор персистился в localStorage без привязки\n// к конкретному звонку — сообщения предыдущего звонка «утекали» в следующий на том же\n// устройстве (и только у того пользователя, у кого localStorage не был очищен штатным\n// disconnect-флоу). Стор намеренно НЕ персистится: чат живёт только в памяти на время\n// звонка и одинаково пуст у всех при входе в новый звонок.\nexport const useChatStore = create<useChatStoreT>()((set, get) => ({\n isChatOpen: false,\n chatMessages: [],\n unreadMessagesCount: 0,\n updateStore: (type: keyof useChatStoreT, value: unknown) => set({ [type]: value }),\n\n addChatMessage: (message: ChatMessageT) => {\n const { isChatOpen, unreadMessagesCount, chatMessages } = get();\n\n // Проверяем, нет ли уже сообщения с таким ID (дедупликация)\n const messageExists = chatMessages.some((msg) => msg.id === message.id);\n if (messageExists) {\n return;\n }\n\n set((state) => ({\n chatMessages: [...state.chatMessages, message],\n unreadMessagesCount: isChatOpen ? unreadMessagesCount : unreadMessagesCount + 1,\n }));\n },\n\n removeChatMessage: (messageId: string) => {\n set((state) => ({\n chatMessages: state.chatMessages.filter((msg) => msg.id !== messageId),\n }));\n },\n\n clearUnreadMessages: () => set({ unreadMessagesCount: 0 }),\n}));\n","import { useCallback } from 'react';\nimport type { JSONContent } from '@tiptap/core';\nimport { useLiveKitDataChannel, useLiveKitDataChannelListener } from '@xipkg/calls-hooks';\nimport { useRoom } from '@xipkg/calls-providers';\nimport { useSoundEffectsStore } from '@xipkg/calls-store';\nimport { playSound } from '@xipkg/calls-utils';\nimport { sanitizeChatContent } from '../editor/sanitizeContent';\nimport { useChatStore } from '../store';\nimport type { ChatMessageT } from '../types';\n\nconst CHAT_MESSAGE_TYPE = 'chat_message';\nconst CHAT_MESSAGE_DELETE_TYPE = 'chat_message_delete';\n\ntype ChatMessagePayload = ChatMessageT;\n\ntype ChatMessageDeletePayload = {\n id: string;\n senderId: string;\n};\n\nexport const useChat = () => {\n const { sendMessage } = useLiveKitDataChannel();\n const { addChatMessage, removeChatMessage, clearUnreadMessages, updateStore } = useChatStore();\n const chatSoundVolume = useSoundEffectsStore((s) => s.chatMessageVolume);\n const { room } = useRoom();\n\n // Получаем информацию о текущем участнике из LiveKit\n const getCurrentParticipantInfo = useCallback(() => {\n if (!room?.localParticipant) {\n return {\n senderId: 'unknown',\n senderName: 'Unknown User',\n };\n }\n\n const participant = room.localParticipant;\n\n try {\n // Парсим метаданные участника\n const metadata = participant.metadata;\n if (metadata) {\n const userInfo = JSON.parse(metadata);\n return {\n senderId: userInfo?.user_id || userInfo?.id || participant.identity,\n senderName:\n userInfo?.display_name ||\n userInfo?.name ||\n userInfo?.username ||\n participant.name ||\n participant.identity,\n };\n }\n } catch (error) {\n console.warn('⚠️ Failed to parse participant metadata:', error);\n }\n\n // Fallback на стандартные поля LiveKit\n return {\n senderId: participant.identity,\n senderName: participant.name || participant.identity,\n };\n }, [room]);\n\n const handleChatMessage = useCallback(\n (message: { type: string; payload: unknown }) => {\n if (message.type === CHAT_MESSAGE_TYPE) {\n const payload = message.payload as ChatMessagePayload;\n\n // Проверяем, что это не наше собственное сообщение\n const currentParticipantInfo = getCurrentParticipantInfo();\n if (payload.senderId === currentParticipantInfo.senderId) {\n return;\n }\n\n addChatMessage({\n ...payload,\n content: sanitizeChatContent(payload.content),\n });\n playSound('chatMessage', chatSoundVolume);\n return;\n }\n\n if (message.type === CHAT_MESSAGE_DELETE_TYPE) {\n const payload = message.payload as ChatMessageDeletePayload;\n if (!payload?.id || !payload?.senderId) return;\n\n // Удаляем только если автор удаления совпадает с автором сообщения —\n // чужой клиент не может удалить чужие сообщения через поддельный payload.\n const existing = useChatStore.getState().chatMessages.find((msg) => msg.id === payload.id);\n if (!existing) return;\n if (String(existing.senderId) !== String(payload.senderId)) return;\n\n removeChatMessage(payload.id);\n }\n },\n [addChatMessage, removeChatMessage, getCurrentParticipantInfo, chatSoundVolume],\n );\n\n // Слушаем сообщения чата\n useLiveKitDataChannelListener(handleChatMessage);\n\n const sendChatMessage = useCallback(\n (text: string, content?: JSONContent) => {\n if (!text.trim()) return;\n\n const participantInfo = getCurrentParticipantInfo();\n const sanitizedContent = sanitizeChatContent(content);\n const message: ChatMessagePayload = {\n id: `${Date.now()}-${Math.random()}`,\n text: text.trim(),\n ...(sanitizedContent ? { content: sanitizedContent } : {}),\n senderId: participantInfo.senderId,\n senderName: participantInfo.senderName,\n timestamp: Date.now(),\n };\n\n // Добавляем сообщение в локальный store отправителя\n addChatMessage(message);\n\n // Отправляем через DataChannel\n sendMessage(CHAT_MESSAGE_TYPE, message);\n },\n [sendMessage, getCurrentParticipantInfo, addChatMessage],\n );\n\n const deleteChatMessage = useCallback(\n (messageId: string) => {\n const existing = useChatStore.getState().chatMessages.find((msg) => msg.id === messageId);\n if (!existing) return;\n\n const participantInfo = getCurrentParticipantInfo();\n if (String(existing.senderId) !== String(participantInfo.senderId)) return;\n\n const payload: ChatMessageDeletePayload = {\n id: messageId,\n senderId: participantInfo.senderId,\n };\n\n // Optimistic: сразу убираем у себя, затем broadcast для остальных\n removeChatMessage(messageId);\n sendMessage(CHAT_MESSAGE_DELETE_TYPE, payload);\n },\n [sendMessage, getCurrentParticipantInfo, removeChatMessage],\n );\n\n const toggleChat = useCallback(() => {\n updateStore('isChatOpen', !useChatStore.getState().isChatOpen);\n clearUnreadMessages();\n }, [updateStore, clearUnreadMessages]);\n\n const openChat = useCallback(() => {\n updateStore('isChatOpen', true);\n clearUnreadMessages();\n }, [updateStore, clearUnreadMessages]);\n\n const closeChat = useCallback(() => {\n updateStore('isChatOpen', false);\n }, [updateStore]);\n\n return {\n sendChatMessage,\n deleteChatMessage,\n toggleChat,\n openChat,\n closeChat,\n };\n};\n","import { markInputRule, markPasteRule } from '@tiptap/core';\nimport { Bold, starInputRegex, starPasteRegex } from '@tiptap/extension-bold';\nimport { Underline } from '@tiptap/extension-underline';\n\n/**\n * Discord: `**жирный**`, `__подчёркнутый__`.\n * Стандартный markdown / StarterKit мапит `__` на bold — переназначаем.\n */\nconst underlineInputRegex = /(?:^|\\s)(__(?!\\s+__)((?:[^_]+))__(?!\\s+__))$/;\nconst underlinePasteRegex = /(?:^|\\s)(__(?!\\s+__)((?:[^_]+))__(?!\\s+__))/g;\n\nexport const DiscordBold = Bold.extend({\n addInputRules() {\n return [\n markInputRule({\n find: starInputRegex,\n type: this.type,\n }),\n ];\n },\n addPasteRules() {\n return [\n markPasteRule({\n find: starPasteRegex,\n type: this.type,\n }),\n ];\n },\n});\n\nexport const DiscordUnderline = Underline.extend({\n addInputRules() {\n return [\n markInputRule({\n find: underlineInputRegex,\n type: this.type,\n }),\n ];\n },\n addPasteRules() {\n return [\n markPasteRule({\n find: underlinePasteRegex,\n type: this.type,\n }),\n ];\n },\n});\n","import StarterKit from '@tiptap/starter-kit';\nimport { DiscordBold, DiscordUnderline } from './discordMarks';\n\nconst LINK_CLASS = 'text-text-link hover:text-text-link cursor-pointer underline';\n\n/** Схема чата: Discord-шорткаты + тот же набор марок, что у текста на доске. */\nexport const chatExtensions = [\n StarterKit.configure({\n bold: false,\n underline: false,\n heading: false,\n horizontalRule: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n listKeymap: false,\n trailingNode: false,\n link: {\n openOnClick: false,\n autolink: true,\n defaultProtocol: 'https',\n HTMLAttributes: {\n target: '_blank',\n rel: 'noopener noreferrer',\n class: LINK_CLASS,\n },\n },\n }),\n DiscordBold,\n DiscordUnderline,\n];\n","import { cn } from '@xipkg/utils';\n\n/**\n * Жирный — 700, не 600: при синтезе начертания (нет файла Inter Bold) 600 почти неотличим от 400.\n */\nconst chatInlineMarksClassName = cn(\n '[&_strong]:font-bold',\n '[&_em]:italic',\n '[&_s]:line-through',\n '[&_u]:underline',\n);\n\n/** Общие стили ProseMirror для композера и пузырьков сообщений. */\nexport const chatProseClassName = cn(\n '[&_.ProseMirror]:min-h-6 [&_.ProseMirror]:text-sm [&_.ProseMirror]:break-words [&_.ProseMirror]:outline-none',\n '[&_.ProseMirror_p]:m-0 [&_.ProseMirror_p+p]:mt-1',\n '[&_.ProseMirror_strong]:font-bold',\n '[&_.ProseMirror_em]:italic',\n '[&_.ProseMirror_s]:line-through',\n '[&_.ProseMirror_u]:underline',\n '[&_.ProseMirror_code]:bg-background-page [&_.ProseMirror_code]:rounded [&_.ProseMirror_code]:px-1 [&_.ProseMirror_code]:py-0.5 [&_.ProseMirror_code]:font-mono [&_.ProseMirror_code]:text-[0.85em]',\n '[&_.ProseMirror_pre]:bg-background-page [&_.ProseMirror_pre]:my-1 [&_.ProseMirror_pre]:overflow-x-auto [&_.ProseMirror_pre]:rounded-lg [&_.ProseMirror_pre]:p-2 [&_.ProseMirror_pre]:font-mono [&_.ProseMirror_pre]:text-xs [&_.ProseMirror_pre]:whitespace-pre-wrap',\n '[&_.ProseMirror_blockquote]:border-border-default [&_.ProseMirror_blockquote]:text-text-secondary [&_.ProseMirror_blockquote]:my-1 [&_.ProseMirror_blockquote]:border-l-2 [&_.ProseMirror_blockquote]:pl-2',\n '[&_.ProseMirror_a]:text-text-link [&_.ProseMirror_a]:cursor-pointer [&_.ProseMirror_a]:underline',\n);\n\nexport const chatMessageProseClassName = cn(\n 'text-sm wrap-break-word',\n '[&_p]:m-0 [&_p+p]:mt-1',\n chatInlineMarksClassName,\n);\n","import type { Editor } from '@tiptap/core';\nimport { TextSelection } from '@tiptap/pm/state';\nimport type { EditorState } from '@tiptap/pm/state';\nimport { BubbleMenu } from '@tiptap/react/menus';\nimport { useEditorState } from '@tiptap/react';\nimport { Bold, Italic, Stroke, Underline as UnderlineIcon } from '@xipkg/icons';\nimport { Button } from '@xipkg/button';\nimport { cn } from '@xipkg/utils';\nimport { useTranslation } from 'react-i18next';\nimport type { ReactNode } from 'react';\n\ntype FormatTypeT = 'bold' | 'italic' | 'underline' | 'strike';\n\ntype ChatBubbleMenuProps = {\n editor: Editor;\n};\n\nconst isValidTextSelection = (state: EditorState): boolean => {\n const { doc, selection } = state;\n if (!(selection instanceof TextSelection) || selection.empty) return false;\n if (selection.from === 0 || selection.to === 0) return false;\n\n try {\n const $from = doc.resolve(selection.from);\n const $to = doc.resolve(selection.to);\n return $from.parent.isTextblock && $to.parent.isTextblock;\n } catch {\n return false;\n }\n};\n\ntype FormatButtonProps = {\n editor: Editor;\n type: FormatTypeT;\n isActive: boolean;\n ariaLabel: string;\n children: ReactNode;\n};\n\nconst FormatButton = ({ editor, type, isActive, ariaLabel, children }: FormatButtonProps) => {\n return (\n <Button\n type=\"button\"\n variant=\"none\"\n aria-label={ariaLabel}\n aria-pressed={isActive}\n className={cn(\n '[&_svg]:fill-icon-primary h-6 w-6 rounded-sm p-1',\n isActive && 'bg-status-info-background [&_svg]:fill-icon-brand',\n )}\n onMouseDown={(event) => {\n event.preventDefault();\n editor.chain().focus().toggleMark(type).run();\n }}\n >\n {children}\n </Button>\n );\n};\n\nexport const ChatBubbleMenu = ({ editor }: ChatBubbleMenuProps) => {\n const { t } = useTranslation('calls');\n const activeStates = useEditorState({\n editor,\n selector: ({ editor: current }) => ({\n bold: current.isActive('bold'),\n italic: current.isActive('italic'),\n underline: current.isActive('underline'),\n strike: current.isActive('strike'),\n }),\n });\n\n return (\n <BubbleMenu\n editor={editor}\n appendTo={() => editor.view.dom.ownerDocument.body}\n shouldShow={({ state }) => isValidTextSelection(state)}\n options={{\n placement: 'top',\n strategy: 'fixed',\n offset: 8,\n }}\n className=\"calls-portaled-overlay border-border-default bg-background-surface z-200 flex gap-1 rounded-lg border p-1 shadow-lg\"\n >\n <FormatButton\n editor={editor}\n type=\"bold\"\n isActive={activeStates.bold}\n ariaLabel={t('chat.formatBold')}\n >\n <Bold />\n </FormatButton>\n <FormatButton\n editor={editor}\n type=\"italic\"\n isActive={activeStates.italic}\n ariaLabel={t('chat.formatItalic')}\n >\n <Italic />\n </FormatButton>\n <FormatButton\n editor={editor}\n type=\"underline\"\n isActive={activeStates.underline}\n ariaLabel={t('chat.formatUnderline')}\n >\n <UnderlineIcon />\n </FormatButton>\n <FormatButton\n editor={editor}\n type=\"strike\"\n isActive={activeStates.strike}\n ariaLabel={t('chat.formatStrike')}\n >\n <Stroke />\n </FormatButton>\n </BubbleMenu>\n );\n};\n","import { useCallback, useEffect, useRef } from 'react';\nimport type { Editor, JSONContent } from '@tiptap/core';\nimport { EditorContent, useEditor, useEditorState } from '@tiptap/react';\nimport { Button } from '@xipkg/button';\nimport { Send } from '@xipkg/icons';\nimport { cn } from '@xipkg/utils';\nimport { chatExtensions } from '../editor/extensions';\nimport { chatProseClassName } from '../editor/proseClassName';\nimport { ChatBubbleMenu } from './ChatBubbleMenu';\n\ntype ChatComposerProps = {\n placeholder: string;\n onSend: (text: string, content: JSONContent) => void;\n};\n\nexport const ChatComposer = ({ placeholder, onSend }: ChatComposerProps) => {\n const onSendRef = useRef(onSend);\n onSendRef.current = onSend;\n\n const editorRef = useRef<Editor | null>(null);\n\n const sendFromEditor = useCallback(() => {\n const current = editorRef.current;\n if (!current || current.isDestroyed) return;\n\n const text = current.getText({ blockSeparator: '\\n' }).trim();\n if (!text) return;\n\n onSendRef.current(text, current.getJSON());\n current.commands.clearContent(true);\n current.commands.focus();\n }, []);\n\n const sendFromEditorRef = useRef(sendFromEditor);\n sendFromEditorRef.current = sendFromEditor;\n\n const editor = useEditor({\n immediatelyRender: false,\n extensions: chatExtensions,\n autofocus: true,\n editorProps: {\n attributes: {\n class: 'min-h-6 text-sm break-words outline-none',\n 'aria-label': placeholder,\n },\n handleKeyDown: (_view, event) => {\n if (\n event.key !== 'Enter' ||\n event.shiftKey ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey\n ) {\n return false;\n }\n if (event.isComposing || event.keyCode === 229) return false;\n\n event.preventDefault();\n sendFromEditorRef.current();\n return true;\n },\n },\n });\n\n useEffect(() => {\n editorRef.current = editor;\n }, [editor]);\n\n const isEmpty =\n useEditorState({\n editor,\n selector: ({ editor: current }) => !current?.getText({ blockSeparator: '\\n' }).trim(),\n }) ?? true;\n\n return (\n <div className=\"flex shrink-0 items-end gap-2 pr-3\">\n <div\n className={cn(\n 'border-border-default flex max-h-40 w-full flex-1 items-center rounded-xl border pl-4',\n chatProseClassName,\n )}\n >\n <div className=\"relative min-w-0 flex-1\">\n {isEmpty && (\n <span className=\"text-text-secondary pointer-events-none absolute top-3 left-0 text-sm\">\n {placeholder}\n </span>\n )}\n <EditorContent editor={editor} className=\"my-3 max-h-32 overflow-y-auto pr-2\" />\n {editor && <ChatBubbleMenu editor={editor} />}\n </div>\n <div className=\"pr-1\">\n <Button\n size=\"icon\"\n variant=\"primary\"\n onClick={sendFromEditor}\n disabled={isEmpty}\n className=\"rounded-xl p-2\"\n >\n <Send\n className={cn(\n 'fill-action-primary-text group-hover:fill-action-primary-text h-6 w-6',\n isEmpty && 'fill-icon-secondary',\n )}\n />\n </Button>\n </div>\n </div>\n </div>\n );\n};\n","import type { JSONContent } from '@tiptap/core';\nimport type { ReactNode } from 'react';\n\nconst LINK_CLASS = 'text-text-link hover:text-text-link cursor-pointer underline';\n\nconst wrapMarks = (text: string, marks: JSONContent['marks']): ReactNode => {\n return (marks ?? []).reduce<ReactNode>((acc, mark) => {\n switch (mark.type) {\n case 'bold':\n return <strong className=\"font-bold\">{acc}</strong>;\n case 'italic':\n return <em className=\"italic\">{acc}</em>;\n case 'strike':\n return <s>{acc}</s>;\n case 'underline':\n return <u>{acc}</u>;\n case 'code':\n return (\n <code className=\"bg-background-page rounded px-1 py-0.5 font-mono text-[0.85em]\">\n {acc}\n </code>\n );\n case 'link': {\n const href = typeof mark.attrs?.href === 'string' ? mark.attrs.href : undefined;\n if (!href) return acc;\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={LINK_CLASS}\n onClick={(event) => event.stopPropagation()}\n data-umami-event=\"outbound-link-click\"\n data-umami-event-url={href}\n data-umami-event-source=\"chat\"\n >\n {acc}\n </a>\n );\n }\n default:\n return acc;\n }\n }, text);\n};\n\nconst renderNode = (node: JSONContent, key: string): ReactNode => {\n const children = node.content?.map((child, index) => renderNode(child, `${key}-${index}`));\n\n switch (node.type) {\n case 'doc':\n return children;\n case 'paragraph':\n return (\n <p key={key} className=\"m-0 min-h-[1em]\">\n {children ?? <br />}\n </p>\n );\n case 'blockquote':\n return (\n <blockquote\n key={key}\n className=\"border-border-default text-text-secondary my-1 border-l-2 pl-2\"\n >\n {children}\n </blockquote>\n );\n case 'codeBlock':\n return (\n <pre\n key={key}\n className=\"bg-background-page my-1 overflow-x-auto rounded-lg p-2 font-mono text-xs whitespace-pre-wrap\"\n >\n <code>{children}</code>\n </pre>\n );\n case 'hardBreak':\n return <br key={key} />;\n case 'text':\n return <span key={key}>{wrapMarks(node.text ?? '', node.marks)}</span>;\n default:\n return children;\n }\n};\n\nexport const renderChatJsonContent = (content: JSONContent): ReactNode => {\n return renderNode(content, 'chat-doc');\n};\n","export const parseLinks = (message: string) => {\n const urlRegex = /(https?:\\/\\/[^\\s]+)/g;\n const messageParts = message.split(urlRegex);\n\n return messageParts.map((messagePart, index) => {\n if (urlRegex.test(messagePart)) {\n return (\n <a\n key={index}\n href={messagePart}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-text-link hover:text-text-link cursor-pointer underline\"\n onClick={(e) => e.stopPropagation()}\n data-umami-event=\"outbound-link-click\"\n data-umami-event-url={messagePart}\n data-umami-event-source=\"chat\"\n >\n {messagePart}\n </a>\n );\n }\n\n return messagePart;\n });\n};\n","import type { JSONContent } from '@tiptap/core';\nimport { cn } from '@xipkg/utils';\nimport { renderChatJsonContent } from '../editor/renderJsonContent';\nimport { chatMessageProseClassName } from '../editor/proseClassName';\nimport { parseLinks } from '../utils/chat';\n\ntype ChatMessageContentProps = {\n text: string;\n content?: JSONContent;\n className?: string;\n};\n\nexport const ChatMessageContent = ({ text, content, className }: ChatMessageContentProps) => {\n return (\n <div className={cn(chatMessageProseClassName, className)}>\n {content ? renderChatJsonContent(content) : parseLinks(text)}\n </div>\n );\n};\n","import { useRef, useEffect, type CSSProperties } from 'react';\nimport type { JSONContent } from '@tiptap/core';\nimport { Button } from '@xipkg/button';\nimport { Close, Trash } from '@xipkg/icons';\nimport { UserProfile } from '@xipkg/userprofile';\nimport { ScrollArea } from '@xipkg/scrollarea';\nimport { Modal, ModalContent, ModalTitle } from '@xipkg/modal';\nimport { useTranslation } from 'react-i18next';\nimport { useChat } from '../hooks';\nimport { useCalls } from '@xipkg/calls-providers';\nimport { useChatStore } from '../store';\nimport { cn, useMediaQuery } from '@xipkg/utils';\nimport { ChatComposer } from './ChatComposer';\nimport { ChatMessageContent } from './ChatMessageContent';\n\ntype ChatProps = {\n /** В компакт-режиме: классы позиционирования (как у CompactCall: top-16 bottom-4 left-4 и т.д.) */\n compactPositionClassName?: string;\n /** В компакт-режиме: отступы от краёв. Нужны, когда тулбар доски занимает не только низ. */\n compactPositionStyle?: CSSProperties;\n /** Встроить чат в родителя (PiP): без fixed/modal, на всю доступную высоту */\n embedded?: boolean;\n};\n\nexport const Chat = ({\n compactPositionClassName,\n compactPositionStyle,\n embedded = false,\n}: ChatProps = {}) => {\n const { t, i18n } = useTranslation('calls');\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const { sendChatMessage, deleteChatMessage, closeChat } = useChat();\n const { chatMessages, isChatOpen } = useChatStore();\n const { data: currentUser } = useCalls().auth.useCurrentUser();\n const timeLocale = i18n.language?.startsWith('ru')\n ? 'ru-RU'\n : i18n.language?.startsWith('en')\n ? 'en-US'\n : i18n.language;\n\n const scrollToBottom = (behavior: ScrollBehavior = 'smooth') => {\n messagesEndRef.current?.scrollIntoView({ behavior });\n };\n\n useEffect(() => {\n if (isChatOpen) {\n requestAnimationFrame(() => {\n scrollToBottom('auto');\n });\n }\n }, [isChatOpen]);\n\n // Автоматическая прокрутка при получении новых сообщений\n useEffect(() => {\n if (isChatOpen && chatMessages.length > 0) {\n requestAnimationFrame(() => {\n scrollToBottom('smooth');\n });\n }\n }, [chatMessages.length, isChatOpen]);\n\n const handleSendMessage = (text: string, content?: JSONContent) => {\n sendChatMessage(text, content);\n requestAnimationFrame(() => {\n scrollToBottom('smooth');\n });\n };\n\n const isMobile = useMediaQuery('(max-width: 639px)');\n if (!isChatOpen) return null;\n\n const chatPanelClassName =\n 'border-border-default bg-background-surface flex min-h-0 flex-col overflow-hidden rounded-2xl border p-4 pr-1';\n\n const chatContent = (\n <>\n {/* Заголовок */}\n <div className=\"border-border-default flex shrink-0 items-center justify-between pr-3\">\n <h3 className=\"text-text-primary text-lg font-medium\">{t('chat.title')}</h3>\n <Button size=\"icon\" variant=\"none\" onClick={closeChat}>\n <Close className=\"h-6 w-6\" aria-label={t('chat.close')} />\n </Button>\n </div>\n\n {/* Сообщения */}\n <ScrollArea className=\"h-full min-h-0 flex-1 py-2 pr-3\">\n <div className=\"space-y-4\">\n {chatMessages.length === 0 ? (\n <div className=\"text-text-secondary text-center\">\n <p>{t('chat.empty')}</p>\n </div>\n ) : (\n chatMessages.map((message) => {\n const isOwnMessage = Number(message.senderId) === Number(currentUser?.id);\n return (\n <div\n key={message.id}\n className={`group flex ${isOwnMessage ? 'justify-end' : 'justify-start'}`}\n >\n <div className=\"text-text-primary flex max-w-[90%] flex-col gap-1 rounded-lg select-text\">\n <div className=\"text-text-primary flex flex-row items-center gap-1 text-xs font-medium\">\n {!isOwnMessage && (\n <UserProfile\n size=\"s\"\n userId={Number(message.senderId)}\n text={message.senderName}\n src={`https://api.sovlium.ru/files/users/${message.senderId}/avatar.webp`}\n />\n )}\n <div\n className={`text-xs-base ${isOwnMessage ? 'text-text-disabled ml-auto' : 'text-text-secondary'}`}\n >\n {new Date(message.timestamp).toLocaleTimeString(timeLocale, {\n hour: '2-digit',\n minute: '2-digit',\n })}\n </div>\n </div>\n <div className=\"relative\">\n <ChatMessageContent\n text={message.text}\n content={message.content}\n className={cn(\n 'cursor-text rounded-lg px-3 py-2 select-text',\n isOwnMessage\n ? 'bg-action-primary-background-disabled'\n : 'bg-background-page',\n )}\n />\n {isOwnMessage && (\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"none\"\n className=\"bg-background-surface border-border-default absolute -top-2 -left-2 h-7 w-7 rounded-full border p-1 opacity-100 shadow-sm sm:opacity-0 sm:group-focus-within:opacity-100 sm:group-hover:opacity-100\"\n onClick={() => deleteChatMessage(message.id)}\n aria-label={t('chat.deleteAria')}\n >\n <Trash className=\"fill-icon-secondary h-4 w-4\" />\n </Button>\n )}\n </div>\n </div>\n </div>\n );\n })\n )}\n <div ref={messagesEndRef} />\n </div>\n </ScrollArea>\n\n <ChatComposer placeholder={t('chat.placeholder')} onSend={handleSendMessage} />\n </>\n );\n\n if (embedded) {\n return (\n <div className={cn(chatPanelClassName, 'h-full min-h-0 w-full min-w-0')}>{chatContent}</div>\n );\n }\n\n if (isMobile) {\n return (\n <Modal open={isChatOpen} onOpenChange={(open) => !open && closeChat()}>\n <ModalContent\n className=\"border-border-default bg-background-surface flex h-[85dvh] max-h-[85dvh] w-[calc(100vw-32px)] max-w-[calc(100vw-32px)] flex-col gap-0 overflow-hidden rounded-2xl border p-4 pr-1\"\n aria-describedby={undefined}\n >\n <ModalTitle className=\"sr-only\">{t('chat.title')}</ModalTitle>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">{chatContent}</div>\n </ModalContent>\n </Modal>\n );\n }\n\n if (compactPositionClassName || compactPositionStyle) {\n return (\n <div\n className={cn(\n 'border-border-default bg-background-surface fixed z-20 flex min-h-0 w-[328px] flex-col overflow-hidden rounded-2xl border p-4 pr-1 shadow-lg',\n compactPositionClassName,\n )}\n style={compactPositionStyle}\n >\n {chatContent}\n </div>\n );\n }\n\n return (\n <div className=\"bg-background-surface border-border-default sm:border-border-default fixed flex h-full min-h-0 w-full max-w-none min-w-[328px] flex-col overflow-hidden rounded-2xl border p-4 pr-1 sm:relative sm:max-w-[328px]\">\n {chatContent}\n </div>\n );\n};\n","import { Button } from '@xipkg/button';\nimport { Chat } from '@xipkg/icons';\nimport { cn } from '@xipkg/utils';\nimport { useChat } from '../hooks/useChat';\nimport { useChatStore } from '../store/chatStore';\n\ntype ChatButtonProps = {\n /** Дополнительные классы (например, для компактной панели: h-8 w-8 rounded-xl) */\n className?: string;\n};\n\nexport const ChatButton = ({ className }: ChatButtonProps) => {\n const { toggleChat } = useChat();\n const { isChatOpen, unreadMessagesCount } = useChatStore();\n\n return (\n <Button\n size=\"icon\"\n variant=\"none\"\n onClick={toggleChat}\n className={cn(\n 'bg-background-surface hover:bg-background-page text-text-primary relative m-0 rounded-xl p-0',\n !className && 'h-10 w-10 min-w-10',\n isChatOpen && 'text-text-link',\n className,\n )}\n data-umami-event=\"call-toggle-chat\"\n data-umami-event-state={isChatOpen ? 'close' : 'open'}\n >\n <Chat className={cn('h-6 w-6', isChatOpen ? 'fill-icon-brand' : 'fill-icon-primary')} />\n {unreadMessagesCount > 0 && (\n <div className=\"bg-action-primary-background-default text-action-primary-text absolute -top-1 -right-1 flex h-5 min-w-5 items-center justify-center rounded-full px-1 text-xs font-medium\">\n {unreadMessagesCount > 99 ? '99+' : unreadMessagesCount}\n </div>\n )}\n </Button>\n );\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xipkg/calls-chat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.55",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
"@tiptap/react": "3.30.1",
|
|
21
21
|
"@tiptap/starter-kit": "3.30.1",
|
|
22
22
|
"@xipkg/button": "4.3.0",
|
|
23
|
-
"@xipkg/calls-config": "^0.1.
|
|
24
|
-
"@xipkg/calls-hooks": "^0.1.
|
|
25
|
-
"@xipkg/calls-providers": "^0.1.
|
|
26
|
-
"@xipkg/calls-store": "^0.1.
|
|
27
|
-
"@xipkg/calls-types": "^0.1.
|
|
28
|
-
"@xipkg/calls-ui": "^0.1.
|
|
29
|
-
"@xipkg/calls-utils": "^0.1.
|
|
23
|
+
"@xipkg/calls-config": "^0.1.55",
|
|
24
|
+
"@xipkg/calls-hooks": "^0.1.55",
|
|
25
|
+
"@xipkg/calls-providers": "^0.1.55",
|
|
26
|
+
"@xipkg/calls-store": "^0.1.55",
|
|
27
|
+
"@xipkg/calls-types": "^0.1.55",
|
|
28
|
+
"@xipkg/calls-ui": "^0.1.55",
|
|
29
|
+
"@xipkg/calls-utils": "^0.1.55",
|
|
30
30
|
"@xipkg/icons": "^3.1.9",
|
|
31
31
|
"@xipkg/modal": "4.6.0",
|
|
32
32
|
"@xipkg/scrollarea": "2.3.0",
|