@xipkg/calls-chat 0.1.25 → 0.1.26

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.mjs CHANGED
@@ -293,11 +293,17 @@ var chatExtensions = [
293
293
  DiscordBold,
294
294
  DiscordUnderline
295
295
  ];
296
+ var chatInlineMarksClassName = cn(
297
+ "[&_strong]:font-bold",
298
+ "[&_em]:italic [&_em]:pr-[0.18em]",
299
+ "[&_s]:line-through",
300
+ "[&_u]:underline"
301
+ );
296
302
  var chatProseClassName = cn(
297
303
  "[&_.ProseMirror]:min-h-6 [&_.ProseMirror]:text-sm [&_.ProseMirror]:break-words [&_.ProseMirror]:outline-none",
298
304
  "[&_.ProseMirror_p]:m-0 [&_.ProseMirror_p+p]:mt-1",
299
- "[&_.ProseMirror_strong]:font-semibold",
300
- "[&_.ProseMirror_em]:italic",
305
+ "[&_.ProseMirror_strong]:font-bold",
306
+ "[&_.ProseMirror_em]:italic [&_.ProseMirror_em]:pr-[0.18em]",
301
307
  "[&_.ProseMirror_s]:line-through",
302
308
  "[&_.ProseMirror_u]:underline",
303
309
  "[&_.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]",
@@ -308,10 +314,7 @@ var chatProseClassName = cn(
308
314
  var chatMessageProseClassName = cn(
309
315
  "text-sm wrap-break-word",
310
316
  "[&_p]:m-0 [&_p+p]:mt-1",
311
- "[&_strong]:font-semibold",
312
- "[&_em]:italic",
313
- "[&_s]:line-through",
314
- "[&_u]:underline"
317
+ chatInlineMarksClassName
315
318
  );
316
319
  var isValidTextSelection = (state) => {
317
320
  const { doc, selection } = state;
@@ -455,7 +458,7 @@ var ChatComposer = ({ placeholder, onSend }) => {
455
458
  editor,
456
459
  selector: ({ editor: current }) => !current?.getText({ blockSeparator: "\n" }).trim()
457
460
  }) ?? true;
458
- return /* @__PURE__ */ jsx("div", { className: "flex items-end gap-2 pr-3", children: /* @__PURE__ */ jsxs(
461
+ return /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-end gap-2 pr-3", children: /* @__PURE__ */ jsxs(
459
462
  "div",
460
463
  {
461
464
  className: cn(
@@ -496,9 +499,9 @@ var wrapMarks = (text, marks) => {
496
499
  return (marks ?? []).reduce((acc, mark) => {
497
500
  switch (mark.type) {
498
501
  case "bold":
499
- return /* @__PURE__ */ jsx("strong", { children: acc });
502
+ return /* @__PURE__ */ jsx("strong", { className: "font-bold", children: acc });
500
503
  case "italic":
501
- return /* @__PURE__ */ jsx("em", { children: acc });
504
+ return /* @__PURE__ */ jsx("em", { className: "pr-[0.18em] italic", children: acc });
502
505
  case "strike":
503
506
  return /* @__PURE__ */ jsx("s", { children: acc });
504
507
  case "underline":
@@ -625,11 +628,11 @@ var Chat = ({ compactPositionClassName, embedded = false } = {}) => {
625
628
  if (!isChatOpen) return null;
626
629
  const chatPanelClassName = "border-border-default bg-background-surface flex min-h-0 flex-col overflow-hidden rounded-2xl border p-4 pr-1";
627
630
  const chatContent = /* @__PURE__ */ jsxs(Fragment, { children: [
628
- /* @__PURE__ */ jsxs("div", { className: "border-border-default flex items-center justify-between pr-3", children: [
631
+ /* @__PURE__ */ jsxs("div", { className: "border-border-default flex shrink-0 items-center justify-between pr-3", children: [
629
632
  /* @__PURE__ */ jsx("h3", { className: "text-text-primary text-lg font-medium", children: t("chat.title") }),
630
633
  /* @__PURE__ */ jsx(Button, { size: "icon", variant: "none", onClick: closeChat, children: /* @__PURE__ */ jsx(Close, { className: "h-6 w-6", "aria-label": t("chat.close") }) })
631
634
  ] }),
632
- /* @__PURE__ */ jsx(ScrollArea, { className: "min-h-0 flex-1 py-2 pr-3", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
635
+ /* @__PURE__ */ jsx(ScrollArea, { className: "h-full min-h-0 flex-1 py-2 pr-3", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
633
636
  chatMessages.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-text-secondary text-center", children: /* @__PURE__ */ jsx("p", { children: t("chat.empty") }) }) : chatMessages.map((message) => {
634
637
  const isOwnMessage = Number(message.senderId) === Number(currentUser?.id);
635
638
  return /* @__PURE__ */ jsx(
@@ -693,7 +696,7 @@ var Chat = ({ compactPositionClassName, embedded = false } = {}) => {
693
696
  /* @__PURE__ */ jsx(ChatComposer, { placeholder: t("chat.placeholder"), onSend: handleSendMessage })
694
697
  ] });
695
698
  if (embedded) {
696
- return /* @__PURE__ */ jsx("div", { className: cn(chatPanelClassName, "h-full w-full"), children: chatContent });
699
+ return /* @__PURE__ */ jsx("div", { className: cn(chatPanelClassName, "h-full min-h-0 w-full"), children: chatContent });
697
700
  }
698
701
  if (isMobile) {
699
702
  return /* @__PURE__ */ jsx(Modal, { open: isChatOpen, onOpenChange: (open) => !open && closeChat(), children: /* @__PURE__ */ jsxs(
@@ -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/** Общие стили 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-semibold',\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 '[&_strong]:font-semibold',\n '[&_em]:italic',\n '[&_s]:line-through',\n '[&_u]:underline',\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 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>{acc}</strong>;\n case 'italic':\n return <em>{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 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=\"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 <div className={cn(chatPanelClassName, 'h-full w-full')}>{chatContent}</div>;\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":";;;;;;;;;;;;;;;;;;;;;;;;;AAEA,IAAM,aAAA,mBAAgB,IAAI,GAAA,CAAI,CAAC,KAAA,EAAO,aAAa,MAAA,EAAQ,WAAA,EAAa,WAAA,EAAa,YAAY,CAAC,CAAA;AAElG,IAAM,aAAA,mBAAgB,IAAI,GAAA,CAAI,CAAC,MAAA,EAAQ,UAAU,QAAA,EAAU,WAAA,EAAa,MAAA,EAAQ,MAAM,CAAC,CAAA;AAEvF,IAAM,SAAA,GAAY,GAAA;AAClB,IAAM,QAAA,GAAW,GAAA;AACjB,IAAM,SAAA,GAAY,EAAA;AAClB,IAAM,eAAA,GAAkB,GAAA;AAExB,IAAM,UAAA,GAAa,CAAC,IAAA,KAAkC;AACpD,EAAA,IAAI,OAAO,SAAS,QAAA,IAAY,IAAA,CAAK,WAAW,CAAA,IAAK,IAAA,CAAK,SAAS,eAAA,EAAiB;AAClF,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAI,CAAA;AACxB,IAAA,OAAO,GAAA,CAAI,QAAA,KAAa,OAAA,IAAW,GAAA,CAAI,QAAA,KAAa,QAAA;AAAA,EACtD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF,CAAA;AAEO,IAAM,mBAAA,GAAsB,CAAC,KAAA,KAA4C;AAC9E,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,OAAO,MAAA;AAEhD,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,IAAI,UAAA,GAAa,CAAA;AAEjB,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,EAAe,KAAA,KAAsC;AACjE,IAAA,IAAI,YAAY,SAAA,IAAa,UAAA,GAAa,QAAA,IAAY,KAAA,GAAQ,WAAW,OAAO,IAAA;AAChF,IAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,IAAA;AAE9C,IAAA,MAAM,GAAA,GAAM,IAAA;AACZ,IAAA,IAAI,OAAO,GAAA,CAAI,IAAA,KAAS,QAAA,IAAY,CAAC,cAAc,GAAA,CAAI,GAAA,CAAI,IAAI,CAAA,EAAG,OAAO,IAAA;AAEzE,IAAA,SAAA,IAAa,CAAA;AACb,IAAA,MAAM,MAAA,GAAsB,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAK;AAE7C,IAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AACvB,MAAA,IAAI,OAAO,GAAA,CAAI,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AACzC,MAAA,UAAA,IAAc,IAAI,IAAA,CAAK,MAAA;AACvB,MAAA,MAAA,CAAO,OAAO,GAAA,CAAI,IAAA;AAAA,IACpB;AAEA,IAAA,IAAI,GAAA,CAAI,SAAS,WAAA,IAAe,GAAA,CAAI,SAAS,OAAO,GAAA,CAAI,KAAA,CAAM,QAAA,KAAa,QAAA,EAAU;AACnF,MAAA,MAAA,CAAO,KAAA,GAAQ,EAAE,QAAA,EAAU,GAAA,CAAI,MAAM,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,EAAE;AAAA,IAC7D;AAEA,IAAA,IAAI,KAAA,CAAM,QAAQ,GAAA,CAAI,KAAK,KAAK,GAAA,CAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpD,MAAA,MAAM,QAA2C,EAAC;AAElD,MAAA,KAAA,MAAW,IAAA,IAAQ,IAAI,KAAA,EAAO;AAC5B,QAAA,IAAI,CAAC,QAAQ,OAAO,IAAA,KAAS,YAAY,OAAO,IAAA,CAAK,SAAS,QAAA,EAAU;AACxE,QAAA,IAAI,CAAC,aAAA,CAAc,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG;AAEnC,QAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACxB,UAAA,MAAM,IAAA,GAAO,KAAK,KAAA,EAAO,IAAA;AACzB,UAAA,IAAI,CAAC,UAAA,CAAW,IAAI,CAAA,EAAG;AACvB,UAAA,KAAA,CAAM,IAAA,CAAK;AAAA,YACT,IAAA,EAAM,MAAA;AAAA,YACN,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAA,EAAU,KAAK,qBAAA;AAAsB,WAC7D,CAAA;AACD,UAAA;AAAA,QACF;AAEA,QAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AAAA,MAChC;AAEA,MAAA,IAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,MAAA,CAAO,KAAA,GAAQ,KAAA;AAAA,IACvC;AAEA,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA,EAAG;AAC9B,MAAA,MAAM,UAAyB,EAAC;AAChC,MAAA,KAAA,MAAW,KAAA,IAAS,IAAI,OAAA,EAAS;AAC/B,QAAA,MAAMA,UAAAA,GAAY,IAAA,CAAK,KAAA,EAAO,KAAA,GAAQ,CAAC,CAAA;AACvC,QAAA,IAAIA,UAAAA,EAAW,OAAA,CAAQ,IAAA,CAAKA,UAAS,CAAA;AAAA,MACvC;AACA,MAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG,MAAA,CAAO,OAAA,GAAU,OAAA;AAAA,IAC3C;AAEA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,EAAO,CAAC,CAAA;AAC/B,EAAA,IAAI,CAAC,SAAA,IAAa,SAAA,CAAU,IAAA,KAAS,OAAO,OAAO,MAAA;AACnD,EAAA,OAAO,SAAA;AACT,CAAA;ACnEO,IAAM,YAAA,GAAe,MAAA,EAAsB,CAAE,CAAC,KAAK,GAAA,MAAS;AAAA,EACjE,UAAA,EAAY,KAAA;AAAA,EACZ,cAAc,EAAC;AAAA,EACf,mBAAA,EAAqB,CAAA;AAAA,EACrB,WAAA,EAAa,CAAC,IAAA,EAA2B,KAAA,KAAmB,GAAA,CAAI,EAAE,CAAC,IAAI,GAAG,KAAA,EAAO,CAAA;AAAA,EAEjF,cAAA,EAAgB,CAAC,OAAA,KAA0B;AACzC,IAAA,MAAM,EAAE,UAAA,EAAY,mBAAA,EAAqB,YAAA,KAAiB,GAAA,EAAI;AAG9D,IAAA,MAAM,aAAA,GAAgB,aAAa,IAAA,CAAK,CAAC,QAAQ,GAAA,CAAI,EAAA,KAAO,QAAQ,EAAE,CAAA;AACtE,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,MACd,YAAA,EAAc,CAAC,GAAG,KAAA,CAAM,cAAc,OAAO,CAAA;AAAA,MAC7C,mBAAA,EAAqB,UAAA,GAAa,mBAAA,GAAsB,mBAAA,GAAsB;AAAA,KAChF,CAAE,CAAA;AAAA,EACJ,CAAA;AAAA,EAEA,iBAAA,EAAmB,CAAC,SAAA,KAAsB;AACxC,IAAA,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,MACd,YAAA,EAAc,MAAM,YAAA,CAAa,MAAA,CAAO,CAAC,GAAA,KAAQ,GAAA,CAAI,OAAO,SAAS;AAAA,KACvE,CAAE,CAAA;AAAA,EACJ,CAAA;AAAA,EAEA,qBAAqB,MAAM,GAAA,CAAI,EAAE,mBAAA,EAAqB,GAAG;AAC3D,CAAA,CAAE;;;ACvCF,IAAM,iBAAA,GAAoB,cAAA;AAC1B,IAAM,wBAAA,GAA2B,qBAAA;AAS1B,IAAM,UAAU,MAAM;AAC3B,EAAA,MAAM,EAAE,WAAA,EAAY,GAAI,qBAAA,EAAsB;AAC9C,EAAA,MAAM,EAAE,cAAA,EAAgB,iBAAA,EAAmB,mBAAA,EAAqB,WAAA,KAAgB,YAAA,EAAa;AAC7F,EAAA,MAAM,eAAA,GAAkB,oBAAA,CAAqB,CAAC,CAAA,KAAM,EAAE,iBAAiB,CAAA;AACvE,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,OAAA,EAAQ;AAGzB,EAAA,MAAM,yBAAA,GAA4B,YAAY,MAAM;AAClD,IAAA,IAAI,CAAC,MAAM,gBAAA,EAAkB;AAC3B,MAAA,OAAO;AAAA,QACL,QAAA,EAAU,SAAA;AAAA,QACV,UAAA,EAAY;AAAA,OACd;AAAA,IACF;AAEA,IAAA,MAAM,cAAc,IAAA,CAAK,gBAAA;AAEzB,IAAA,IAAI;AAEF,MAAA,MAAM,WAAW,WAAA,CAAY,QAAA;AAC7B,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AACpC,QAAA,OAAO;AAAA,UACL,QAAA,EAAU,QAAA,EAAU,OAAA,IAAW,QAAA,EAAU,MAAM,WAAA,CAAY,QAAA;AAAA,UAC3D,UAAA,EACE,UAAU,YAAA,IACV,QAAA,EAAU,QACV,QAAA,EAAU,QAAA,IACV,WAAA,CAAY,IAAA,IACZ,WAAA,CAAY;AAAA,SAChB;AAAA,MACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAA,CAAK,sDAA4C,KAAK,CAAA;AAAA,IAChE;AAGA,IAAA,OAAO;AAAA,MACL,UAAU,WAAA,CAAY,QAAA;AAAA,MACtB,UAAA,EAAY,WAAA,CAAY,IAAA,IAAQ,WAAA,CAAY;AAAA,KAC9C;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,iBAAA,GAAoB,WAAA;AAAA,IACxB,CAAC,OAAA,KAAgD;AAC/C,MAAA,IAAI,OAAA,CAAQ,SAAS,iBAAA,EAAmB;AACtC,QAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AAGxB,QAAA,MAAM,yBAAyB,yBAAA,EAA0B;AACzD,QAAA,IAAI,OAAA,CAAQ,QAAA,KAAa,sBAAA,CAAuB,QAAA,EAAU;AACxD,UAAA;AAAA,QACF;AAEA,QAAA,cAAA,CAAe;AAAA,UACb,GAAG,OAAA;AAAA,UACH,OAAA,EAAS,mBAAA,CAAoB,OAAA,CAAQ,OAAO;AAAA,SAC7C,CAAA;AACD,QAAA,SAAA,CAAU,eAAe,eAAe,CAAA;AACxC,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,CAAQ,SAAS,wBAAA,EAA0B;AAC7C,QAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AACxB,QAAA,IAAI,CAAC,OAAA,EAAS,EAAA,IAAM,CAAC,SAAS,QAAA,EAAU;AAIxC,QAAA,MAAM,QAAA,GAAW,YAAA,CAAa,QAAA,EAAS,CAAE,YAAA,CAAa,IAAA,CAAK,CAAC,GAAA,KAAQ,GAAA,CAAI,EAAA,KAAO,OAAA,CAAQ,EAAE,CAAA;AACzF,QAAA,IAAI,CAAC,QAAA,EAAU;AACf,QAAA,IAAI,OAAO,QAAA,CAAS,QAAQ,MAAM,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAA,EAAG;AAE5D,QAAA,iBAAA,CAAkB,QAAQ,EAAE,CAAA;AAAA,MAC9B;AAAA,IACF,CAAA;AAAA,IACA,CAAC,cAAA,EAAgB,iBAAA,EAAmB,yBAAA,EAA2B,eAAe;AAAA,GAChF;AAGA,EAAA,6BAAA,CAA8B,iBAAiB,CAAA;AAE/C,EAAA,MAAM,eAAA,GAAkB,WAAA;AAAA,IACtB,CAAC,MAAc,OAAA,KAA0B;AACvC,MAAA,IAAI,CAAC,IAAA,CAAK,IAAA,EAAK,EAAG;AAElB,MAAA,MAAM,kBAAkB,yBAAA,EAA0B;AAClD,MAAA,MAAM,gBAAA,GAAmB,oBAAoB,OAAO,CAAA;AACpD,MAAA,MAAM,OAAA,GAA8B;AAAA,QAClC,EAAA,EAAI,GAAG,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,IAAA,CAAK,QAAQ,CAAA,CAAA;AAAA,QAClC,IAAA,EAAM,KAAK,IAAA,EAAK;AAAA,QAChB,GAAI,gBAAA,GAAmB,EAAE,OAAA,EAAS,gBAAA,KAAqB,EAAC;AAAA,QACxD,UAAU,eAAA,CAAgB,QAAA;AAAA,QAC1B,YAAY,eAAA,CAAgB,UAAA;AAAA,QAC5B,SAAA,EAAW,KAAK,GAAA;AAAI,OACtB;AAGA,MAAA,cAAA,CAAe,OAAO,CAAA;AAGtB,MAAA,WAAA,CAAY,mBAAmB,OAAO,CAAA;AAAA,IACxC,CAAA;AAAA,IACA,CAAC,WAAA,EAAa,yBAAA,EAA2B,cAAc;AAAA,GACzD;AAEA,EAAA,MAAM,iBAAA,GAAoB,WAAA;AAAA,IACxB,CAAC,SAAA,KAAsB;AACrB,MAAA,MAAM,QAAA,GAAW,YAAA,CAAa,QAAA,EAAS,CAAE,YAAA,CAAa,KAAK,CAAC,GAAA,KAAQ,GAAA,CAAI,EAAA,KAAO,SAAS,CAAA;AACxF,MAAA,IAAI,CAAC,QAAA,EAAU;AAEf,MAAA,MAAM,kBAAkB,yBAAA,EAA0B;AAClD,MAAA,IAAI,OAAO,QAAA,CAAS,QAAQ,MAAM,MAAA,CAAO,eAAA,CAAgB,QAAQ,CAAA,EAAG;AAEpE,MAAA,MAAM,OAAA,GAAoC;AAAA,QACxC,EAAA,EAAI,SAAA;AAAA,QACJ,UAAU,eAAA,CAAgB;AAAA,OAC5B;AAGA,MAAA,iBAAA,CAAkB,SAAS,CAAA;AAC3B,MAAA,WAAA,CAAY,0BAA0B,OAAO,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA,CAAC,WAAA,EAAa,yBAAA,EAA2B,iBAAiB;AAAA,GAC5D;AAEA,EAAA,MAAM,UAAA,GAAa,YAAY,MAAM;AACnC,IAAA,WAAA,CAAY,YAAA,EAAc,CAAC,YAAA,CAAa,QAAA,GAAW,UAAU,CAAA;AAC7D,IAAA,mBAAA,EAAoB;AAAA,EACtB,CAAA,EAAG,CAAC,WAAA,EAAa,mBAAmB,CAAC,CAAA;AAErC,EAAA,MAAM,QAAA,GAAW,YAAY,MAAM;AACjC,IAAA,WAAA,CAAY,cAAc,IAAI,CAAA;AAC9B,IAAA,mBAAA,EAAoB;AAAA,EACtB,CAAA,EAAG,CAAC,WAAA,EAAa,mBAAmB,CAAC,CAAA;AAErC,EAAA,MAAM,SAAA,GAAY,YAAY,MAAM;AAClC,IAAA,WAAA,CAAY,cAAc,KAAK,CAAA;AAAA,EACjC,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,iBAAA;AAAA,IACA,UAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF;AACF;AC9JA,IAAM,mBAAA,GAAsB,8CAAA;AAC5B,IAAM,mBAAA,GAAsB,8CAAA;AAErB,IAAM,WAAA,GAAc,KAAK,MAAA,CAAO;AAAA,EACrC,aAAA,GAAgB;AACd,IAAA,OAAO;AAAA,MACL,aAAA,CAAc;AAAA,QACZ,IAAA,EAAM,cAAA;AAAA,QACN,MAAM,IAAA,CAAK;AAAA,OACZ;AAAA,KACH;AAAA,EACF,CAAA;AAAA,EACA,aAAA,GAAgB;AACd,IAAA,OAAO;AAAA,MACL,aAAA,CAAc;AAAA,QACZ,IAAA,EAAM,cAAA;AAAA,QACN,MAAM,IAAA,CAAK;AAAA,OACZ;AAAA,KACH;AAAA,EACF;AACF,CAAC,CAAA;AAEM,IAAM,gBAAA,GAAmB,UAAU,MAAA,CAAO;AAAA,EAC/C,aAAA,GAAgB;AACd,IAAA,OAAO;AAAA,MACL,aAAA,CAAc;AAAA,QACZ,IAAA,EAAM,mBAAA;AAAA,QACN,MAAM,IAAA,CAAK;AAAA,OACZ;AAAA,KACH;AAAA,EACF,CAAA;AAAA,EACA,aAAA,GAAgB;AACd,IAAA,OAAO;AAAA,MACL,aAAA,CAAc;AAAA,QACZ,IAAA,EAAM,mBAAA;AAAA,QACN,MAAM,IAAA,CAAK;AAAA,OACZ;AAAA,KACH;AAAA,EACF;AACF,CAAC,CAAA;;;AC5CD,IAAM,UAAA,GAAa,8DAAA;AAGZ,IAAM,cAAA,GAAiB;AAAA,EAC5B,WAAW,SAAA,CAAU;AAAA,IACnB,IAAA,EAAM,KAAA;AAAA,IACN,SAAA,EAAW,KAAA;AAAA,IACX,OAAA,EAAS,KAAA;AAAA,IACT,cAAA,EAAgB,KAAA;AAAA,IAChB,UAAA,EAAY,KAAA;AAAA,IACZ,WAAA,EAAa,KAAA;AAAA,IACb,QAAA,EAAU,KAAA;AAAA,IACV,UAAA,EAAY,KAAA;AAAA,IACZ,YAAA,EAAc,KAAA;AAAA,IACd,IAAA,EAAM;AAAA,MACJ,WAAA,EAAa,KAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,eAAA,EAAiB,OAAA;AAAA,MACjB,cAAA,EAAgB;AAAA,QACd,MAAA,EAAQ,QAAA;AAAA,QACR,GAAA,EAAK,qBAAA;AAAA,QACL,KAAA,EAAO;AAAA;AACT;AACF,GACD,CAAA;AAAA,EACD,WAAA;AAAA,EACA;AACF,CAAA;ACxBA,IAAM,wBAAA,GAA2B,EAAA;AAAA,EAC/B,sBAAA;AAAA,EACA,kCAAA;AAAA,EACA,oBAAA;AAAA,EACA;AACF,CAAA;AAGO,IAAM,kBAAA,GAAqB,EAAA;AAAA,EAChC,8GAAA;AAAA,EACA,kDAAA;AAAA,EACA,mCAAA;AAAA,EACA,4DAAA;AAAA,EACA,iCAAA;AAAA,EACA,8BAAA;AAAA,EACA,oMAAA;AAAA,EACA,sQAAA;AAAA,EACA,4MAAA;AAAA,EACA;AACF,CAAA;AAEO,IAAM,yBAAA,GAA4B,EAAA;AAAA,EACvC,yBAAA;AAAA,EACA,wBAAA;AAAA,EACA;AACF,CAAA;ACdA,IAAM,oBAAA,GAAuB,CAAC,KAAA,KAAgC;AAC5D,EAAA,MAAM,EAAE,GAAA,EAAK,SAAA,EAAU,GAAI,KAAA;AAC3B,EAAA,IAAI,EAAE,SAAA,YAAqB,aAAA,CAAA,IAAkB,SAAA,CAAU,OAAO,OAAO,KAAA;AACrE,EAAA,IAAI,UAAU,IAAA,KAAS,CAAA,IAAK,SAAA,CAAU,EAAA,KAAO,GAAG,OAAO,KAAA;AAEvD,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,OAAA,CAAQ,SAAA,CAAU,IAAI,CAAA;AACxC,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,OAAA,CAAQ,SAAA,CAAU,EAAE,CAAA;AACpC,IAAA,OAAO,KAAA,CAAM,MAAA,CAAO,WAAA,IAAe,GAAA,CAAI,MAAA,CAAO,WAAA;AAAA,EAChD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF,CAAA;AAUA,IAAM,YAAA,GAAe,CAAC,EAAE,MAAA,EAAQ,MAAM,QAAA,EAAU,SAAA,EAAW,UAAS,KAAyB;AAC3F,EAAA,uBACE,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,OAAA,EAAQ,MAAA;AAAA,MACR,YAAA,EAAY,SAAA;AAAA,MACZ,cAAA,EAAc,QAAA;AAAA,MACd,SAAA,EAAWC,EAAAA;AAAA,QACT,kDAAA;AAAA,QACA,QAAA,IAAY;AAAA,OACd;AAAA,MACA,WAAA,EAAa,CAAC,KAAA,KAAU;AACtB,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,MAAA,CAAO,OAAM,CAAE,KAAA,GAAQ,UAAA,CAAW,IAAI,EAAE,GAAA,EAAI;AAAA,MAC9C,CAAA;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ,CAAA;AAEO,IAAM,cAAA,GAAiB,CAAC,EAAE,MAAA,EAAO,KAA2B;AACjE,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,cAAA,CAAe,OAAO,CAAA;AACpC,EAAA,MAAM,eAAe,cAAA,CAAe;AAAA,IAClC,MAAA;AAAA,IACA,QAAA,EAAU,CAAC,EAAE,MAAA,EAAQ,SAAQ,MAAO;AAAA,MAClC,IAAA,EAAM,OAAA,CAAQ,QAAA,CAAS,MAAM,CAAA;AAAA,MAC7B,MAAA,EAAQ,OAAA,CAAQ,QAAA,CAAS,QAAQ,CAAA;AAAA,MACjC,SAAA,EAAW,OAAA,CAAQ,QAAA,CAAS,WAAW,CAAA;AAAA,MACvC,MAAA,EAAQ,OAAA,CAAQ,QAAA,CAAS,QAAQ;AAAA,KACnC;AAAA,GACD,CAAA;AAED,EAAA,uBACE,IAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,MAAA;AAAA,MACA,QAAA,EAAU,MAAM,MAAA,CAAO,IAAA,CAAK,IAAI,aAAA,CAAc,IAAA;AAAA,MAC9C,YAAY,CAAC,EAAE,KAAA,EAAM,KAAM,qBAAqB,KAAK,CAAA;AAAA,MACrD,OAAA,EAAS;AAAA,QACP,SAAA,EAAW,KAAA;AAAA,QACX,QAAA,EAAU,OAAA;AAAA,QACV,MAAA,EAAQ;AAAA,OACV;AAAA,MACA,SAAA,EAAU,8FAAA;AAAA,MAEV,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,YAAA;AAAA,UAAA;AAAA,YACC,MAAA;AAAA,YACA,IAAA,EAAK,MAAA;AAAA,YACL,UAAU,YAAA,CAAa,IAAA;AAAA,YACvB,SAAA,EAAW,EAAE,iBAAiB,CAAA;AAAA,YAE9B,QAAA,kBAAA,GAAA,CAACC,QAAA,EAAK;AAAA;AAAA,SACR;AAAA,wBACA,GAAA;AAAA,UAAC,YAAA;AAAA,UAAA;AAAA,YACC,MAAA;AAAA,YACA,IAAA,EAAK,QAAA;AAAA,YACL,UAAU,YAAA,CAAa,MAAA;AAAA,YACvB,SAAA,EAAW,EAAE,mBAAmB,CAAA;AAAA,YAEhC,8BAAC,MAAA,EAAA,EAAO;AAAA;AAAA,SACV;AAAA,wBACA,GAAA;AAAA,UAAC,YAAA;AAAA,UAAA;AAAA,YACC,MAAA;AAAA,YACA,IAAA,EAAK,WAAA;AAAA,YACL,UAAU,YAAA,CAAa,SAAA;AAAA,YACvB,SAAA,EAAW,EAAE,sBAAsB,CAAA;AAAA,YAEnC,8BAACC,WAAA,EAAA,EAAc;AAAA;AAAA,SACjB;AAAA,wBACA,GAAA;AAAA,UAAC,YAAA;AAAA,UAAA;AAAA,YACC,MAAA;AAAA,YACA,IAAA,EAAK,QAAA;AAAA,YACL,UAAU,YAAA,CAAa,MAAA;AAAA,YACvB,SAAA,EAAW,EAAE,mBAAmB,CAAA;AAAA,YAEhC,8BAAC,MAAA,EAAA,EAAO;AAAA;AAAA;AACV;AAAA;AAAA,GACF;AAEJ,CAAA;ACvGO,IAAM,YAAA,GAAe,CAAC,EAAE,WAAA,EAAa,QAAO,KAAyB;AAC1E,EAAA,MAAM,SAAA,GAAY,OAAO,MAAM,CAAA;AAC/B,EAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAEpB,EAAA,MAAM,SAAA,GAAY,OAAsB,IAAI,CAAA;AAE5C,EAAA,MAAM,cAAA,GAAiBC,YAAY,MAAM;AACvC,IAAA,MAAM,UAAU,SAAA,CAAU,OAAA;AAC1B,IAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,WAAA,EAAa;AAErC,IAAA,MAAM,IAAA,GAAO,QAAQ,OAAA,CAAQ,EAAE,gBAAgB,IAAA,EAAM,EAAE,IAAA,EAAK;AAC5D,IAAA,IAAI,CAAC,IAAA,EAAM;AAEX,IAAA,SAAA,CAAU,OAAA,CAAQ,IAAA,EAAM,OAAA,CAAQ,OAAA,EAAS,CAAA;AACzC,IAAA,OAAA,CAAQ,QAAA,CAAS,aAAa,IAAI,CAAA;AAClC,IAAA,OAAA,CAAQ,SAAS,KAAA,EAAM;AAAA,EACzB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,iBAAA,GAAoB,OAAO,cAAc,CAAA;AAC/C,EAAA,iBAAA,CAAkB,OAAA,GAAU,cAAA;AAE5B,EAAA,MAAM,SAAS,SAAA,CAAU;AAAA,IACvB,iBAAA,EAAmB,KAAA;AAAA,IACnB,UAAA,EAAY,cAAA;AAAA,IACZ,SAAA,EAAW,IAAA;AAAA,IACX,WAAA,EAAa;AAAA,MACX,UAAA,EAAY;AAAA,QACV,KAAA,EAAO,0CAAA;AAAA,QACP,YAAA,EAAc;AAAA,OAChB;AAAA,MACA,aAAA,EAAe,CAAC,KAAA,EAAO,KAAA,KAAU;AAC/B,QAAA,IACE,KAAA,CAAM,GAAA,KAAQ,OAAA,IACd,KAAA,CAAM,QAAA,IACN,MAAM,MAAA,IACN,KAAA,CAAM,OAAA,IACN,KAAA,CAAM,OAAA,EACN;AACA,UAAA,OAAO,KAAA;AAAA,QACT;AACA,QAAA,IAAI,KAAA,CAAM,WAAA,IAAe,KAAA,CAAM,OAAA,KAAY,KAAK,OAAO,KAAA;AAEvD,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,iBAAA,CAAkB,OAAA,EAAQ;AAC1B,QAAA,OAAO,IAAA;AAAA,MACT;AAAA;AACF,GACD,CAAA;AAED,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAAA,EACtB,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,MAAM,UACJC,cAAAA,CAAe;AAAA,IACb,MAAA;AAAA,IACA,QAAA,EAAU,CAAC,EAAE,MAAA,EAAQ,SAAQ,KAAM,CAAC,OAAA,EAAS,OAAA,CAAQ,EAAE,cAAA,EAAgB,IAAA,EAAM,EAAE,IAAA;AAAK,GACrF,CAAA,IAAK,IAAA;AAER,EAAA,uBACEC,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sCACb,QAAA,kBAAAC,IAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWN,EAAAA;AAAA,QACT,uFAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAAM,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAA,EACZ,QAAA,EAAA;AAAA,UAAA,OAAA,oBACCD,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yEACb,QAAA,EAAA,WAAA,EACH,CAAA;AAAA,0BAEFA,GAAAA,CAAC,aAAA,EAAA,EAAc,MAAA,EAAgB,WAAU,oCAAA,EAAqC,CAAA;AAAA,UAC7E,MAAA,oBAAUA,GAAAA,CAAC,cAAA,EAAA,EAAe,MAAA,EAAgB;AAAA,SAAA,EAC7C,CAAA;AAAA,wBACAA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,QACb,QAAA,kBAAAA,GAAAA;AAAA,UAACE,MAAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,MAAA;AAAA,YACL,OAAA,EAAQ,SAAA;AAAA,YACR,OAAA,EAAS,cAAA;AAAA,YACT,QAAA,EAAU,OAAA;AAAA,YACV,SAAA,EAAU,gBAAA;AAAA,YAEV,QAAA,kBAAAF,GAAAA;AAAA,cAAC,IAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAWL,EAAAA;AAAA,kBACT,uEAAA;AAAA,kBACA,OAAA,IAAW;AAAA;AACb;AAAA;AACF;AAAA,SACF,EACF;AAAA;AAAA;AAAA,GACF,EACF,CAAA;AAEJ,CAAA;AC3GA,IAAMQ,WAAAA,GAAa,8DAAA;AAEnB,IAAM,SAAA,GAAY,CAAC,IAAA,EAAc,KAAA,KAA2C;AAC1E,EAAA,OAAA,CAAQ,SAAS,EAAC,EAAG,MAAA,CAAkB,CAAC,KAAK,IAAA,KAAS;AACpD,IAAA,QAAQ,KAAK,IAAA;AAAM,MACjB,KAAK,MAAA;AACH,QAAA,uBAAOH,GAAAA,CAAC,QAAA,EAAA,EAAO,SAAA,EAAU,aAAa,QAAA,EAAA,GAAA,EAAI,CAAA;AAAA,MAC5C,KAAK,QAAA;AACH,QAAA,uBAAOA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,sBAAsB,QAAA,EAAA,GAAA,EAAI,CAAA;AAAA,MACjD,KAAK,QAAA;AACH,QAAA,uBAAOA,GAAAA,CAAC,GAAA,EAAA,EAAG,QAAA,EAAA,GAAA,EAAI,CAAA;AAAA,MACjB,KAAK,WAAA;AACH,QAAA,uBAAOA,GAAAA,CAAC,GAAA,EAAA,EAAG,QAAA,EAAA,GAAA,EAAI,CAAA;AAAA,MACjB,KAAK,MAAA;AACH,QAAA,uBACEA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kEACb,QAAA,EAAA,GAAA,EACH,CAAA;AAAA,MAEJ,KAAK,MAAA,EAAQ;AACX,QAAA,MAAM,IAAA,GAAO,OAAO,IAAA,CAAK,KAAA,EAAO,SAAS,QAAA,GAAW,IAAA,CAAK,MAAM,IAAA,GAAO,MAAA;AACtE,QAAA,IAAI,CAAC,MAAM,OAAO,GAAA;AAClB,QAAA,uBACEA,GAAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,IAAA;AAAA,YACA,MAAA,EAAO,QAAA;AAAA,YACP,GAAA,EAAI,qBAAA;AAAA,YACJ,SAAA,EAAWG,WAAAA;AAAA,YACX,OAAA,EAAS,CAAC,KAAA,KAAU,KAAA,CAAM,eAAA,EAAgB;AAAA,YAC1C,kBAAA,EAAiB,qBAAA;AAAA,YACjB,sBAAA,EAAsB,IAAA;AAAA,YACtB,yBAAA,EAAwB,MAAA;AAAA,YAEvB,QAAA,EAAA;AAAA;AAAA,SACH;AAAA,MAEJ;AAAA,MACA;AACE,QAAA,OAAO,GAAA;AAAA;AACX,EACF,GAAG,IAAI,CAAA;AACT,CAAA;AAEA,IAAM,UAAA,GAAa,CAAC,IAAA,EAAmB,GAAA,KAA2B;AAChE,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,EAAS,GAAA,CAAI,CAAC,KAAA,EAAO,KAAA,KAAU,UAAA,CAAW,KAAA,EAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,KAAK,EAAE,CAAC,CAAA;AAEzF,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,KAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,uBACEH,GAAAA,CAAC,GAAA,EAAA,EAAY,SAAA,EAAU,iBAAA,EACpB,sCAAYA,GAAAA,CAAC,IAAA,EAAA,EAAG,CAAA,EAAA,EADX,GAER,CAAA;AAAA,IAEJ,KAAK,YAAA;AACH,MAAA,uBACEA,GAAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,gEAAA;AAAA,UAET;AAAA,SAAA;AAAA,QAHI;AAAA,OAIP;AAAA,IAEJ,KAAK,WAAA;AACH,MAAA,uBACEA,GAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,8FAAA;AAAA,UAEV,QAAA,kBAAAA,GAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAS;AAAA,SAAA;AAAA,QAHX;AAAA,OAIP;AAAA,IAEJ,KAAK,WAAA;AACH,MAAA,uBAAOA,GAAAA,CAAC,IAAA,EAAA,EAAA,EAAQ,GAAK,CAAA;AAAA,IACvB,KAAK,MAAA;AACH,MAAA,uBAAOA,GAAAA,CAAC,MAAA,EAAA,EAAgB,QAAA,EAAA,SAAA,CAAU,IAAA,CAAK,QAAQ,EAAA,EAAI,IAAA,CAAK,KAAK,CAAA,EAAA,EAA3C,GAA6C,CAAA;AAAA,IACjE;AACE,MAAA,OAAO,QAAA;AAAA;AAEb,CAAA;AAEO,IAAM,qBAAA,GAAwB,CAAC,OAAA,KAAoC;AACxE,EAAA,OAAO,UAAA,CAAW,SAAS,UAAU,CAAA;AACvC,CAAA;ACvFO,IAAM,UAAA,GAAa,CAAC,OAAA,KAAoB;AAC7C,EAAA,MAAM,QAAA,GAAW,sBAAA;AACjB,EAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,KAAA,CAAM,QAAQ,CAAA;AAE3C,EAAA,OAAO,YAAA,CAAa,GAAA,CAAI,CAAC,WAAA,EAAa,KAAA,KAAU;AAC9C,IAAA,IAAI,QAAA,CAAS,IAAA,CAAK,WAAW,CAAA,EAAG;AAC9B,MAAA,uBACEA,GAAAA;AAAA,QAAC,GAAA;AAAA,QAAA;AAAA,UAEC,IAAA,EAAM,WAAA;AAAA,UACN,MAAA,EAAO,QAAA;AAAA,UACP,GAAA,EAAI,qBAAA;AAAA,UACJ,SAAA,EAAU,8DAAA;AAAA,UACV,OAAA,EAAS,CAAC,CAAA,KAAM,CAAA,CAAE,eAAA,EAAgB;AAAA,UAClC,kBAAA,EAAiB,qBAAA;AAAA,UACjB,sBAAA,EAAsB,WAAA;AAAA,UACtB,yBAAA,EAAwB,MAAA;AAAA,UAEvB,QAAA,EAAA;AAAA,SAAA;AAAA,QAVI;AAAA,OAWP;AAAA,IAEJ;AAEA,IAAA,OAAO,WAAA;AAAA,EACT,CAAC,CAAA;AACH,CAAA;ACbO,IAAM,qBAAqB,CAAC,EAAE,IAAA,EAAM,OAAA,EAAS,WAAU,KAA+B;AAC3F,EAAA,uBACEA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAWL,GAAG,yBAAA,EAA2B,SAAS,CAAA,EACpD,QAAA,EAAA,OAAA,GAAU,qBAAA,CAAsB,OAAO,CAAA,GAAI,UAAA,CAAW,IAAI,CAAA,EAC7D,CAAA;AAEJ,CAAA;ACIO,IAAM,IAAA,GAAO,CAAC,EAAE,wBAAA,EAA0B,WAAW,KAAA,EAAM,GAAe,EAAC,KAAM;AACtF,EAAA,MAAM,EAAE,CAAA,EAAG,IAAA,EAAK,GAAIS,eAAe,OAAO,CAAA;AAC1C,EAAA,MAAM,cAAA,GAAiBC,OAAuB,IAAI,CAAA;AAClD,EAAA,MAAM,EAAE,eAAA,EAAiB,iBAAA,EAAmB,SAAA,KAAc,OAAA,EAAQ;AAClE,EAAA,MAAM,EAAE,YAAA,EAAc,UAAA,EAAW,GAAI,YAAA,EAAa;AAClD,EAAA,MAAM,EAAE,IAAA,EAAM,WAAA,KAAgB,QAAA,EAAS,CAAE,KAAK,cAAA,EAAe;AAC7D,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,QAAA,EAAU,UAAA,CAAW,IAAI,CAAA,GAC7C,OAAA,GACA,IAAA,CAAK,QAAA,EAAU,UAAA,CAAW,IAAI,CAAA,GAC5B,UACA,IAAA,CAAK,QAAA;AAEX,EAAA,MAAM,cAAA,GAAiB,CAAC,QAAA,GAA2B,QAAA,KAAa;AAC9D,IAAA,cAAA,CAAe,OAAA,EAAS,cAAA,CAAe,EAAE,QAAA,EAAU,CAAA;AAAA,EACrD,CAAA;AAEA,EAAAC,UAAU,MAAM;AACd,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,qBAAA,CAAsB,MAAM;AAC1B,QAAA,cAAA,CAAe,MAAM,CAAA;AAAA,MACvB,CAAC,CAAA;AAAA,IACH;AAAA,EACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAGf,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,UAAA,IAAc,YAAA,CAAa,MAAA,GAAS,CAAA,EAAG;AACzC,MAAA,qBAAA,CAAsB,MAAM;AAC1B,QAAA,cAAA,CAAe,QAAQ,CAAA;AAAA,MACzB,CAAC,CAAA;AAAA,IACH;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,CAAa,MAAA,EAAQ,UAAU,CAAC,CAAA;AAEpC,EAAA,MAAM,iBAAA,GAAoB,CAAC,IAAA,EAAc,OAAA,KAA0B;AACjE,IAAA,eAAA,CAAgB,MAAM,OAAO,CAAA;AAC7B,IAAA,qBAAA,CAAsB,MAAM;AAC1B,MAAA,cAAA,CAAe,QAAQ,CAAA;AAAA,IACzB,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,cAAc,oBAAoB,CAAA;AACnD,EAAA,IAAI,CAAC,YAAY,OAAO,IAAA;AAExB,EAAA,MAAM,kBAAA,GACJ,+GAAA;AAEF,EAAA,MAAM,WAAA,mBACJL,IAAAA,CAAA,QAAA,EAAA,EAEE,QAAA,EAAA;AAAA,oBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uEAAA,EACb,QAAA,EAAA;AAAA,sBAAAD,IAAC,IAAA,EAAA,EAAG,SAAA,EAAU,uCAAA,EAAyC,QAAA,EAAA,CAAA,CAAE,YAAY,CAAA,EAAE,CAAA;AAAA,sBACvEA,GAAAA,CAACE,MAAAA,EAAA,EAAO,IAAA,EAAK,MAAA,EAAO,SAAQ,MAAA,EAAO,OAAA,EAAS,WAC1C,QAAA,kBAAAF,GAAAA,CAAC,SAAM,SAAA,EAAU,SAAA,EAAU,cAAY,CAAA,CAAE,YAAY,GAAG,CAAA,EAC1D;AAAA,KAAA,EACF,CAAA;AAAA,oBAGAA,IAAC,UAAA,EAAA,EAAW,SAAA,EAAU,mCACpB,QAAA,kBAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACZ,QAAA,EAAA;AAAA,MAAA,YAAA,CAAa,WAAW,CAAA,mBACvBD,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mCACb,QAAA,kBAAAA,GAAAA,CAAC,GAAA,EAAA,EAAG,QAAA,EAAA,CAAA,CAAE,YAAY,CAAA,EAAE,CAAA,EACtB,IAEA,YAAA,CAAa,GAAA,CAAI,CAAC,OAAA,KAAY;AAC5B,QAAA,MAAM,eAAe,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAA,KAAM,MAAA,CAAO,aAAa,EAAE,CAAA;AACxE,QAAA,uBACEA,GAAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YAEC,SAAA,EAAW,CAAA,WAAA,EAAc,YAAA,GAAe,aAAA,GAAgB,eAAe,CAAA,CAAA;AAAA,YAEvE,QAAA,kBAAAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0EAAA,EACb,QAAA,EAAA;AAAA,8BAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wEAAA,EACZ,QAAA,EAAA;AAAA,gBAAA,CAAC,gCACAD,GAAAA;AAAA,kBAAC,WAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,GAAA;AAAA,oBACL,MAAA,EAAQ,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAA;AAAA,oBAC/B,MAAM,OAAA,CAAQ,UAAA;AAAA,oBACd,GAAA,EAAK,CAAA,mCAAA,EAAsC,OAAA,CAAQ,QAAQ,CAAA,YAAA;AAAA;AAAA,iBAC7D;AAAA,gCAEFA,GAAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAW,CAAA,aAAA,EAAgB,YAAA,GAAe,4BAAA,GAA+B,qBAAqB,CAAA,CAAA;AAAA,oBAE7F,cAAI,IAAA,CAAK,OAAA,CAAQ,SAAS,CAAA,CAAE,mBAAmB,UAAA,EAAY;AAAA,sBAC1D,IAAA,EAAM,SAAA;AAAA,sBACN,MAAA,EAAQ;AAAA,qBACT;AAAA;AAAA;AACH,eAAA,EACF,CAAA;AAAA,8BACAC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,UAAA,EACb,QAAA,EAAA;AAAA,gCAAAD,GAAAA;AAAA,kBAAC,kBAAA;AAAA,kBAAA;AAAA,oBACC,MAAM,OAAA,CAAQ,IAAA;AAAA,oBACd,SAAS,OAAA,CAAQ,OAAA;AAAA,oBACjB,SAAA,EAAWL,EAAAA;AAAA,sBACT,8CAAA;AAAA,sBACA,eACI,uCAAA,GACA;AAAA;AACN;AAAA,iBACF;AAAA,gBACC,gCACCK,GAAAA;AAAA,kBAACE,MAAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,IAAA,EAAK,MAAA;AAAA,oBACL,OAAA,EAAQ,MAAA;AAAA,oBACR,SAAA,EAAU,qMAAA;AAAA,oBACV,OAAA,EAAS,MAAM,iBAAA,CAAkB,OAAA,CAAQ,EAAE,CAAA;AAAA,oBAC3C,YAAA,EAAY,EAAE,iBAAiB,CAAA;AAAA,oBAE/B,QAAA,kBAAAF,GAAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,6BAAA,EAA8B;AAAA;AAAA;AACjD,eAAA,EAEJ;AAAA,aAAA,EACF;AAAA,WAAA;AAAA,UA9CK,OAAA,CAAQ;AAAA,SA+Cf;AAAA,MAEJ,CAAC,CAAA;AAAA,sBAEHA,GAAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,cAAA,EAAgB;AAAA,KAAA,EAC5B,CAAA,EACF,CAAA;AAAA,oBAEAA,IAAC,YAAA,EAAA,EAAa,WAAA,EAAa,EAAE,kBAAkB,CAAA,EAAG,QAAQ,iBAAA,EAAmB;AAAA,GAAA,EAC/E,CAAA;AAGF,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBAAOA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAWL,GAAG,kBAAA,EAAoB,uBAAuB,GAAI,QAAA,EAAA,WAAA,EAAY,CAAA;AAAA,EACvF;AAEA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBACEK,GAAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,UAAA,EAAY,YAAA,EAAc,CAAC,IAAA,KAAS,CAAC,IAAA,IAAQ,SAAA,EAAU,EAClE,QAAA,kBAAAC,IAAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,mLAAA;AAAA,QACV,kBAAA,EAAkB,MAAA;AAAA,QAElB,QAAA,EAAA;AAAA,0BAAAD,IAAC,UAAA,EAAA,EAAW,SAAA,EAAU,SAAA,EAAW,QAAA,EAAA,CAAA,CAAE,YAAY,CAAA,EAAE,CAAA;AAAA,0BACjDA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gDAAgD,QAAA,EAAA,WAAA,EAAY;AAAA;AAAA;AAAA,KAC7E,EACF,CAAA;AAAA,EAEJ;AAEA,EAAA,IAAI,wBAAA,EAA0B;AAC5B,IAAA,uBACEA,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAWL,EAAAA;AAAA,UACT,+IAAA;AAAA,UACA;AAAA,SACF;AAAA,QAEC,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,uBACEK,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oNACZ,QAAA,EAAA,WAAA,EACH,CAAA;AAEJ;AC9KO,IAAM,UAAA,GAAa,CAAC,EAAE,SAAA,EAAU,KAAuB;AAC5D,EAAA,MAAM,EAAE,UAAA,EAAW,GAAI,OAAA,EAAQ;AAC/B,EAAA,MAAM,EAAE,UAAA,EAAY,mBAAA,EAAoB,GAAI,YAAA,EAAa;AAEzD,EAAA,uBACEC,IAAAA;AAAA,IAACC,MAAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,MAAA;AAAA,MACL,OAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,UAAA;AAAA,MACT,SAAA,EAAWP,EAAAA;AAAA,QACT,8FAAA;AAAA,QACA,CAAC,SAAA,IAAa,oBAAA;AAAA,QACd,UAAA,IAAc,gBAAA;AAAA,QACd;AAAA,OACF;AAAA,MACA,kBAAA,EAAiB,kBAAA;AAAA,MACjB,wBAAA,EAAwB,aAAa,OAAA,GAAU,MAAA;AAAA,MAE/C,QAAA,EAAA;AAAA,wBAAAK,GAAAA,CAACO,QAAA,EAAK,SAAA,EAAWZ,GAAG,SAAA,EAAW,UAAA,GAAa,iBAAA,GAAoB,mBAAmB,CAAA,EAAG,CAAA;AAAA,QACrF,mBAAA,GAAsB,CAAA,oBACrBK,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,2KAAA,EACZ,QAAA,EAAA,mBAAA,GAAsB,EAAA,GAAK,KAAA,GAAQ,mBAAA,EACtC;AAAA;AAAA;AAAA,GAEJ;AAEJ","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 * Курсив — запас справа: наклон глифа вылезает из метрики и сталкивается со следующим символом.\n */\nconst chatInlineMarksClassName = cn(\n '[&_strong]:font-bold',\n '[&_em]:italic [&_em]:pr-[0.18em]',\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 [&_.ProseMirror_em]:pr-[0.18em]',\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=\"pr-[0.18em] 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 <div className={cn(chatPanelClassName, 'h-full min-h-0 w-full')}>{chatContent}</div>;\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xipkg/calls-chat",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
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.25",
24
- "@xipkg/calls-hooks": "^0.1.25",
25
- "@xipkg/calls-providers": "^0.1.25",
26
- "@xipkg/calls-store": "^0.1.25",
27
- "@xipkg/calls-types": "^0.1.25",
28
- "@xipkg/calls-ui": "^0.1.25",
29
- "@xipkg/calls-utils": "^0.1.25",
23
+ "@xipkg/calls-config": "^0.1.26",
24
+ "@xipkg/calls-hooks": "^0.1.26",
25
+ "@xipkg/calls-providers": "^0.1.26",
26
+ "@xipkg/calls-store": "^0.1.26",
27
+ "@xipkg/calls-types": "^0.1.26",
28
+ "@xipkg/calls-ui": "^0.1.26",
29
+ "@xipkg/calls-utils": "^0.1.26",
30
30
  "@xipkg/icons": "^3.1.0",
31
31
  "@xipkg/modal": "4.6.0",
32
32
  "@xipkg/scrollarea": "2.3.0",