@ermis-network/ermis-chat-react 1.0.6 → 1.0.8
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.cjs +3802 -1772
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +836 -25
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +304 -1
- package/dist/index.d.ts +304 -1
- package/dist/index.mjs +3755 -1761
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/channelRoleUtils.ts +73 -0
- package/src/channelTypeUtils.ts +46 -0
- package/src/components/Avatar.tsx +57 -31
- package/src/components/BannedOverlay.tsx +40 -0
- package/src/components/ChannelActions.tsx +233 -0
- package/src/components/ChannelHeader.tsx +126 -5
- package/src/components/ChannelInfo/ChannelInfo.tsx +128 -24
- package/src/components/ChannelInfo/ChannelInfoTabs.tsx +67 -28
- package/src/components/ChannelInfo/ChannelSettingsPanel.tsx +90 -1
- package/src/components/ChannelInfo/EditChannelModal.tsx +5 -4
- package/src/components/ChannelInfo/MemberListItem.tsx +2 -1
- package/src/components/ChannelList.tsx +514 -47
- package/src/components/ClosedTopicOverlay.tsx +38 -0
- package/src/components/CreateChannelModal.tsx +53 -16
- package/src/components/EditPreview.tsx +2 -1
- package/src/components/ForwardMessageModal.tsx +2 -1
- package/src/components/MediaLightbox.tsx +314 -0
- package/src/components/MessageInput.tsx +21 -3
- package/src/components/MessageItem.tsx +10 -12
- package/src/components/MessageQuickReactions.tsx +3 -2
- package/src/components/MessageReactions.tsx +8 -3
- package/src/components/MessageRenderers.tsx +174 -54
- package/src/components/PendingOverlay.tsx +51 -0
- package/src/components/PinnedMessages.tsx +2 -1
- package/src/components/ReplyPreview.tsx +2 -1
- package/src/components/SkippedOverlay.tsx +36 -0
- package/src/components/TopicModal.tsx +189 -0
- package/src/components/UserPicker.tsx +1 -1
- package/src/components/VirtualMessageList.tsx +162 -47
- package/src/hooks/useBannedState.ts +27 -3
- package/src/hooks/useBlockedState.ts +3 -2
- package/src/hooks/useChannelCapabilities.ts +10 -8
- package/src/hooks/useChannelData.ts +1 -1
- package/src/hooks/useChannelListUpdates.ts +28 -5
- package/src/hooks/useChannelMessages.ts +2 -3
- package/src/hooks/useChannelRowUpdates.ts +9 -2
- package/src/hooks/useMessageActions.ts +23 -9
- package/src/hooks/useOnlineStatus.ts +71 -0
- package/src/hooks/useOnlineUsers.ts +115 -0
- package/src/hooks/usePendingState.ts +8 -3
- package/src/index.ts +67 -10
- package/src/messageTypeUtils.ts +64 -0
- package/src/styles/_channel-info.css +21 -0
- package/src/styles/_channel-list.css +276 -6
- package/src/styles/_media-lightbox.css +263 -0
- package/src/styles/_message-bubble.css +170 -13
- package/src/styles/_message-input.css +24 -0
- package/src/styles/_message-list.css +76 -6
- package/src/styles/_message-quick-reactions.css +5 -0
- package/src/styles/_message-reactions.css +7 -0
- package/src/styles/_topic-modal.css +154 -0
- package/src/styles/index.css +2 -0
- package/src/types.ts +203 -3
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/context/ChatProvider.tsx","../src/components/ErmisCallProvider.tsx","../src/context/ErmisCallContext.tsx","../src/components/ErmisCallUI.tsx","../src/hooks/useCallContext.ts","../src/components/Modal.tsx","../src/components/Avatar.tsx","../src/hooks/useChatClient.ts","../src/hooks/useChannel.ts","../src/hooks/useChannelListUpdates.ts","../src/hooks/useChannelRowUpdates.ts","../src/hooks/useBannedState.ts","../src/hooks/useBlockedState.ts","../src/hooks/usePendingState.ts","../src/components/ChannelList.tsx","../src/utils.ts","../src/components/Channel.tsx","../src/components/ForwardMessageModal.tsx","../src/components/ChannelHeader.tsx","../src/components/VirtualMessageList.tsx","../src/hooks/useLoadMessages.ts","../src/hooks/useScrollToMessage.ts","../src/hooks/useChannelMessages.ts","../src/hooks/useChannelData.ts","../src/components/MessageItem.tsx","../src/components/QuotedMessagePreview.tsx","../src/components/MessageActionsBox.tsx","../src/hooks/useMessageActions.ts","../src/hooks/useChannelCapabilities.ts","../src/components/Dropdown.tsx","../src/components/MessageReactions.tsx","../src/components/MessageQuickReactions.tsx","../src/components/MessageRenderers.tsx","../src/components/PinnedMessages.tsx","../src/components/ReadReceipts.tsx","../src/components/TypingIndicator.tsx","../src/hooks/useTypingIndicator.ts","../src/components/MessageInput.tsx","../src/hooks/useMentions.ts","../src/hooks/useFileUpload.ts","../src/hooks/useEmojiPicker.ts","../src/hooks/useMessageSend.ts","../src/components/MessageInputDefaults.tsx","../src/components/MentionSuggestions.tsx","../src/components/FilesPreview.tsx","../src/components/ReplyPreview.tsx","../src/components/EditPreview.tsx","../src/components/ChannelInfo/ChannelInfo.tsx","../src/components/ChannelInfo/ChannelInfoTabs.tsx","../src/components/ChannelInfo/utils.tsx","../src/components/ChannelInfo/MediaGridItem.tsx","../src/components/ChannelInfo/LinkListItem.tsx","../src/components/ChannelInfo/FileListItem.tsx","../src/components/ChannelInfo/MemberListItem.tsx","../src/components/ChannelInfo/States.tsx","../src/components/ChannelInfo/AddMemberModal.tsx","../src/components/UserPicker.tsx","../src/components/ChannelInfo/EditChannelModal.tsx","../src/components/ChannelInfo/MessageSearchPanel.tsx","../src/components/Panel.tsx","../src/components/ChannelInfo/ChannelSettingsPanel.tsx","../src/components/CreateChannelModal.tsx"],"sourcesContent":["// Styles\nimport './styles/index.css';\n\n// Context\nexport { ChatProvider } from './context/ChatProvider';\nexport type { ChatProviderProps, ChatContextValue, Theme } from './context/ChatProvider';\n\n// Hooks\nexport { useChatClient } from './hooks/useChatClient';\nexport { useChannel } from './hooks/useChannel';\nexport type { UseChannelReturn } from './hooks/useChannel';\nexport { useChannelListUpdates } from './hooks/useChannelListUpdates';\nexport { useChannelRowUpdates } from './hooks/useChannelRowUpdates';\nexport { useBannedState } from './hooks/useBannedState';\nexport { useBlockedState } from './hooks/useBlockedState';\nexport { usePendingState } from './hooks/usePendingState';\n\n// Components\nexport { Avatar } from './components/Avatar';\nexport type { AvatarProps } from './components/Avatar';\n\nexport { ChannelList, ChannelItem } from './components/ChannelList';\nexport type { ChannelListProps, ChannelItemProps } from './components/ChannelList';\n\nexport { Channel } from './components/Channel';\nexport type { ChannelProps } from './components/Channel';\n\nexport { ChannelHeader } from './components/ChannelHeader';\nexport type { ChannelHeaderProps } from './components/ChannelHeader';\nexport type { ChannelHeaderData } from './types';\n\nexport type { MessageListProps, MessageBubbleProps, MessageItemProps, SystemMessageItemProps, DateSeparatorProps, JumpToLatestProps } from './types';\n\nexport { VirtualMessageList } from './components/VirtualMessageList';\n\nexport { PinnedMessages } from './components/PinnedMessages';\nexport type { PinnedMessagesProps, PinnedMessageItemProps } from './types';\n\nexport { MessageItem, SystemMessageItem } from './components/MessageItem';\nexport { MessageActionsBox } from './components/MessageActionsBox';\nexport type { MessageActionsBoxProps } from './types';\n\nexport { Dropdown, closeAllDropdowns } from './components/Dropdown';\nexport type { DropdownProps } from './components/Dropdown';\n\nexport { MessageReactions } from './components/MessageReactions';\nexport type { MessageReactionsProps, ReactionUser, LatestReaction } from './types';\n\nexport { MessageQuickReactions } from './components/MessageQuickReactions';\n\nexport { useMessageActions } from './hooks/useMessageActions';\n\nexport { formatTime, getDateKey, formatDateLabel, getMessageUserId, replaceMentionsForPreview } from './utils';\n\nexport {\n defaultMessageRenderers,\n RegularMessage,\n SystemMessage,\n SignalMessage,\n PollMessage,\n StickerMessage,\n ErrorMessage,\n AttachmentList,\n MessageAttachment,\n} from './components/MessageRenderers';\nexport type { MessageRendererProps, AttachmentProps } from './components/MessageRenderers';\n\nexport { MessageInput } from './components/MessageInput';\nexport type { MessageInputProps, SendButtonProps, AttachButtonProps, EmojiPickerProps, EmojiButtonProps } from './components/MessageInput';\n\nexport { FilesPreview } from './components/FilesPreview';\nexport type { FilePreviewItem, FilesPreviewProps } from './components/FilesPreview';\n\nexport { MentionSuggestions } from './components/MentionSuggestions';\nexport type { MentionSuggestionsProps } from './components/MentionSuggestions';\n\nexport { useMentions } from './hooks/useMentions';\nexport type { MentionMember, MentionPayload, UseMentionsOptions, UseMentionsReturn } from './hooks/useMentions';\n\nexport { useScrollToMessage } from './hooks/useScrollToMessage';\nexport type { UseScrollToMessageOptions, UseScrollToMessageReturn } from './hooks/useScrollToMessage';\n\nexport { useLoadMessages, dedupMessages } from './hooks/useLoadMessages';\nexport type { UseLoadMessagesOptions, UseLoadMessagesReturn } from './hooks/useLoadMessages';\n\nexport { useChannelMessages } from './hooks/useChannelMessages';\nexport type { UseChannelMessagesOptions } from './hooks/useChannelMessages';\n\nexport { QuotedMessagePreview } from './components/QuotedMessagePreview';\nexport type { QuotedMessagePreviewProps } from './components/QuotedMessagePreview';\nexport { ReplyPreview } from './components/ReplyPreview';\nexport type { ReplyPreviewProps } from './types';\n\nexport { ForwardMessageModal } from './components/ForwardMessageModal';\nexport type { ForwardMessageModalProps, ForwardChannelItemProps } from './components/ForwardMessageModal';\n\nexport { TypingIndicator } from './components/TypingIndicator';\nexport type { TypingIndicatorProps } from './components/TypingIndicator';\nexport { useTypingIndicator } from './hooks/useTypingIndicator';\nexport type { TypingUser } from './hooks/useTypingIndicator';\n\nexport {\n ChannelInfo,\n DefaultChannelInfoHeader,\n DefaultChannelInfoCover,\n DefaultChannelInfoActions,\n DefaultChannelInfoTabs\n} from './components/ChannelInfo';\n\nexport { Modal } from './components/Modal';\nexport { Panel } from './components/Panel';\nexport type {\n ChannelInfoProps,\n ChannelInfoHeaderProps,\n ChannelInfoCoverProps,\n ChannelInfoActionsProps,\n ChannelInfoTabsProps,\n ChannelInfoMemberItemProps,\n ChannelInfoMediaItemProps,\n ChannelInfoLinkItemProps,\n ChannelInfoFileItemProps,\n ChannelInfoEmptyStateProps,\n AttachmentItem,\n MediaTab,\n ModalProps,\n AddMemberModalProps,\n AddMemberUserItemProps,\n AddMemberButtonProps,\n} from './types';\n\nexport { UserPicker } from './components/UserPicker';\nexport type {\n UserPickerProps,\n UserPickerUser,\n UserPickerItemProps,\n UserPickerSelectedBoxProps,\n} from './types';\n\nexport { CreateChannelModal } from './components/CreateChannelModal';\nexport type { CreateChannelModalProps } from './types';\n\n// Call Components\nexport { ErmisCallContext } from './context/ErmisCallContext';\nexport type { CallContextValue } from './context/ErmisCallContext';\nexport { useCallContext } from './hooks/useCallContext';\nexport { ErmisCallProvider } from './components/ErmisCallProvider';\nexport type { ErmisCallProviderProps } from './components/ErmisCallProvider';\nexport { ErmisCallUI } from './components/ErmisCallUI';\nexport type {\n ErmisCallUIProps,\n ErmisCallRingingProps,\n ErmisCallConnectedAudioProps,\n ErmisCallConnectedVideoProps,\n ErmisCallErrorProps,\n ErmisCallControlsBarProps,\n} from './types';\n","import React, { createContext, useState, useCallback } from 'react';\nimport type { Channel, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { Theme, ChatContextValue, ChatProviderProps, ReadStateEntry } from '../types';\nimport { ErmisCallProvider } from '../components/ErmisCallProvider';\nimport { ErmisCallUI } from '../components/ErmisCallUI';\n\nexport type { Theme, ChatContextValue, ChatProviderProps } from '../types';\n\nexport const ChatContext = createContext<ChatContextValue | null>(null);\n\nexport const ChatProvider: React.FC<ChatProviderProps> = ({\n client,\n children,\n initialTheme = 'light',\n enableCall = false,\n callSessionId,\n callWasmPath,\n callRelayUrl,\n CallUIComponent,\n incomingCallAudioPath,\n outgoingCallAudioPath,\n onCallStart,\n onCallEnd,\n onCallError,\n onIncomingCall,\n onCallAccepted,\n onCallRejected,\n}) => {\n const [activeChannelRaw, setActiveChannelRaw] = useState<Channel | null>(null);\n const [theme, setTheme] = useState<Theme>(initialTheme);\n const [messages, setMessages] = useState<FormatMessageResponse[]>([]);\n const [quotedMessage, setQuotedMessage] = useState<FormatMessageResponse | null>(null);\n const [editingMessage, setEditingMessage] = useState<FormatMessageResponse | null>(null);\n const [readState, setReadState] = useState<Record<string, ReadStateEntry>>({});\n const [forwardingMessage, setForwardingMessage] = useState<FormatMessageResponse | null>(null);\n const [jumpToMessageId, setJumpToMessageId] = useState<string | null>(null);\n\n const activeChannel = activeChannelRaw;\n\n const setActiveChannel = useCallback((channel: Channel | null) => {\n setActiveChannelRaw(channel);\n setQuotedMessage(null);\n setEditingMessage(null);\n if (channel) {\n setMessages([...channel.state.latestMessages]);\n setReadState({ ...channel.state.read });\n } else {\n setMessages([]);\n setReadState({});\n }\n }, []);\n\n /** Re-read messages from SDK state into React state */\n const syncMessages = useCallback(() => {\n if (activeChannel) {\n setMessages([...activeChannel.state.latestMessages]);\n }\n }, [activeChannel]);\n\n const value: ChatContextValue = {\n client,\n activeChannel,\n setActiveChannel,\n theme,\n setTheme,\n messages,\n setMessages,\n syncMessages,\n quotedMessage,\n setQuotedMessage,\n editingMessage,\n setEditingMessage,\n readState,\n setReadState,\n forwardingMessage,\n setForwardingMessage,\n jumpToMessageId,\n setJumpToMessageId,\n enableCall,\n };\n\n const CallUIView = CallUIComponent ? <CallUIComponent /> : (\n <ErmisCallUI\n incomingCallAudioPath={incomingCallAudioPath}\n outgoingCallAudioPath={outgoingCallAudioPath}\n />\n );\n\n const content = (\n <ChatContext.Provider value={value}>\n <div className={`ermis-chat ermis-chat--${theme}`}>\n {children}\n {enableCall && CallUIView}\n </div>\n </ChatContext.Provider>\n );\n\n if (enableCall) {\n if (!callSessionId) {\n console.warn('ErmisChat React: enableCall is true but callSessionId is missing.');\n }\n return (\n <ErmisCallProvider\n client={client}\n sessionId={callSessionId || ''}\n wasmPath={callWasmPath}\n relayUrl={callRelayUrl}\n onCallStart={onCallStart}\n onCallEnd={onCallEnd}\n onCallError={onCallError}\n onIncomingCall={onIncomingCall}\n onCallAccepted={onCallAccepted}\n onCallRejected={onCallRejected}\n >\n {content}\n </ErmisCallProvider>\n );\n }\n\n return content;\n};\n","import React, { useEffect, useState, useCallback, useRef } from 'react';\nimport { CallStatus, ErmisCallNode, type UserCallInfo, type CallEventData } from '@ermis-network/ermis-chat-sdk';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\nimport type { ErmisCallProviderProps } from '../types';\n\nexport type { ErmisCallProviderProps } from '../types';\n\nexport const ErmisCallProvider: React.FC<ErmisCallProviderProps> = ({\n children,\n client,\n sessionId,\n wasmPath = '/ermis_call_node_wasm_bg.wasm',\n relayUrl = 'https://iroh-relay.ermis.network:8443',\n onCallStart,\n onCallEnd,\n onCallError,\n onIncomingCall,\n onCallAccepted,\n onCallRejected,\n}) => {\n const [callNode, setCallNode] = useState<ErmisCallNode | null>(null);\n const [callStatus, setCallStatus] = useState<CallStatus | ''>('');\n const [localStream, setLocalStream] = useState<MediaStream | null>(null);\n const [remoteStream, setRemoteStream] = useState<MediaStream | null>(null);\n const [callType, setCallType] = useState<string>('audio');\n const [callerInfo, setCallerInfo] = useState<UserCallInfo | undefined>(undefined);\n const [receiverInfo, setReceiverInfo] = useState<UserCallInfo | undefined>(undefined);\n const [isIncoming, setIsIncoming] = useState<boolean>(false);\n const [isMicMuted, setIsMicMuted] = useState(false);\n const [isVideoMuted, setIsVideoMuted] = useState(true); // Default to true until a video track is added\n const [audioDevices, setAudioDevices] = useState<MediaDeviceInfo[]>([]);\n const [videoDevices, setVideoDevices] = useState<MediaDeviceInfo[]>([]);\n const [selectedAudioDeviceId, setSelectedAudioDeviceId] = useState<string>('');\n const [selectedVideoDeviceId, setSelectedVideoDeviceId] = useState<string>('');\n const [isScreenSharing, setIsScreenSharing] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [isRemoteMicMuted, setIsRemoteMicMuted] = useState(false);\n const [isRemoteVideoMuted, setIsRemoteVideoMuted] = useState(false);\n\n // Call duration timer (C7 — exposed via context)\n const [callDuration, setCallDuration] = useState(0);\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const startTimer = useCallback(() => {\n setCallDuration(0);\n timerRef.current = setInterval(() => {\n setCallDuration((prev) => prev + 1);\n }, 1000);\n }, []);\n\n const stopTimer = useCallback(() => {\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n setCallDuration(0);\n }, []);\n\n useEffect(() => {\n if (callStatus === CallStatus.CONNECTED) {\n startTimer();\n } else {\n stopTimer();\n }\n return () => stopTimer();\n }, [callStatus, startTimer, stopTimer]);\n\n useEffect(() => {\n if (!client || !sessionId) return;\n\n // Create new call node instance\n const node = new ErmisCallNode(client, sessionId, wasmPath, relayUrl);\n setCallNode(node);\n\n // Register Call Events\n node.onCallEvent = (data: CallEventData) => {\n setIsIncoming(data.type === 'incoming');\n setCallType(data.callType);\n setCallerInfo(data.callerInfo);\n setReceiverInfo(data.receiverInfo);\n // C1: Lifecycle callback — incoming call\n if (data.type === 'incoming' && data.callerInfo) {\n onIncomingCall?.(data.callerInfo);\n }\n };\n\n node.onError = (error: string) => {\n setErrorMessage(error);\n // C1: Lifecycle callback — error\n onCallError?.(error);\n };\n node.onDeviceChange = (audio, video) => {\n setAudioDevices(audio);\n setVideoDevices(video);\n };\n node.onScreenShareChange = (isSharing: boolean) => setIsScreenSharing(isSharing);\n\n node.getDevices().then(({ audioDevices: a, videoDevices: v }) => {\n setAudioDevices(a);\n setVideoDevices(v);\n });\n\n node.onCallStatus = (status: string | null) => {\n const parsedStatus = status as CallStatus | '';\n setCallStatus(parsedStatus);\n if (parsedStatus === CallStatus.ENDED || !parsedStatus) {\n setLocalStream(null);\n setRemoteStream(null);\n setIsIncoming(false);\n setCallStatus('');\n }\n };\n\n node.onLocalStream = (stream: MediaStream) => {\n setLocalStream(stream);\n const audioTracks = stream.getAudioTracks();\n setIsMicMuted(audioTracks.length === 0 || !audioTracks[0].enabled);\n const videoTracks = stream.getVideoTracks();\n setIsVideoMuted(videoTracks.length === 0 || !videoTracks[0].enabled);\n };\n\n node.onRemoteStream = (stream: MediaStream) => setRemoteStream(stream);\n\n // Listen for remote peer transceiver state via data channel\n node.onDataChannelMessage = (state: { audio_enable?: boolean; video_enable?: boolean }) => {\n if (typeof state?.audio_enable === 'boolean') {\n setIsRemoteMicMuted(!state.audio_enable);\n }\n if (typeof state?.video_enable === 'boolean') {\n setIsRemoteVideoMuted(!state.video_enable);\n }\n };\n\n // Listen for remote peer requesting to upgrade call (audio → video)\n // Pattern 2: Automatically switch UI layout to video without prompting.\n node.onUpgradeCall = () => {\n setCallType('video');\n // Note: We don't turn on our own camera automatically.\n };\n\n return () => {\n const cleanup = async () => {\n try {\n await node.endCall();\n } catch (e) { } // ignore during unmount\n };\n cleanup();\n };\n }, [client, sessionId, wasmPath, relayUrl, onIncomingCall, onCallError]);\n\n const createCall = useCallback(async (type: 'audio' | 'video', cid: string) => {\n if (!callNode) return;\n setCallType(type);\n setIsIncoming(false);\n setCallStatus(CallStatus.RINGING);\n await callNode.createCall(type, cid);\n // C1: Lifecycle callback — call started\n onCallStart?.(type, cid);\n }, [callNode, onCallStart]);\n\n const acceptCall = useCallback(async () => {\n if (callNode) await callNode.acceptCall();\n // C1: Lifecycle callback — call accepted\n onCallAccepted?.();\n }, [callNode, onCallAccepted]);\n\n const rejectCall = useCallback(async () => {\n if (callNode) await callNode.rejectCall();\n setCallStatus('');\n setIsIncoming(false);\n // C1: Lifecycle callback — call rejected\n onCallRejected?.();\n }, [callNode, onCallRejected]);\n\n const endCall = useCallback(async () => {\n if (callNode) await callNode.endCall();\n // C1: Lifecycle callback — call ended (capture duration before reset)\n const duration = callDuration;\n setCallStatus('');\n setIsIncoming(false);\n setLocalStream(null);\n setRemoteStream(null);\n onCallEnd?.(duration);\n }, [callNode, callDuration, onCallEnd]);\n\n const toggleScreenShare = useCallback(async () => {\n if (!callNode) return;\n if (isScreenSharing) {\n await callNode.stopScreenShare();\n } else {\n await callNode.startScreenShare();\n }\n }, [callNode, isScreenSharing]);\n\n const switchAudioDevice = useCallback(async (deviceId: string) => {\n if (!callNode) return;\n const success = await callNode.switchAudioDevice(deviceId);\n if (success) setSelectedAudioDeviceId(deviceId);\n }, [callNode]);\n\n const switchVideoDevice = useCallback(async (deviceId: string) => {\n if (!callNode) return;\n const success = await callNode.switchVideoDevice(deviceId);\n if (success) setSelectedVideoDeviceId(deviceId);\n }, [callNode]);\n\n const clearError = useCallback(() => setErrorMessage(null), []);\n\n const upgradeCall = useCallback(async () => {\n if (!callNode) return;\n await callNode.upgradeCall();\n setCallType('video');\n }, [callNode]);\n\n const toggleMic = useCallback(async () => {\n if (!callNode || !localStream) return;\n const newMutedState = !isMicMuted;\n await callNode.toggleMic(!newMutedState);\n setIsMicMuted(newMutedState);\n }, [callNode, localStream, isMicMuted]);\n\n const toggleVideo = useCallback(async () => {\n if (!callNode) return;\n if (localStream) {\n if (localStream.getVideoTracks().length > 0) {\n const newMutedState = !isVideoMuted;\n await callNode.toggleCamera(!newMutedState);\n setIsVideoMuted(newMutedState);\n } else {\n // One-way video case: we are in a video call but our camera is off (no track).\n // Clicking toggle video should add our camera track via requestUpgradeCall.\n // This avoids sending the UPGRADE_CALL signal to the backend again.\n await callNode.requestUpgradeCall(true);\n setIsVideoMuted(false);\n }\n }\n }, [callNode, localStream, isVideoMuted]);\n\n const value = {\n callNode,\n callStatus,\n localStream,\n remoteStream,\n callType,\n callerInfo,\n receiverInfo,\n isIncoming,\n createCall,\n acceptCall,\n rejectCall,\n endCall,\n toggleMic,\n toggleVideo,\n isMicMuted,\n isVideoMuted,\n audioDevices,\n videoDevices,\n selectedAudioDeviceId,\n selectedVideoDeviceId,\n isScreenSharing,\n errorMessage,\n toggleScreenShare,\n switchAudioDevice,\n switchVideoDevice,\n clearError,\n isRemoteMicMuted,\n isRemoteVideoMuted,\n upgradeCall,\n callDuration,\n };\n\n return (\n <ErmisCallContext.Provider value={value}>\n {children}\n </ErmisCallContext.Provider>\n );\n};\n\nErmisCallProvider.displayName = 'ErmisCallProvider';\n","import React from 'react';\nimport { CallStatus, type ErmisCallNode, type UserCallInfo } from '@ermis-network/ermis-chat-sdk';\n\nexport type CallContextValue = {\n callNode: ErmisCallNode | null;\n callStatus: CallStatus | '';\n localStream: MediaStream | null;\n remoteStream: MediaStream | null;\n callType: string;\n callerInfo?: UserCallInfo | undefined;\n receiverInfo?: UserCallInfo | undefined;\n isIncoming: boolean;\n createCall: (type: 'audio' | 'video', cid: string) => Promise<void>;\n acceptCall: () => Promise<void>;\n rejectCall: () => Promise<void>;\n endCall: () => Promise<void>;\n toggleMic: () => void;\n toggleVideo: () => void;\n isMicMuted: boolean;\n isVideoMuted: boolean;\n audioDevices: MediaDeviceInfo[];\n videoDevices: MediaDeviceInfo[];\n selectedAudioDeviceId: string;\n selectedVideoDeviceId: string;\n isScreenSharing: boolean;\n errorMessage: string | null;\n toggleScreenShare: () => Promise<void>;\n switchAudioDevice: (id: string) => Promise<void>;\n switchVideoDevice: (id: string) => Promise<void>;\n clearError: () => void;\n isRemoteMicMuted: boolean;\n isRemoteVideoMuted: boolean;\n upgradeCall: () => Promise<void>;\n callDuration: number;\n};\n\nexport const ErmisCallContext = React.createContext<CallContextValue | undefined>(undefined);\n","import React, { useEffect, useRef, useState, useCallback } from 'react';\nimport { useCallContext } from '../hooks/useCallContext';\nimport { Modal } from './Modal';\nimport { Avatar } from './Avatar';\nimport { CallStatus } from '@ermis-network/ermis-chat-sdk';\nimport type { ErmisCallUIProps } from '../types';\n\n/** Format seconds into MM:SS */\nconst formatDuration = (totalSeconds: number): string => {\n const m = Math.floor(totalSeconds / 60).toString().padStart(2, '0');\n const s = (totalSeconds % 60).toString().padStart(2, '0');\n return `${m}:${s}`;\n};\n\nexport const ErmisCallUI: React.FC<ErmisCallUIProps> = React.memo(({\n className,\n incomingCallTitle = (type: string) => `Incoming ${type} call`,\n outgoingCallTitle = (type: string) => `Outgoing ${type} call`,\n ongoingCallTitle = (type: string) => `Ongoing ${type} Call`,\n isCallingYouLabel = 'is calling you...',\n ringingLabel = 'Ringing...',\n rejectCallLabel = 'Reject',\n acceptCallLabel = 'Accept',\n endCallLabel = 'End Call',\n cancelLabel = 'Cancel',\n toggleMicTitle = 'Toggle Mic',\n toggleVideoTitle = 'Toggle Video',\n shareScreenTitle = 'Share Screen',\n stopScreenShareTitle = 'Stop Sharing',\n connectedLabel = 'Connected',\n audioCallBadgeLabel = 'Audio Call',\n videoCallBadgeLabel = 'Video Call',\n fullscreenTitle = 'Fullscreen',\n exitFullscreenTitle = 'Exit Fullscreen',\n upgradeCallTitle = 'Request Video Upgrade',\n suppressIncomingCalls = false,\n onCallDurationChange,\n AvatarComponent = Avatar,\n MicIcon: PropMicIcon,\n MicOffIcon: PropMicOffIcon,\n VideoIcon: PropVideoIcon,\n VideoOffIcon: PropVideoOffIcon,\n PhoneIcon: PropPhoneIcon,\n ScreenShareIcon: PropScreenShareIcon,\n ScreenShareOffIcon: PropScreenShareOffIcon,\n FullscreenIcon: PropFullscreenIcon,\n ExitFullscreenIcon: PropExitFullscreenIcon,\n UpgradeCallIcon: PropUpgradeCallIcon,\n incomingCallAudioPath = '/call_incoming.mp3',\n outgoingCallAudioPath = '/call_outgoing.mp3',\n RingingComponent: CustomRingingComponent,\n ConnectedAudioComponent: CustomConnectedAudioComponent,\n ConnectedVideoComponent: CustomConnectedVideoComponent,\n ErrorComponent: CustomErrorComponent,\n ControlsBarComponent: CustomControlsBarComponent,\n}) => {\n const {\n callStatus,\n callType,\n callerInfo,\n receiverInfo,\n isIncoming,\n localStream,\n remoteStream,\n acceptCall,\n rejectCall,\n endCall,\n toggleMic,\n toggleVideo,\n isMicMuted,\n isVideoMuted,\n audioDevices,\n videoDevices,\n selectedAudioDeviceId,\n selectedVideoDeviceId,\n isScreenSharing,\n errorMessage,\n toggleScreenShare,\n switchAudioDevice,\n switchVideoDevice,\n clearError,\n isRemoteMicMuted,\n upgradeCall,\n callDuration,\n } = useCallContext();\n\n const localVideoRef = useRef<HTMLVideoElement>(null);\n const remoteVideoRef = useRef<HTMLVideoElement>(null);\n const remoteAudioRef = useRef<HTMLAudioElement>(null);\n const ringingAudioRef = useRef<HTMLAudioElement>(null);\n const callContainerRef = useRef<HTMLDivElement>(null);\n\n // Fullscreen state\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n const toggleFullscreen = useCallback(() => {\n if (!callContainerRef.current) return;\n if (!document.fullscreenElement) {\n callContainerRef.current.requestFullscreen?.().catch(() => {});\n } else {\n document.exitFullscreen?.().catch(() => {});\n }\n }, []);\n\n useEffect(() => {\n const handleChange = () => setIsFullscreen(!!document.fullscreenElement);\n document.addEventListener('fullscreenchange', handleChange);\n return () => document.removeEventListener('fullscreenchange', handleChange);\n }, []);\n\n // C5: Notify consumer of duration changes\n useEffect(() => {\n if (callDuration > 0) {\n onCallDurationChange?.(callDuration);\n }\n }, [callDuration, onCallDurationChange]);\n\n useEffect(() => {\n if (localVideoRef.current && localStream) {\n localVideoRef.current.srcObject = localStream;\n }\n }, [localStream, callType, callStatus]);\n\n useEffect(() => {\n if (remoteStream) {\n if (callType === 'video' && remoteVideoRef.current) {\n remoteVideoRef.current.srcObject = remoteStream;\n }\n if (remoteAudioRef.current) {\n remoteAudioRef.current.srcObject = remoteStream;\n }\n }\n }, [remoteStream, callType, callStatus]);\n\n useEffect(() => {\n if (callStatus === CallStatus.RINGING && ringingAudioRef.current) {\n const playPromise = ringingAudioRef.current.play();\n if (playPromise !== undefined) {\n playPromise.catch((e) => console.log('ErmisChat: Audio play blocked by browser:', e));\n }\n } else if (ringingAudioRef.current) {\n ringingAudioRef.current.pause();\n ringingAudioRef.current.currentTime = 0;\n }\n }, [callStatus]);\n\n if (!callStatus && !errorMessage) return null;\n\n // C3: Suppress incoming call UI (DND mode)\n if (suppressIncomingCalls && isIncoming && callStatus === CallStatus.RINGING) return null;\n\n const isOpen = callStatus === CallStatus.RINGING || callStatus === CallStatus.CONNECTED || !!errorMessage;\n if (!isOpen) return null;\n\n const title = errorMessage ? 'Call Error' : (\n callStatus === CallStatus.RINGING\n ? (isIncoming ? incomingCallTitle(callType) : outgoingCallTitle(callType))\n : ongoingCallTitle(callType)\n );\n\n const peerInfo = isIncoming ? callerInfo : receiverInfo;\n const modalMaxWidth = callType === 'video' && callStatus === CallStatus.CONNECTED ? '720px' : '480px';\n\n // Default icons\n const FinalPhoneIcon = PropPhoneIcon || (() => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"></path>\n </svg>\n ));\n\n const FinalVideoIcon = PropVideoIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\"></polygon>\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n </svg>\n ));\n\n const FinalVideoOffIcon = PropVideoOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M16 16v1a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2m5.66 0H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10M1 1l22 22\"></path>\n </svg>\n ));\n\n const FinalMicIcon = PropMicIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"></path>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"></path>\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"></line>\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"></line>\n </svg>\n ));\n\n const FinalMicOffIcon = PropMicOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\"></path>\n <path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23\"></path>\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"></line>\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"></line>\n </svg>\n ));\n\n const FinalScreenShareIcon = PropScreenShareIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"></line>\n <path d=\"M16 11l-4 4-4-4\"></path>\n <path d=\"M12 15V7\"></path>\n </svg>\n ));\n\n const FinalScreenShareOffIcon = PropScreenShareOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"10\" x2=\"12\" y2=\"10\"></line>\n </svg>\n ));\n\n const FinalFullscreenIcon = PropFullscreenIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M8 3H5a2 2 0 0 0-2 2v3\"></path>\n <path d=\"M21 8V5a2 2 0 0 0-2-2h-3\"></path>\n <path d=\"M3 16v3a2 2 0 0 0 2 2h3\"></path>\n <path d=\"M16 21h3a2 2 0 0 0 2-2v-3\"></path>\n </svg>\n ));\n\n const FinalExitFullscreenIcon = PropExitFullscreenIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M4 14h6v6\"></path>\n <path d=\"M20 10h-6V4\"></path>\n <path d=\"M14 10l7-7\"></path>\n <path d=\"M3 21l7-7\"></path>\n </svg>\n ));\n\n // C4: Upgrade call icon (defaults to FinalVideoIcon)\n const FinalUpgradeCallIcon = PropUpgradeCallIcon || FinalVideoIcon;\n\n /* ================================================================\n Shared Controls Bar — used by both audio and video active states\n ================================================================ */\n const renderControls = () => {\n // C6: Allow consumer to replace controls bar entirely\n if (CustomControlsBarComponent) {\n return (\n <CustomControlsBarComponent\n callType={callType}\n toggleMic={toggleMic}\n toggleVideo={toggleVideo}\n toggleScreenShare={toggleScreenShare}\n toggleFullscreen={toggleFullscreen}\n upgradeCall={upgradeCall}\n endCall={endCall}\n isMicMuted={isMicMuted}\n isVideoMuted={isVideoMuted}\n isScreenSharing={isScreenSharing}\n isFullscreen={isFullscreen}\n audioDevices={audioDevices}\n videoDevices={videoDevices}\n selectedAudioDeviceId={selectedAudioDeviceId}\n selectedVideoDeviceId={selectedVideoDeviceId}\n switchAudioDevice={switchAudioDevice}\n switchVideoDevice={switchVideoDevice}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__controls\">\n {/* Mic */}\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleMic}\n className={`ermis-call-ui__control-btn ${isMicMuted ? 'ermis-call-ui__control-btn--muted' : ''}`}\n data-tooltip={toggleMicTitle}\n >\n {isMicMuted ? <FinalMicOffIcon /> : <FinalMicIcon />}\n </button>\n {audioDevices.length > 0 && (\n <select\n className=\"ermis-call-ui__device-select\"\n value={selectedAudioDeviceId}\n onChange={(e) => switchAudioDevice(e.target.value)}\n >\n {audioDevices.map(d => (\n <option key={d.deviceId} value={d.deviceId}>{d.label || 'Microphone'}</option>\n ))}\n </select>\n )}\n </div>\n\n {/* Video controls */}\n {callType === 'video' ? (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleVideo}\n className={`ermis-call-ui__control-btn ${isVideoMuted ? 'ermis-call-ui__control-btn--muted' : ''}`}\n data-tooltip={toggleVideoTitle}\n >\n {isVideoMuted ? <FinalVideoOffIcon /> : <FinalVideoIcon />}\n </button>\n {videoDevices.length > 0 && (\n <select\n className=\"ermis-call-ui__device-select\"\n value={selectedVideoDeviceId}\n onChange={(e) => switchVideoDevice(e.target.value)}\n >\n {videoDevices.map(d => (\n <option key={d.deviceId} value={d.deviceId}>{d.label || 'Camera'}</option>\n ))}\n </select>\n )}\n </div>\n ) : (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={upgradeCall}\n className=\"ermis-call-ui__control-btn\"\n data-tooltip={upgradeCallTitle}\n >\n <FinalUpgradeCallIcon />\n </button>\n </div>\n )}\n\n {/* Screen Share */}\n {callType === 'video' && typeof navigator.mediaDevices?.getDisplayMedia === 'function' && (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleScreenShare}\n className={`ermis-call-ui__control-btn ${isScreenSharing ? 'ermis-call-ui__control-btn--active' : ''}`}\n data-tooltip={isScreenSharing ? stopScreenShareTitle : shareScreenTitle}\n >\n {isScreenSharing ? <FinalScreenShareIcon /> : <FinalScreenShareOffIcon />}\n </button>\n </div>\n )}\n\n {/* Fullscreen */}\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleFullscreen}\n className=\"ermis-call-ui__control-btn\"\n data-tooltip={isFullscreen ? exitFullscreenTitle : fullscreenTitle}\n >\n {isFullscreen ? <FinalExitFullscreenIcon /> : <FinalFullscreenIcon />}\n </button>\n </div>\n\n {/* Separator before end call */}\n <div className=\"ermis-call-ui__controls-separator\" />\n\n {/* End Call */}\n <button\n onClick={endCall}\n className=\"ermis-call-ui__control-btn ermis-call-ui__control-btn--danger\"\n data-tooltip={endCallLabel}\n >\n <FinalPhoneIcon />\n </button>\n </div>\n );\n };\n\n /* ================================================================\n Render ringing state\n ================================================================ */\n const renderRinging = () => {\n // C6: Allow consumer to replace ringing view entirely\n if (CustomRingingComponent) {\n return (\n <CustomRingingComponent\n peerInfo={peerInfo}\n callType={callType}\n isIncoming={isIncoming}\n acceptCall={acceptCall}\n rejectCall={rejectCall}\n endCall={endCall}\n AvatarComponent={AvatarComponent}\n isCallingYouLabel={isCallingYouLabel}\n ringingLabel={ringingLabel}\n rejectCallLabel={rejectCallLabel}\n acceptCallLabel={acceptCallLabel}\n endCallLabel={endCallLabel}\n audioCallBadgeLabel={audioCallBadgeLabel}\n videoCallBadgeLabel={videoCallBadgeLabel}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__ringing\">\n {/* Avatar with pulse rings */}\n <div className=\"ermis-call-ui__ringing-avatar\">\n <div className=\"ermis-call-ui__ringing-avatar-inner\">\n <AvatarComponent\n image={peerInfo?.avatar}\n name={peerInfo?.name}\n size={88}\n />\n </div>\n </div>\n\n <h3 className=\"ermis-call-ui__ringing-name\">\n {peerInfo?.name}\n </h3>\n <p className=\"ermis-call-ui__ringing-status\">\n {isIncoming ? isCallingYouLabel : ringingLabel}\n </p>\n\n {/* Call type badge */}\n <div className=\"ermis-call-ui__type-badge\">\n {callType === 'video' ? <FinalVideoIcon /> : <FinalPhoneIcon />}\n {callType === 'video' ? videoCallBadgeLabel : audioCallBadgeLabel}\n </div>\n\n {/* Action buttons */}\n <div className=\"ermis-call-ui__ringing-actions\">\n {isIncoming ? (\n <>\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={rejectCall}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--reject\"\n >\n <FinalPhoneIcon />\n </button>\n <span className=\"ermis-call-ui__action-label\">{rejectCallLabel}</span>\n </div>\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={acceptCall}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--accept\"\n >\n {callType === 'video' ? <FinalVideoIcon /> : <FinalPhoneIcon />}\n </button>\n <span className=\"ermis-call-ui__action-label\">{acceptCallLabel}</span>\n </div>\n </>\n ) : (\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={endCall}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--reject\"\n >\n <FinalPhoneIcon />\n </button>\n <span className=\"ermis-call-ui__action-label\">{endCallLabel}</span>\n </div>\n )}\n </div>\n </div>\n );\n };\n\n /* ================================================================\n Render connected state\n ================================================================ */\n const renderConnected = () => {\n if (callType === 'video') {\n // C6: Allow consumer to replace connected video view\n if (CustomConnectedVideoComponent) {\n return (\n <CustomConnectedVideoComponent\n localVideoRef={localVideoRef}\n remoteVideoRef={remoteVideoRef}\n isRemoteMicMuted={isRemoteMicMuted}\n renderControls={renderControls}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__active\">\n <div className=\"ermis-call-ui__video-container\">\n <video\n ref={remoteVideoRef}\n autoPlay\n playsInline\n className=\"ermis-call-ui__video-remote\"\n />\n <div className=\"ermis-call-ui__video-local\">\n <video\n ref={localVideoRef}\n autoPlay\n playsInline\n muted\n className=\"ermis-call-ui__video-local-stream\"\n />\n </div>\n {/* Remote mic muted indicator */}\n {isRemoteMicMuted && (\n <div className=\"ermis-call-ui__remote-muted-badge\">\n <FinalMicOffIcon />\n </div>\n )}\n {/* Glassmorphism controls overlay */}\n <div className=\"ermis-call-ui__video-controls-overlay\">\n {renderControls()}\n </div>\n </div>\n </div>\n );\n }\n\n // Audio call\n // C6: Allow consumer to replace connected audio view\n if (CustomConnectedAudioComponent) {\n return (\n <CustomConnectedAudioComponent\n peerInfo={peerInfo}\n callDuration={callDuration}\n isRemoteMicMuted={isRemoteMicMuted}\n AvatarComponent={AvatarComponent}\n connectedLabel={connectedLabel}\n renderControls={renderControls}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__active\">\n <div className=\"ermis-call-ui__audio-container\">\n <div className=\"ermis-call-ui__audio-avatar-wrapper\">\n <AvatarComponent\n image={peerInfo?.avatar}\n name={peerInfo?.name}\n size={100}\n />\n {/* Remote mic muted indicator */}\n {isRemoteMicMuted && (\n <div className=\"ermis-call-ui__remote-muted-badge ermis-call-ui__remote-muted-badge--audio\">\n <FinalMicOffIcon />\n </div>\n )}\n </div>\n <h3 className=\"ermis-call-ui__active-name\">\n {peerInfo?.name}\n </h3>\n\n {/* Status + Timer */}\n <div className=\"ermis-call-ui__active-status\">\n <span className=\"ermis-call-ui__active-status-dot\" />\n <span>{connectedLabel}</span>\n <span className=\"ermis-call-ui__timer\">\n {formatDuration(callDuration)}\n </span>\n </div>\n\n {/* Audio wave visualizer */}\n <div className=\"ermis-call-ui__audio-waves\">\n {Array.from({ length: 9 }).map((_, i) => (\n <span key={i} className=\"ermis-call-ui__audio-wave-bar\" />\n ))}\n </div>\n\n <audio ref={remoteAudioRef} autoPlay className=\"ermis-call-ui__audio--hidden\" />\n\n {/* Controls bar */}\n {renderControls()}\n </div>\n </div>\n );\n };\n\n /* ================================================================\n Render error state\n ================================================================ */\n const renderError = () => {\n if (!errorMessage) return null;\n\n // C6: Allow consumer to replace error view\n if (CustomErrorComponent) {\n return (\n <CustomErrorComponent\n errorMessage={errorMessage}\n clearError={clearError}\n cancelLabel={cancelLabel}\n PhoneIcon={FinalPhoneIcon}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__error\">\n <div className=\"ermis-call-ui__error-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--ermis-color-danger)\" strokeWidth=\"2\" width=\"56\" height=\"56\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n </div>\n <p className=\"ermis-call-ui__error-text\">{errorMessage}</p>\n <button\n className=\"ermis-call-ui__error-dismiss\"\n onClick={clearError}\n >\n <FinalPhoneIcon /> {cancelLabel}\n </button>\n </div>\n );\n };\n\n return (\n <Modal isOpen={isOpen} onClose={endCall} title={title} hideCloseButton closeOnOutsideClick={false} maxWidth={modalMaxWidth}>\n <div className={`ermis-call-ui ${isFullscreen ? 'ermis-call-ui--fullscreen' : ''}${className ? ` ${className}` : ''}`} ref={callContainerRef}>\n {/* Ringing audio */}\n {(incomingCallAudioPath || outgoingCallAudioPath) && (\n <audio\n ref={ringingAudioRef}\n src={isIncoming ? incomingCallAudioPath : outgoingCallAudioPath}\n loop\n className=\"ermis-call-ui__audio--hidden\"\n />\n )}\n\n {/* ============ ERROR STATE ============ */}\n {errorMessage && renderError()}\n\n {/* ============ RINGING STATE ============ */}\n {!errorMessage && callStatus === CallStatus.RINGING && renderRinging()}\n\n {/* ============ CONNECTED STATE ============ */}\n {!errorMessage && callStatus === CallStatus.CONNECTED && renderConnected()}\n </div>\n </Modal>\n );\n});\n\nErmisCallUI.displayName = 'ErmisCallUI';\n","import { useContext } from 'react';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\n\nexport const useCallContext = () => {\n const context = useContext(ErmisCallContext);\n if (context === undefined) {\n throw new Error('useCallContext must be used within an ErmisCallProvider');\n }\n return context;\n};\n","import React, { useEffect } from 'react';\nimport type { ModalProps } from '../types';\n\nexport const Modal: React.FC<ModalProps> = ({\n isOpen,\n onClose,\n title,\n children,\n footer,\n maxWidth = '480px',\n hideCloseButton = false,\n closeOnOutsideClick = true,\n}) => {\n useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && isOpen) onClose();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [isOpen, onClose]);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"ermis-modal-overlay\" onClick={closeOnOutsideClick ? onClose : undefined}>\n <div \n className=\"ermis-modal-content\" \n style={{ maxWidth }} \n onClick={e => e.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <div className=\"ermis-modal-header\">\n {title ? (\n typeof title === 'string' ? <h3>{title}</h3> : title\n ) : <div />}\n {!hideCloseButton && (\n <button className=\"ermis-modal-close\" onClick={onClose} aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n )}\n </div>\n )}\n\n <div className=\"ermis-modal-body\">\n {children}\n </div>\n\n {footer && (\n <div className=\"ermis-modal-footer\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n};\n","import React, { useMemo } from 'react';\nimport type { AvatarProps } from '../types';\n\nexport type { AvatarProps } from '../types';\n\n/**\n * Extracts 1–2 initials from a name.\n */\nfunction getInitials(name?: string): string {\n if (!name) return '?';\n if (name.startsWith('0x')) return '0x';\n const parts = name.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n }\n return parts[0][0].toUpperCase();\n}\n\n/**\n * Avatar component with image or initial fallback.\n */\nexport const Avatar: React.FC<AvatarProps> = React.memo(({\n image,\n name,\n size = 36,\n className,\n}) => {\n const [isLoaded, setIsLoaded] = React.useState(false);\n const [hasError, setHasError] = React.useState(false);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Reset state if image URL changes\n React.useEffect(() => {\n if (image) {\n setHasError(false);\n if (imgRef.current?.complete) {\n setIsLoaded(true);\n } else {\n setIsLoaded(false);\n }\n }\n }, [image]);\n\n const initials = useMemo(() => getInitials(name), [name]);\n\n const wrapperStyle = useMemo<React.CSSProperties>(() => ({\n width: size,\n height: size,\n minWidth: size,\n position: 'relative',\n borderRadius: '100%', /* Or var(--ermis-radius-full) */\n overflow: 'hidden',\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }), [size]);\n\n const contentStyle = useMemo<React.CSSProperties>(() => ({\n width: '100%',\n height: '100%',\n fontSize: size * 0.4,\n lineHeight: 1,\n }), [size]);\n\n return (\n <div className={`ermis-avatar-wrapper${className ? ` ${className}` : ''}`} style={wrapperStyle}>\n {/* 1. Underlying Fallback (Placeholder) */}\n <div\n className=\"ermis-avatar ermis-avatar--fallback\"\n style={contentStyle}\n title={name}\n >\n {initials}\n </div>\n\n {/* 2. Actual Image (Lazy, Fades in natively using CSS opacity) */}\n {image && !hasError && (\n <img\n ref={imgRef}\n className=\"ermis-avatar__img\"\n src={image}\n alt={name || 'Avatar'}\n loading=\"lazy\"\n onLoad={() => setIsLoaded(true)}\n onError={() => setHasError(true)}\n style={{\n ...contentStyle,\n position: 'absolute',\n top: 0,\n left: 0,\n opacity: isLoaded ? 1 : 0,\n transition: 'opacity 0.3s ease-in-out',\n objectFit: 'cover',\n }}\n />\n )}\n </div>\n );\n});\n\nAvatar.displayName = 'Avatar';\n","import { useContext } from 'react';\nimport { ChatContext } from '../context/ChatProvider';\nimport type { ChatContextValue } from '../context/ChatProvider';\n\nexport const useChatClient = (): ChatContextValue => {\n const ctx = useContext(ChatContext);\n if (!ctx) {\n throw new Error('useChatClient must be used within a ChatProvider');\n }\n return ctx;\n};\n","import { useState, useEffect, useCallback } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport type { UseChannelReturn } from '../types';\n\nexport type { UseChannelReturn } from '../types';\n\nexport const useChannel = (): UseChannelReturn => {\n const { activeChannel } = useChatClient();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n return {\n channel: activeChannel,\n loading,\n error,\n };\n};\n","import { useEffect, useRef } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\n\n/**\n * Subscribes to real-time events and keeps the channel list in sync:\n *\n * 1. `message.new` → moves channel to top, auto-calls `markRead()` if\n * the channel is currently active\n * 2. `message.read` → triggers re-render so the unread badge disappears\n *\n * The SDK already mutates `channel.state.latestMessages` and\n * `channel.state.unreadCount` before our listener fires, so we only\n * need to re-order / flush the React state.\n */\nexport function useChannelListUpdates(\n channels: Channel[],\n setChannels: React.Dispatch<React.SetStateAction<Channel[]>>,\n): void {\n const { client, activeChannel, setActiveChannel } = useChatClient();\n\n // Ref to always have the latest activeChannel without re-subscribing\n const activeChannelRef = useRef(activeChannel);\n activeChannelRef.current = activeChannel;\n\n useEffect(() => {\n // --- message.new: re-sort + auto mark-read ---\n const handleNewMessage = (event: Event) => {\n const eventCid = event.cid;\n if (!eventCid) return;\n\n // If the new message is on the active channel and from someone else,\n // mark it as read immediately so unreadCount resets to 0.\n // Skip markRead if the current user is banned, blocked, or pending in that channel.\n const active = activeChannelRef.current;\n if (active?.cid === eventCid && event.user?.id !== client.userID) {\n const isBannedInActive = Boolean(active.state?.membership?.banned);\n const isBlockedInActive = active.type === 'messaging' && Boolean(active.state?.membership?.blocked);\n const isPendingActive =\n active.state?.membership?.channel_role === 'pending' || (active.state?.membership as Record<string, unknown>)?.role === 'pending';\n\n if (!isBannedInActive && !isBlockedInActive && !isPendingActive) {\n active.markRead().catch(() => {\n // silently ignore mark-read errors\n });\n }\n }\n\n setChannels((prev) => {\n const idx = prev.findIndex((ch) => ch.cid === eventCid);\n if (idx <= 0) {\n // Already at top or not found — just create a new reference\n return idx === 0 ? [...prev] : prev;\n }\n\n const channel = prev[idx];\n\n // Don't move banned channels to the top\n if (channel.state?.membership?.banned) {\n return [...prev];\n }\n\n // Move channel to the top\n const updated = [...prev];\n const [ch] = updated.splice(idx, 1);\n updated.unshift(ch);\n return updated;\n });\n };\n\n // --- channel.deleted: remove from list and reset active ---\n const handleChannelDeleted = (event: Event) => {\n const eventCid = event.cid || event.channel?.cid;\n if (!eventCid) return;\n\n if (activeChannelRef.current?.cid === eventCid) {\n setActiveChannel(null);\n }\n\n setChannels((prev) => prev.filter((ch) => ch.cid !== eventCid));\n };\n\n // --- member.removed / notification.invite_rejected: remove from list if it's current user ---\n const handleMemberRemoved = (event: Event) => {\n const eventCid = event.cid || event.channel?.cid;\n // channel_id is often used in notification.* events instead of .cid directly\n const normalizedCid = eventCid\n ? eventCid\n : (event as Record<string, unknown>).channel_id\n ? `${(event as Record<string, unknown>).channel_type}:${(event as Record<string, unknown>).channel_id}`\n : undefined;\n\n if (!normalizedCid) return;\n\n const removedUserId = event.member?.user_id || event.member?.user?.id || event.user?.id;\n\n // If the current user was removed or rejected the invite, remove the channel from their list\n if (removedUserId === client.userID) {\n if (activeChannelRef.current?.cid === normalizedCid) {\n setActiveChannel(null);\n }\n setChannels((prev) => prev.filter((ch) => ch.cid !== normalizedCid));\n }\n // Note: We don't trigger a global global re-render here if someone else is removed.\n // Individual ChannelRow components handle UI updates (e.g., via channel.updated or member.removed events locally).\n };\n\n // --- channel.created: fetch channel details and prepend to list ---\n const handleChannelCreated = async (event: Event, forceWatch: boolean = false) => {\n const type = event.channel?.type || (event as Record<string, unknown>).channel_type;\n const id = event.channel?.id || (event as Record<string, unknown>).channel_id;\n const cid = event.channel?.cid || event.cid || `${type}:${id}`;\n\n if (!type || !id) return;\n\n try {\n // Initialize or retrieve channel instance from SDK cache\n const channelInstance = client.channel(type as string, id as string);\n\n // If this is a member.added event (where event.member belongs to the current user),\n // we optimistically inject the membership so it instantly jumps into pending invites!\n // We DO NOT do this for channel.created, because in channel.created, event.member is the creator (owner).\n if (!forceWatch && event.type === 'member.added' && event.member && channelInstance.state) {\n channelInstance.state.membership = { ...channelInstance.state.membership, ...event.member } as unknown as Record<string, unknown>;\n }\n\n // If the caller requested an explicit api call (e.g. for channel.created)\n if (forceWatch && !channelInstance.initialized) {\n await channelInstance.watch().catch((err) => console.error('Failed to watch channel:', err));\n }\n\n setChannels((prev) => {\n // Double check to prevent duplicates after async pause\n if (prev.some((c) => c.cid === cid)) {\n return prev;\n }\n return [channelInstance, ...prev];\n });\n\n // Loop wait for the core SDK to finish populating the local state from its own watch\n if (!channelInstance.initialized) {\n let attempts = 0;\n const checkInitialized = setInterval(() => {\n attempts++;\n if (channelInstance.initialized || attempts > 60 /* 3s max */) {\n clearInterval(checkInitialized);\n if (channelInstance.initialized) {\n // Force useMemo in ChannelList to recalculate classification (invite vs regular) just in case\n setChannels((p) => [...p]);\n // Manually synthesize a channel.updated event to bust the React.memo inside ChannelItem\n const clientObj = channelInstance.getClient();\n if ('dispatchEvent' in clientObj && typeof clientObj.dispatchEvent === 'function') {\n (clientObj.dispatchEvent as Function)({\n type: 'channel.updated',\n cid: channelInstance.cid,\n channel: channelInstance.data,\n });\n }\n }\n }\n }, 50);\n }\n } catch (err) {\n console.error('Failed to watch newly created channel:', err);\n }\n };\n\n // --- member.added / notification.added_to_channel: fetch if current user is added/invited ---\n const handleMemberAdded = async (event: Event) => {\n const addedUserId = event.member?.user_id || event.member?.user?.id;\n // If the current user was invited or added, fetch the channel (NO API duplication)\n if (addedUserId === client.userID) {\n await handleChannelCreated(event, false);\n }\n };\n\n // --- notification.invite_accepted: force re-grouping ---\n const handleMemberUpdated = (event: Event) => {\n const updatedUserId = event.member?.user_id || event.member?.user?.id || event.user?.id;\n if (updatedUserId === client.userID) {\n setChannels((prev) => {\n // Defensively mutate the channel's membership before grouping logic runs\n const eventCid =\n event.cid ||\n event.channel?.cid ||\n ((event as Record<string, unknown>).channel_id ? `${(event as Record<string, unknown>).channel_type}:${(event as Record<string, unknown>).channel_id}` : undefined);\n\n if (eventCid && event.member) {\n const targetChannel = prev.find((c) => c.cid === eventCid);\n // We forcefully map the updated incoming member data into the static channel representation\n if (targetChannel && targetChannel.state) {\n targetChannel.state.membership = {\n ...targetChannel.state.membership,\n ...event.member,\n } as unknown as Record<string, unknown>;\n }\n }\n\n return [...prev]; // Force react map to regenerate\n });\n }\n };\n\n const sub1 = client.on('message.new', handleNewMessage);\n const sub2 = client.on('channel.deleted', handleChannelDeleted);\n const sub3 = client.on('member.removed', handleMemberRemoved);\n const sub4 = client.on('channel.created', (event) => handleChannelCreated(event, true));\n const sub5 = client.on('member.added', handleMemberAdded);\n const sub6 = client.on('notification.added_to_channel', handleMemberAdded);\n const sub7 = client.on('notification.invite_rejected', handleMemberRemoved);\n const sub8 = client.on('notification.invite_accepted', handleMemberUpdated);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n };\n }, [client, setChannels, setActiveChannel]);\n}\n","import { useEffect, useState } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Custom hook to abstract real-time row-level updates for a single channel.\n * Manages the local unread count, last message preview, and banned status for the channel row in the list.\n */\nexport function useChannelRowUpdates(channel: Channel, currentUserId?: string) {\n // Track banned state for the current user in this channel\n const [isBannedInChannel, setIsBannedInChannel] = useState(() => Boolean(channel.state?.membership?.banned));\n const [isBlockedInChannel, setIsBlockedInChannel] = useState(() => {\n if (channel.type !== 'messaging') return false;\n return Boolean(channel.state?.membership?.blocked);\n });\n\n // Force re-render when messages, members, or read state changes\n const [updateCount, setUpdateCount] = useState(0);\n\n useEffect(() => {\n setIsBannedInChannel(Boolean(channel.state?.membership?.banned));\n setIsBlockedInChannel(\n channel.type === 'messaging' ? Boolean(channel.state?.membership?.blocked) : false\n );\n\n const handleBanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBannedInChannel(true);\n }\n };\n const handleUnbanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBannedInChannel(false);\n }\n };\n\n const handleUpdate = () => setUpdateCount((c) => c + 1);\n\n const sub1 = channel.on('member.banned', handleBanned);\n const sub2 = channel.on('member.unbanned', handleUnbanned);\n const sub3 = channel.on('message.new', handleUpdate);\n const sub4 = channel.on('message.read', handleUpdate);\n const sub5 = channel.on('message.updated', handleUpdate);\n const sub6 = channel.on('message.deleted', handleUpdate);\n const sub7 = channel.on('channel.updated', handleUpdate);\n const sub8 = channel.on('member.added', handleUpdate);\n const sub9 = channel.on('member.removed', handleUpdate);\n\n // Blocked state (messaging channels only)\n const handleBlocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlockedInChannel(true);\n }\n };\n const handleUnblocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlockedInChannel(false);\n }\n };\n const sub10 = channel.on('member.blocked', handleBlocked);\n const sub11 = channel.on('member.unblocked', handleUnblocked);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBannedInChannel, isBlockedInChannel, updateCount };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Hook that tracks whether the current user is banned in the given channel.\n *\n * Reads the initial value from `channel.state.membership.banned` and subscribes\n * to `member.banned` / `member.unbanned` WebSocket events for real-time updates.\n *\n * Only triggers a re-render when the *current user* is the target of the event.\n */\nexport function useBannedState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isBanned, setIsBanned] = useState<boolean>(() => {\n return Boolean(channel?.state?.membership?.banned);\n });\n\n useEffect(() => {\n if (!channel) {\n setIsBanned(false);\n return;\n }\n\n // Sync initial state when channel changes\n setIsBanned(Boolean(channel.state?.membership?.banned));\n\n const handleBanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBanned(true);\n }\n };\n\n const handleUnbanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBanned(false);\n }\n };\n\n const sub1 = channel.on('member.banned', handleBanned);\n const sub2 = channel.on('member.unbanned', handleUnbanned);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBanned };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Hook that tracks whether the current user has blocked the other party\n * in a messaging (1-1) channel.\n *\n * Reads the initial value from `channel.state.membership.blocked` and subscribes\n * to `member.blocked` / `member.unblocked` WebSocket events for real-time updates.\n *\n * Only triggers a re-render when the *current user* is the target of the event\n * (i.e., the blocker). When user A blocks user B, only A's membership has\n * `blocked: true`. B is unaffected.\n *\n * This hook is only meaningful for `messaging` channels. For `team` channels,\n * use `useBannedState` instead.\n */\nexport function useBlockedState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isBlocked, setIsBlocked] = useState<boolean>(() => {\n if (channel?.type !== 'messaging') return false;\n return Boolean(channel?.state?.membership?.blocked);\n });\n\n useEffect(() => {\n if (!channel || channel.type !== 'messaging') {\n setIsBlocked(false);\n return;\n }\n\n // Sync initial state when channel changes\n setIsBlocked(Boolean(channel.state?.membership?.blocked));\n\n const handleBlocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlocked(true);\n }\n };\n\n const handleUnblocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlocked(false);\n }\n };\n\n const sub1 = channel.on('member.blocked', handleBlocked);\n const sub2 = channel.on('member.unblocked', handleUnblocked);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBlocked };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Hook that tracks whether the current user is in a 'pending' state for the given channel.\n */\nexport function usePendingState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isPending, setIsPending] = useState<boolean>(() => {\n const membership = channel?.state?.membership || channel?.state?.members?.[currentUserId || ''];\n return membership?.channel_role === 'pending' || (membership as Record<string, unknown>)?.role === 'pending';\n });\n\n useEffect(() => {\n if (!channel || !currentUserId) {\n setIsPending(false);\n return;\n }\n\n const checkPending = () => {\n const membership = channel.state?.membership || channel.state?.members?.[currentUserId];\n return membership?.channel_role === 'pending' || (membership as Record<string, unknown>)?.role === 'pending';\n };\n\n // Sync initial state\n setIsPending(checkPending());\n\n const defensiveUpdateState = (event: Record<string, unknown>) => {\n // The SDK does not aggressively mutate local state for all events,\n // so we manually map the incoming `member` data onto the channel state so `checkPending` sees it.\n if (event.member && channel.state && channel.state.membership) {\n channel.state.membership = {\n ...channel.state.membership,\n ...(event.member as Record<string, unknown>),\n } as unknown as Record<string, unknown>;\n }\n };\n\n const handleInviteAction = (event: Record<string, unknown>) => {\n const eventMember = event.member as Record<string, unknown>;\n const eventUser = event.user as Record<string, unknown>;\n const eventUserId = eventMember?.user_id || (eventMember?.user as Record<string, unknown>)?.id || eventUser?.id;\n if (eventUserId !== currentUserId) return; // Only react to own invite events\n\n const eventCid =\n event.cid || (event.channel as Record<string, unknown>)?.cid || (event.channel_id ? `${event.channel_type}:${event.channel_id}` : undefined);\n if (eventCid === channel.cid) {\n defensiveUpdateState(event);\n setIsPending(checkPending());\n }\n };\n\n const client = channel.getClient();\n const sub1 = client.on('notification.invite_accepted', handleInviteAction);\n const sub2 = client.on('notification.invite_rejected', handleInviteAction);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isPending };\n}\n","import React, { useEffect, useState, useCallback, useMemo } from 'react';\nimport { VList } from 'virtua';\nimport type { Channel, Event, ChannelFilters } from '@ermis-network/ermis-chat-sdk';\nimport { parseSystemMessage, parseSignalMessage } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useChannelListUpdates } from '../hooks/useChannelListUpdates';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport { useChannelRowUpdates } from '../hooks/useChannelRowUpdates';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { Avatar } from './Avatar';\nimport type { ChannelItemProps, ChannelListProps } from '../types';\n\nexport type { ChannelListProps, ChannelItemProps } from '../types';\n\n/**\n * Get a human-readable preview string for the last message,\n * handling regular, system, and signal message types.\n */\nfunction getLastMessagePreview(\n channel: Channel,\n myUserId?: string,\n): { text: string; user: string } {\n const lastMsg = channel.state?.latestMessages?.slice(-1)[0];\n if (!lastMsg) return { text: '', user: '' };\n\n const msgType = lastMsg.type || 'regular';\n const rawText = lastMsg.text ?? '';\n\n if (msgType === 'system') {\n const userMap = buildUserMap(channel.state);\n return { text: parseSystemMessage(rawText, userMap), user: '' };\n }\n\n if (msgType === 'signal') {\n const result = parseSignalMessage(rawText, myUserId || '');\n return { text: result?.text || rawText, user: '' };\n }\n\n // Display 'Sticker' if message is a sticker\n if (msgType === 'sticker' || (lastMsg as Record<string, unknown>).sticker_url) {\n return { text: 'Sticker', user: lastMsg.user?.name || lastMsg.user_id || '' };\n }\n\n // Regular / other\n let displayText = rawText;\n if (!displayText && lastMsg.attachments && lastMsg.attachments.length > 0) {\n const att = lastMsg.attachments[0];\n const type = att.type || '';\n switch (type) {\n case 'image':\n displayText = '📷 Photo';\n break;\n case 'video':\n displayText = '🎬 Video';\n break;\n case 'voiceRecording':\n displayText = '🎤 Voice message';\n break;\n default:\n displayText = '📎 File';\n break;\n }\n if (lastMsg.attachments.length > 1) {\n displayText += ` +${lastMsg.attachments.length - 1}`;\n }\n }\n\n // Format mentions if necessary\n const lastMsgRecord = lastMsg as Record<string, unknown>;\n const mentionedUsers = lastMsgRecord.mentioned_users as string[] | undefined;\n const mentionedAll = lastMsgRecord.mentioned_all as boolean | undefined;\n\n if (displayText && (mentionedAll || (mentionedUsers && mentionedUsers.length > 0))) {\n const userMap = buildUserMap(channel.state);\n displayText = replaceMentionsForPreview(displayText, lastMsg as any, userMap);\n }\n\n return {\n text: displayText,\n user: lastMsg.user?.name || lastMsg.user_id || '',\n };\n}\n\n/* ----------------------------------------------------------\n Memoized channel list item (exported for consumer reuse)\n ---------------------------------------------------------- */\nexport const ChannelItem: React.FC<ChannelItemProps> = React.memo(({\n channel,\n isActive,\n hasUnread,\n unreadCount,\n lastMessageText,\n lastMessageUser,\n onSelect,\n AvatarComponent,\n isBlocked,\n isPending,\n pendingBadgeLabel,\n blockedBadgeLabel,\n}) => {\n // Subscribe to channel.updated so that when name/image/description change,\n // we re-render from within (bypasses React.memo which only blocks parent-driven re-renders)\n const [, forceUpdate] = useState(0);\n useEffect(() => {\n const sub = channel.on('channel.updated', () => forceUpdate((c) => c + 1));\n return () => sub.unsubscribe();\n }, [channel]);\n\n const name = channel.data?.name || channel.cid;\n const image = channel.data?.image as string | undefined;\n const showUnread = hasUnread && !isActive;\n\n const handleClick = useCallback(() => {\n onSelect(channel);\n }, [channel, onSelect]);\n\n const itemClass = [\n 'ermis-channel-list__item',\n isActive ? 'ermis-channel-list__item--active' : '',\n showUnread ? 'ermis-channel-list__item--unread' : '',\n isBlocked ? 'ermis-channel-list__item--blocked' : '',\n isPending ? 'ermis-channel-list__item--pending' : '',\n ].filter(Boolean).join(' ');\n\n return (\n <div className={itemClass} onClick={handleClick}>\n <AvatarComponent image={image} name={name} size={40} />\n <div className=\"ermis-channel-list__item-content\">\n <div className=\"ermis-channel-list__item-name\">{name}</div>\n {lastMessageText && (\n <div className=\"ermis-channel-list__item-last-message\">\n {lastMessageUser && (\n <span className=\"ermis-channel-list__item-last-message-user\">\n {lastMessageUser}:{' '}\n </span>\n )}\n <span>{lastMessageText}</span>\n </div>\n )}\n </div>\n {showUnread && unreadCount > 0 && (\n <span className=\"ermis-channel-list__unread-badge\">\n {unreadCount > 99 ? '99+' : unreadCount}\n </span>\n )}\n {isBlocked && (\n <span className=\"ermis-channel-list__blocked-icon\" title={blockedBadgeLabel || \"Blocked\"}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </span>\n )}\n {isPending && (\n <span className=\"ermis-channel-list__pending-badge\">{pendingBadgeLabel || 'Invited'}</span>\n )}\n </div>\n );\n});\nChannelItem.displayName = 'ChannelItem';\n\nconst DefaultLoading = React.memo(({ text }: { text?: string }) => (\n <div className=\"ermis-channel-list__loading\">{text || 'Loading channels...'}</div>\n));\nDefaultLoading.displayName = 'DefaultLoading';\n\nconst DefaultEmpty = React.memo(({ text }: { text?: string }) => (\n <div className=\"ermis-channel-list__empty\">{text || 'No channels found'}</div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\n/* ----------------------------------------------------------\n Virtual Row Component to map channel and defer parsing\n ---------------------------------------------------------- */\ntype ChannelRowProps = {\n channel: Channel;\n isActive: boolean;\n handleSelect: (c: Channel) => void;\n renderChannel?: (c: Channel, active: boolean) => React.ReactNode;\n ChannelItemComponent: React.ComponentType<ChannelItemProps>;\n AvatarComponent: React.ComponentType<any>;\n currentUserId?: string;\n pendingBadgeLabel?: string;\n blockedBadgeLabel?: string;\n};\n\nconst ChannelRow: React.FC<ChannelRowProps> = React.memo(({\n channel,\n isActive,\n handleSelect,\n renderChannel,\n ChannelItemComponent,\n AvatarComponent,\n currentUserId,\n pendingBadgeLabel,\n blockedBadgeLabel,\n}) => {\n // Use the new custom hook to handle all row-level realtime updates\n const { isBannedInChannel, isBlockedInChannel, updateCount } = useChannelRowUpdates(channel, currentUserId);\n const { isPending } = usePendingState(channel, currentUserId);\n\n const channelState = channel.state as unknown as Record<string, unknown> | undefined;\n const rawUnreadCount = (channelState?.unreadCount as number) ?? 0;\n const unreadCount = (isBannedInChannel || isBlockedInChannel || isPending) ? 0 : rawUnreadCount;\n const hasUnread = unreadCount > 0;\n\n // Derive last message preview computation is deferred here, \n // so it only executes when VList actually mounts this visible item\n const { text: rawLastMessageText, user: rawLastMessageUser } = useMemo(\n () => getLastMessagePreview(channel, currentUserId),\n // Recompute if latestMessage changes or we get a force update\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [channel, channel.state?.latestMessages, updateCount]\n );\n\n // Hide last message preview when banned, blocked, or pending\n const lastMessageText = (isBannedInChannel || isBlockedInChannel || isPending) ? '' : rawLastMessageText;\n const lastMessageUser = (isBannedInChannel || isBlockedInChannel || isPending) ? '' : rawLastMessageUser;\n\n if (renderChannel) {\n return (\n <div onClick={() => handleSelect(channel)}>\n {renderChannel(channel, isActive)}\n </div>\n );\n }\n\n return (\n <ChannelItemComponent\n channel={channel}\n isActive={isActive}\n hasUnread={hasUnread}\n unreadCount={unreadCount}\n lastMessageText={lastMessageText}\n lastMessageUser={lastMessageUser}\n onSelect={handleSelect}\n AvatarComponent={AvatarComponent}\n isBlocked={isBlockedInChannel}\n isPending={isPending}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n />\n );\n});\nChannelRow.displayName = 'ChannelRow';\n\nexport const ChannelList: React.FC<ChannelListProps> = React.memo(({\n filters = { type: ['messaging', 'team', 'meeting'], include_pinned_messages: true } as unknown as ChannelFilters,\n sort = [],\n options = { message_limit: 25 } as unknown as ChannelListProps['options'],\n renderChannel,\n onChannelSelect,\n className,\n LoadingIndicator = DefaultLoading,\n EmptyStateIndicator = DefaultEmpty,\n AvatarComponent = Avatar,\n ChannelItemComponent = ChannelItem,\n pendingInvitesLabel,\n channelsLabel = 'Channels',\n pendingBadgeLabel,\n loadingLabel,\n emptyStateLabel = 'No channels found',\n blockedBadgeLabel = 'Blocked',\n}) => {\n const { client, activeChannel, setActiveChannel } = useChatClient();\n const [channels, setChannels] = useState<Channel[]>([]);\n const [loading, setLoading] = useState(true);\n const [isPendingExpanded, setIsPendingExpanded] = useState(true);\n\n // Group channels into pending and regular\n const { pendingChannels, regularChannels } = useMemo<{ pendingChannels: Channel[], regularChannels: Channel[] }>(() => {\n const pending: Channel[] = [];\n const regular: Channel[] = [];\n\n channels.forEach(ch => {\n const ms = ch.state?.membership as Record<string, unknown> | undefined;\n const isPending = ms?.channel_role === 'pending' || ms?.role === 'pending';\n if (isPending) {\n pending.push(ch);\n } else {\n regular.push(ch);\n }\n });\n\n return { pendingChannels: pending, regularChannels: regular };\n }, [channels]);\n\n const filtersKey = useMemo(() => JSON.stringify(filters), [filters]);\n\n const loadChannels = useCallback(async () => {\n try {\n setLoading(true);\n const result = await client.queryChannels(filters, sort, options as { message_limit?: number });\n setChannels(result);\n } catch (err) {\n console.error('Failed to load channels:', err);\n } finally {\n setLoading(false);\n }\n }, [client, filtersKey]);\n\n useEffect(() => {\n loadChannels();\n }, [loadChannels]);\n\n // Real-time: List manipulation (move to top, add, delete)\n useChannelListUpdates(channels, setChannels);\n\n const handleSelect = useCallback(\n (channel: Channel) => {\n setActiveChannel(channel);\n onChannelSelect?.(channel);\n\n // Mark as read when user selects a channel (skip if banned, blocked, or pending)\n const ms = channel.state?.membership as Record<string, unknown> | undefined;\n const chState = channel.state as unknown as Record<string, unknown> | undefined;\n const isBannedInChannel = Boolean(ms?.banned);\n const isBlockedInChannel = channel.type === 'messaging' && Boolean(ms?.blocked);\n const isPending = ms?.channel_role === 'pending' || ms?.role === 'pending';\n\n if (!isBannedInChannel && !isBlockedInChannel && !isPending && (chState?.unreadCount as number) > 0) {\n channel.markRead().catch(() => { });\n // Optimistically reset unread to update UI immediately\n if (chState) chState.unreadCount = 0;\n setChannels((prev) => [...prev]);\n }\n },\n [setActiveChannel, onChannelSelect, setChannels],\n );\n\n if (loading) return <LoadingIndicator text={loadingLabel} />;\n if (channels.length === 0) return <EmptyStateIndicator text={emptyStateLabel} />;\n\n return (\n <div className={`ermis-channel-list${className ? ` ${className}` : ''}`}>\n {/* VList requires its container to have a height to work. */}\n <VList style={{ height: '100%' }}>\n {pendingChannels.length > 0 && (\n <div\n className=\"ermis-channel-list__accordion-header\"\n onClick={() => setIsPendingExpanded(prev => !prev)}\n >\n <span>\n {typeof pendingInvitesLabel === 'function'\n ? pendingInvitesLabel(pendingChannels.length)\n : pendingInvitesLabel || `Invites (${pendingChannels.length})`}\n </span>\n <svg\n className={`ermis-channel-list__accordion-icon ${isPendingExpanded ? 'ermis-channel-list__accordion-icon--expanded' : ''}`}\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n )}\n {isPendingExpanded && pendingChannels.map((channel: Channel) => {\n const isActive = activeChannel?.cid === channel.cid;\n return (\n <ChannelRow\n key={channel.cid}\n channel={channel}\n isActive={isActive}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n />\n );\n })}\n {pendingChannels.length > 0 && regularChannels.length > 0 && (\n <div className=\"ermis-channel-list__accordion-header ermis-channel-list__accordion-header--static\">\n <span>{channelsLabel}</span>\n </div>\n )}\n {regularChannels.map((channel: Channel) => {\n const isActive = activeChannel?.cid === channel.cid;\n\n return (\n <ChannelRow\n key={channel.cid}\n channel={channel}\n isActive={isActive}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n />\n );\n })}\n </VList>\n </div>\n );\n});\n\nChannelList.displayName = 'ChannelList'; 'ChannelList';\n","import type { MentionMember } from './types';\nimport type { Attachment, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Format a Date or date-string to a short time string (HH:MM).\n */\nexport function formatTime(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n}\n\n/**\n * Format a date as \"HH:MM, Today\", \"HH:MM, Yesterday\", or \"HH:MM, MM/DD/YYYY\".\n */\nexport function formatReadTimestamp(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const msgDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());\n const diffMs = today.getTime() - msgDay.getTime();\n const diffDays = Math.round(diffMs / 86400000);\n const time = d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n\n if (diffDays === 0) return `${time}, Today`;\n if (diffDays === 1) return `${time}, Yesterday`;\n const mm = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n const yyyy = d.getFullYear();\n return `${time}, ${mm}/${dd}/${yyyy}`;\n}\n\n/**\n * Return a YYYY-M-D key for date comparison (used by date separators).\n */\nexport function getDateKey(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;\n}\n\n/**\n * Format a date into a human-friendly label (Today / Yesterday / full date).\n */\nexport function formatDateLabel(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const msgDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());\n const diffMs = today.getTime() - msgDay.getTime();\n const diffDays = Math.round(diffMs / 86400000);\n\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n return d.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n}\n\n/**\n * Get the user id from a message, checking multiple possible sources.\n */\nexport function getMessageUserId(message: FormatMessageResponse): string {\n return message.user?.id || message.user_id || '';\n}\n\n/**\n * Replace @user_id with @UserName for plain text previews.\n * Returns the formatted string.\n */\nexport function replaceMentionsForPreview(\n text: string,\n message: FormatMessageResponse | { mentioned_users?: string[]; mentioned_all?: boolean },\n userMap: Record<string, string>,\n renderWrapper?: (userId: string, name: string) => string\n): string {\n const mentionedUsers: string[] = (message as any).mentioned_users ?? [];\n const mentionedAll: boolean = (message as any).mentioned_all ?? false;\n\n // If no mentions, nothing to replace\n if (mentionedUsers.length === 0 && !mentionedAll) {\n return text;\n }\n\n const replacements: { pattern: string; label: string }[] = [];\n\n for (const userId of mentionedUsers) {\n if (!userId) continue;\n const name = userMap[userId] ?? userId;\n replacements.push({\n pattern: `@${userId}`,\n label: renderWrapper ? renderWrapper(userId, name) : `@${name}`,\n });\n }\n\n if (mentionedAll) {\n replacements.push({\n pattern: '@all',\n label: renderWrapper ? renderWrapper('__all__', 'all') : '@all'\n });\n }\n\n if (replacements.length === 0) return text;\n\n // Escape special regex characters in the patterns\n const escaped = replacements.map((r) => r.pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n const regex = new RegExp(`(${escaped.join('|')})`, 'g');\n\n // Map pattern back to label for quick lookup\n const patternToLabel = new Map(replacements.map((r) => [r.pattern, r.label]));\n\n return text.replace(regex, (match) => patternToLabel.get(match) || match);\n}\n\n/**\n * Common helper to build a dictionary of User ID -> Display Name\n * from the channel state, used for rendering Mentions and System logs.\n */\nexport function buildUserMap(channelState: any): Record<string, string> {\n const map: Record<string, string> = {};\n const members = channelState?.members;\n if (members && typeof members === 'object') {\n for (const [id, member] of Object.entries<any>(members)) {\n map[id] = member?.user?.name || member?.user_id || id;\n }\n }\n return map;\n}\n\n/**\n * Move caret to the very end of a contenteditable element.\n */\nexport function moveCaretToEnd(el: HTMLElement) {\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.selectNodeContents(el);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Move caret immediately after a specific DOM node.\n */\nexport function moveCaretAfterNode(node: Node) {\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Checks if a given attachment represents user-managed media (e.g., photo, video, text file, voice)\n * as opposed to backend-injected automated system cards (like linkPreviews or slash commands).\n */\nexport function isUserManagedAttachment(attachment: Attachment): boolean {\n const type = attachment.type || 'file';\n return ['image', 'video', 'file', 'voiceRecording'].includes(type);\n}\n\n/**\n * Lightweight in-memory image preloader.\n */\nconst preloadedUrls = new Set<string>();\nconst MAX_CACHE_SIZE = 500;\n\nexport function preloadImage(url: string): void {\n if (!url || preloadedUrls.has(url)) return;\n\n if (preloadedUrls.size >= MAX_CACHE_SIZE) {\n const first = preloadedUrls.values().next().value;\n if (first) preloadedUrls.delete(first);\n }\n\n const img = new Image();\n img.src = url;\n preloadedUrls.add(url);\n}\n\nexport function isImagePreloaded(url: string): boolean {\n return preloadedUrls.has(url);\n}\n\n/**\n * Format bytes into a human-readable file size (e.g. \"1.2 MB\").\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n}\n\n/**\n * Format a date string into a relative label:\n * \"Today\", \"Yesterday\", \"Xd ago\", or \"Mon DD\" / \"Mon DD, YYYY\".\n */\nexport function formatRelativeDate(dateStr: string): string {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n if (diffDays < 7) return `${diffDays}d ago`;\n\n return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined });\n}\n\n/**\n * Get a cleaned display name from a raw file_name.\n * Strips UUID-heavy prefixes that the API sometimes prepends.\n */\nexport function getDisplayName(fileName: string): string {\n const parts = fileName.split('-');\n if (parts.length > 5) {\n const ext = fileName.split('.').pop() || '';\n return `file.${ext}`;\n }\n return fileName;\n}\n\n/**\n * Extract the hostname from a URL string. Returns the original string on error.\n */\nexport function extractDomain(url: string): string {\n try {\n return new URL(url).hostname;\n } catch {\n return url;\n }\n}\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { ForwardMessageModal } from './ForwardMessageModal';\nimport type { ChannelProps } from '../types';\n\nexport type { ChannelProps } from '../types';\n\nconst DefaultEmpty = React.memo(() => (\n <div className=\"ermis-channel__empty\">Select a channel to start chatting</div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\n/**\n * Channel wrapper component.\n *\n * Customization:\n * - `HeaderComponent` — replace default ChannelHeader with a fully custom component.\n * Receives `{ channel, name, image }` as props.\n * - `EmptyStateIndicator` — custom component when no channel is selected.\n */\nexport const Channel: React.FC<ChannelProps> = React.memo(({\n children,\n className,\n EmptyStateIndicator = DefaultEmpty,\n HeaderComponent,\n ForwardMessageModalComponent = ForwardMessageModal,\n}) => {\n const { activeChannel, client, forwardingMessage, setForwardingMessage } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n\n // Force re-render when channel info is updated via WS\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n useEffect(() => {\n\n console.log('---activeChannel--', activeChannel)\n\n if (!activeChannel) return;\n const sub = activeChannel.on('channel.updated', () => setChannelUpdateCount((c) => c + 1));\n return () => sub.unsubscribe();\n }, [activeChannel]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const headerData = useMemo(() => {\n if (!activeChannel || !HeaderComponent) return null;\n return {\n channel: activeChannel,\n name: (activeChannel.data?.name || activeChannel.cid || '') as string,\n image: activeChannel.data?.image as string | undefined,\n };\n }, [activeChannel, HeaderComponent, channelUpdateCount]);\n\n if (!activeChannel) {\n return <EmptyStateIndicator />;\n }\n\n const bannedClass = isBanned ? ' ermis-channel--banned' : '';\n const blockedClass = isBlocked ? ' ermis-channel--blocked' : '';\n\n return (\n <div className={`ermis-channel${bannedClass}${blockedClass}${className ? ` ${className}` : ''}`}>\n {HeaderComponent && headerData && <HeaderComponent {...headerData} />}\n {children}\n {forwardingMessage && (\n <ForwardMessageModalComponent\n message={forwardingMessage}\n onDismiss={() => setForwardingMessage(null)}\n />\n )}\n </div>\n );\n});\n\nChannel.displayName = 'Channel';\n\n","import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { createForwardMessagePayload } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { Modal } from './Modal';\nimport type { ForwardMessageModalProps, ForwardChannelItemProps, AvatarProps } from '../types';\n\nexport type { ForwardMessageModalProps, ForwardChannelItemProps } from '../types';\n\n/* ----------------------------------------------------------\n Default channel item row with checkbox\n ---------------------------------------------------------- */\nconst DefaultForwardChannelItem: React.FC<ForwardChannelItemProps> = React.memo(({\n channel,\n selected,\n onToggle,\n AvatarComponent,\n}) => {\n const name = (channel.data?.name || channel.cid) as string;\n const rawImage = channel.data?.image as string | undefined;\n // Parse emoji:// format → extract just the emoji for avatar fallback\n const isEmoji = rawImage?.startsWith('emoji://');\n const image = isEmoji ? undefined : rawImage;\n const emojiIcon = isEmoji ? rawImage!.replace('emoji://', '') : undefined;\n\n return (\n <div\n className={`ermis-forward-modal__channel-item ${selected ? 'ermis-forward-modal__channel-item--selected' : ''}`}\n onClick={() => onToggle(channel)}\n >\n {emojiIcon ? (\n <span className=\"ermis-forward-modal__channel-emoji\" style={{ fontSize: 24, width: 36, textAlign: 'center' }}>{emojiIcon}</span>\n ) : (\n <AvatarComponent image={image} name={name} size={36} />\n )}\n <span className=\"ermis-forward-modal__channel-name\">{name}</span>\n <div className={`ermis-forward-modal__checkbox ${selected ? 'ermis-forward-modal__checkbox--checked' : ''}`}>\n {selected && (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n )}\n </div>\n </div>\n );\n});\nDefaultForwardChannelItem.displayName = 'DefaultForwardChannelItem';\n\n/* ----------------------------------------------------------\n ForwardMessageModal\n ---------------------------------------------------------- */\nexport const ForwardMessageModal: React.FC<ForwardMessageModalProps> = ({\n message,\n onDismiss,\n ChannelItemComponent = DefaultForwardChannelItem,\n SearchInputComponent,\n}) => {\n const { client, activeChannel } = useChatClient();\n const [selectedChannels, setSelectedChannels] = useState<Set<string>>(new Set());\n const [search, setSearch] = useState('');\n const [sending, setSending] = useState(false);\n const [results, setResults] = useState<{ success: string[]; failed: string[] } | null>(null);\n const backdropRef = useRef<HTMLDivElement>(null);\n\n /* ---------- Get channels from client state (exclude topics) ---------- */\n const channels = useMemo(() => {\n return (Object.values(client.activeChannels) as Channel[]).filter(\n (ch) => ch.type !== 'topic',\n );\n }, [client.activeChannels]);\n\n /* ---------- Filter by search ---------- */\n const filteredChannels = useMemo(() => {\n if (!search.trim()) return channels;\n const q = search.toLowerCase();\n return channels.filter((ch) => {\n const name = ((ch.data?.name || ch.cid) as string).toLowerCase();\n return name.includes(q);\n });\n }, [channels, search]);\n\n /* ---------- Toggle selection ---------- */\n const toggleChannel = useCallback((channel: Channel) => {\n setSelectedChannels((prev) => {\n const next = new Set(prev);\n if (next.has(channel.cid)) {\n next.delete(channel.cid);\n } else {\n next.add(channel.cid);\n }\n return next;\n });\n }, []);\n\n /* ---------- Send forward ---------- */\n const handleSend = useCallback(async () => {\n if (!activeChannel || selectedChannels.size === 0 || sending) return;\n setSending(true);\n const success: string[] = [];\n const failed: string[] = [];\n\n for (const cid of selectedChannels) {\n const targetChannel = channels.find((c) => c.cid === cid);\n if (!targetChannel) continue;\n try {\n const forwardPayload = createForwardMessagePayload(\n message,\n targetChannel.cid as string,\n activeChannel.cid as string,\n );\n\n await activeChannel.forwardMessage(forwardPayload, {\n type: targetChannel.type,\n channelID: targetChannel.id!,\n });\n success.push((targetChannel.data?.name || targetChannel.cid) as string);\n } catch (err) {\n console.error(`Failed to forward to ${cid}`, err);\n failed.push((targetChannel.data?.name || targetChannel.cid) as string);\n }\n }\n\n setResults({ success, failed });\n setSending(false);\n\n // Auto-close after success (short delay)\n if (failed.length === 0) {\n setTimeout(() => onDismiss(), 1200);\n }\n }, [activeChannel, selectedChannels, channels, message, sending, onDismiss]);\n\n /* ---------- Keyboard / backdrop close ---------- */\n useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onDismiss();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [onDismiss]);\n\n const handleBackdropClick = useCallback((e: React.MouseEvent) => {\n if (e.target === backdropRef.current) onDismiss();\n }, [onDismiss]);\n\n /* ---------- Message preview ---------- */\n const previewText = message.text\n ? (message.text.length > 120 ? message.text.slice(0, 120) + '…' : message.text)\n : '';\n const attachmentCount = message.attachments?.length ?? 0;\n\n const footer = (\n <>\n <button className=\"ermis-forward-modal__btn ermis-forward-modal__btn--cancel\" onClick={onDismiss}>\n Cancel\n </button>\n <button\n className=\"ermis-forward-modal__btn ermis-forward-modal__btn--send\"\n onClick={handleSend}\n disabled={selectedChannels.size === 0 || sending || results !== null}\n >\n {sending ? 'Sending…' : `Forward${selectedChannels.size > 0 ? ` (${selectedChannels.size})` : ''}`}\n </button>\n </>\n );\n\n return (\n <Modal isOpen onClose={onDismiss} title=\"Forward Message\" footer={footer}>\n {/* Message preview */}\n <div className=\"ermis-forward-modal__preview\">\n <div className=\"ermis-forward-modal__preview-sender\">\n {message.user?.name || message.user_id || 'Unknown'}\n </div>\n {previewText && (\n <div className=\"ermis-forward-modal__preview-text\">{previewText}</div>\n )}\n {attachmentCount > 0 && (\n <div className=\"ermis-forward-modal__preview-attachments\">\n 📎 {attachmentCount} attachment{attachmentCount > 1 ? 's' : ''}\n </div>\n )}\n </div>\n\n {/* Search */}\n <div className=\"ermis-forward-modal__search-wrapper\">\n {SearchInputComponent ? (\n <SearchInputComponent value={search} onChange={setSearch} />\n ) : (\n <input\n className=\"ermis-forward-modal__search\"\n type=\"text\"\n placeholder=\"Search channels…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n autoFocus\n />\n )}\n </div>\n\n {/* Channel list */}\n <div className=\"ermis-forward-modal__channel-list\">\n {filteredChannels.length === 0 ? (\n <div className=\"ermis-forward-modal__empty\">No channels found</div>\n ) : (\n filteredChannels.map((ch) => (\n <ChannelItemComponent\n key={ch.cid}\n channel={ch}\n selected={selectedChannels.has(ch.cid)}\n onToggle={toggleChannel}\n AvatarComponent={Avatar}\n />\n ))\n )}\n </div>\n\n {/* Results feedback */}\n {results && (\n <div className=\"ermis-forward-modal__results\">\n {results.success.length > 0 && (\n <div className=\"ermis-forward-modal__results-success\">\n ✓ Sent to {results.success.join(', ')}\n </div>\n )}\n {results.failed.length > 0 && (\n <div className=\"ermis-forward-modal__results-failed\">\n ✗ Failed: {results.failed.join(', ')}\n </div>\n )}\n </div>\n )}\n </Modal>\n );\n};\n","import React, { useMemo, useState, useEffect, useContext } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { Avatar } from './Avatar';\nimport type { ChannelHeaderProps } from '../types';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\n\nexport type { ChannelHeaderProps } from '../types';\n\n/**\n * ChannelHeader displays the active channel's avatar and name.\n *\n * Customization:\n * - `title` / `image` — override the channel name and avatar\n * - `subtitle` — add a subtitle line (e.g. member count)\n * - `AvatarComponent` — replace the avatar\n * - `renderTitle(channel)` — fully custom title rendering\n * - `renderRight(channel)` — render content on the right side\n *\n * For a fully custom header, use `Channel`'s `HeaderComponent` prop instead.\n */\nexport const ChannelHeader: React.FC<ChannelHeaderProps> = React.memo(({\n className,\n AvatarComponent = Avatar,\n title,\n image,\n subtitle,\n renderRight,\n renderTitle,\n renderAudioCallButton,\n renderVideoCallButton,\n audioCallTitle = 'Audio Call',\n videoCallTitle = 'Video Call',\n CallBadgeComponent,\n}) => {\n const { activeChannel, client, enableCall } = useChatClient();\n const { isPending } = usePendingState(activeChannel, client.userID);\n const callContext = useContext(ErmisCallContext);\n\n const actionDisabled = isPending;\n\n // Force re-render when channel.updated WS event fires\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!activeChannel) return;\n const sub = activeChannel.on('channel.updated', () => setChannelUpdateCount(c => c + 1));\n return () => sub.unsubscribe();\n }, [activeChannel]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const channelName = useMemo(() =>\n title || activeChannel?.data?.name || activeChannel?.cid || '',\n [title, activeChannel?.data?.name, activeChannel?.cid, channelUpdateCount],\n );\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const channelImage = useMemo(() =>\n image || (activeChannel?.data?.image as string | undefined),\n [image, activeChannel?.data?.image, channelUpdateCount],\n );\n\n if (!activeChannel) return null;\n\n return (\n <div className={`ermis-channel-header${className ? ` ${className}` : ''}`}>\n <AvatarComponent image={channelImage} name={channelName} size={32} />\n\n <div className=\"ermis-channel-header__info\">\n {renderTitle ? (\n renderTitle(activeChannel)\n ) : (\n <div className=\"ermis-channel-header__name\">{channelName}</div>\n )}\n {subtitle && (\n <div className=\"ermis-channel-header__subtitle\">{subtitle}</div>\n )}\n </div>\n\n {/* renderRight exposes actionDisabled for consumers to disable UI features natively */}\n <div className=\"ermis-channel-header__actions\">\n {enableCall && callContext && activeChannel?.type === 'messaging' && !isPending && (\n <>\n {renderAudioCallButton ? (\n renderAudioCallButton(() => callContext.createCall('audio', activeChannel.cid || ''), actionDisabled)\n ) : (\n <button\n className=\"ermis-btn ermis-btn--icon\"\n disabled={actionDisabled}\n onClick={() => callContext.createCall('audio', activeChannel.cid || '')}\n title={audioCallTitle}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"></path>\n </svg>\n </button>\n )}\n \n {renderVideoCallButton ? (\n renderVideoCallButton(() => callContext.createCall('video', activeChannel.cid || ''), actionDisabled)\n ) : (\n <button\n className=\"ermis-btn ermis-btn--icon\"\n disabled={actionDisabled}\n onClick={() => callContext.createCall('video', activeChannel.cid || '')}\n title={videoCallTitle}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\"></polygon>\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n </svg>\n </button>\n )}\n </>\n )}\n {/* C8: Active call badge */}\n {enableCall && callContext && callContext.callStatus && CallBadgeComponent && (\n <CallBadgeComponent callType={callContext.callType} />\n )}\n {renderRight && renderRight(activeChannel, actionDisabled)}\n </div>\n </div>\n );\n});\n\nChannelHeader.displayName = 'ChannelHeader';\n","import React, { useState, useRef, useCallback, useMemo, useEffect } from 'react';\nimport { VList, type VListHandle } from 'virtua';\nimport type { MessageLabel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { useLoadMessages } from '../hooks/useLoadMessages';\nimport { useScrollToMessage } from '../hooks/useScrollToMessage';\nimport { useChannelMessages } from '../hooks/useChannelMessages';\nimport { useChannelProfile } from '../hooks/useChannelData';\nimport { Avatar } from './Avatar';\nimport { MessageItem } from './MessageItem';\nimport { SystemMessageItem } from './MessageItem';\nimport {\n defaultMessageRenderers,\n type MessageBubbleProps,\n} from './MessageRenderers';\nimport { getDateKey, formatDateLabel, getMessageUserId, formatReadTimestamp } from '../utils';\nimport { QuotedMessagePreview } from './QuotedMessagePreview';\nimport { PinnedMessages } from './PinnedMessages';\nimport { ReadReceipts } from './ReadReceipts';\nimport { TypingIndicator } from './TypingIndicator';\nimport type { MessageListProps } from '../types';\n\n/* ----------------------------------------------------------\n Internal sub-components\n ---------------------------------------------------------- */\nconst DefaultDateSeparator: React.FC<{ label: string }> = React.memo(({ label }) => (\n <div className=\"ermis-message-list__date-separator\">\n <div className=\"ermis-message-list__date-separator-line\" />\n <span className=\"ermis-message-list__date-separator-label\">{label}</span>\n <div className=\"ermis-message-list__date-separator-line\" />\n </div>\n));\n(DefaultDateSeparator as any).displayName = 'DefaultDateSeparator';\n\nconst DefaultJumpToLatest = React.memo(({ onClick, label = '↓ Jump to latest' }: any) => (\n <button className=\"ermis-message-list__jump-latest\" onClick={onClick}>\n {label}\n </button>\n));\nDefaultJumpToLatest.displayName = 'DefaultJumpToLatest';\n\nconst DefaultEmpty = React.memo(({ title = 'No messages yet', subtitle = 'Send a message to start the conversation' }: any) => (\n <div className=\"ermis-message-list__empty\">\n <div className=\"ermis-message-list__empty-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__empty-title\">{title}</span>\n <span className=\"ermis-message-list__empty-subtitle\">{subtitle}</span>\n </div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\nconst DefaultBubble: React.FC<MessageBubbleProps> = React.memo(({\n isOwnMessage,\n message,\n children,\n}) => (\n <div\n className={`ermis-message-bubble ${isOwnMessage ? 'ermis-message-bubble--own' : 'ermis-message-bubble--other'}`}\n >\n {message?.pinned && (\n <div className={`ermis-message-list__pinned-indicator ${isOwnMessage ? 'ermis-message-list__pinned-indicator--own' : 'ermis-message-list__pinned-indicator--other'}`}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n </div>\n )}\n {children}\n </div>\n));\n(DefaultBubble as any).displayName = 'DefaultBubble';\n\n/* ----------------------------------------------------------\n VirtualMessageList\n ---------------------------------------------------------- */\nexport const VirtualMessageList: React.FC<MessageListProps> = React.memo(({\n renderMessage,\n className,\n EmptyStateIndicator = DefaultEmpty,\n AvatarComponent = Avatar,\n MessageBubble = DefaultBubble,\n messageRenderers: customRenderers,\n loadMoreLimit = 25,\n DateSeparatorComponent = DefaultDateSeparator,\n MessageItemComponent = MessageItem,\n SystemMessageItemComponent = SystemMessageItem,\n JumpToLatestButton = DefaultJumpToLatest,\n QuotedMessagePreviewComponent = QuotedMessagePreview,\n MessageActionsBoxComponent,\n showPinnedMessages = true,\n PinnedMessagesComponent = PinnedMessages,\n showReadReceipts = true,\n ReadReceiptsComponent = ReadReceipts,\n ReadReceiptsTooltipComponent,\n readReceiptsMaxAvatars = 5,\n showTypingIndicator = true,\n TypingIndicatorComponent = TypingIndicator,\n MessageReactionsComponent,\n emptyTitle = 'No messages yet',\n emptySubtitle = 'Send a message to start the conversation',\n jumpToLatestLabel = '↓ Jump to latest',\n bannedOverlayTitle = 'You have been blocked from this channel',\n bannedOverlaySubtitle = 'You can no longer read or send messages here',\n blockedOverlayTitle = 'You have blocked this user',\n blockedOverlaySubtitle = 'Unblock to continue the conversation',\n pendingOverlayTitle = 'You are invited to this channel',\n pendingOverlaySubtitle = 'Accept the invitation to view messages and interact',\n pendingAcceptLabel = 'Accept',\n pendingRejectLabel = 'Reject',\n}) => {\n const { client, messages, readState, activeChannel, jumpToMessageId, setJumpToMessageId } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n const { isPending } = usePendingState(activeChannel, client.userID);\n\n const { channelName, channelImage } = useChannelProfile(activeChannel);\n\n const vlistRef = useRef<VListHandle>(null);\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\n const currentUserId = client.userID;\n\n // Ref to scope DOM queries (safe for multiple instances)\n const containerRef = useRef<HTMLDivElement>(null);\n const getVListElement = useCallback((): HTMLElement | null => {\n return containerRef.current?.querySelector('.ermis-message-list__vlist') ?? null;\n }, []);\n\n const handleAcceptInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n const isPublicTeam = activeChannel.type === 'team' && Boolean(activeChannel.data?.public);\n const action = isPublicTeam ? 'join' : 'accept';\n await activeChannel.acceptInvite(action);\n } catch (e: any) {\n console.error('Error accepting invite', e);\n }\n }, [activeChannel]);\n\n const handleRejectInvite = useCallback(() => {\n if (!activeChannel) return;\n activeChannel.rejectInvite().catch((e: any) => console.error('Error rejecting invite', e));\n }, [activeChannel]);\n\n const scrollToBottom = useCallback((smooth = false, attempts = 0) => {\n const handle = vlistRef.current;\n if (!handle) return;\n\n const count = messagesRef.current.length;\n if (count === 0) return;\n\n // Ensure virtua has measured the viewport via ResizeObserver.\n // If viewportSize is unmeasured (0) or scrollSize is 0, align: 'end' calculates wrong.\n if ((!handle.viewportSize || handle.viewportSize === 0) && attempts < 10) {\n requestAnimationFrame(() => scrollToBottom(smooth, attempts + 1));\n return;\n }\n\n handle.scrollToIndex(count - 1, { align: 'end', smooth });\n }, []);\n\n // Shared guard: skip scroll-triggered loads during jump transitions\n const jumpingRef = useRef(false);\n\n /* ---------- Hooks ---------- */\n const {\n shiftMode,\n hasMore, setHasMore,\n hasNewer, setHasNewer,\n loadingMoreRef, loadingNewerRef,\n handleScroll,\n isAtBottomRef,\n } = useLoadMessages({\n vlistRef,\n messagesRef,\n jumpingRef,\n loadMoreLimit,\n });\n\n const { highlightedId, scrollToMessage, jumpToLatest } = useScrollToMessage({\n vlistRef,\n messagesRef,\n setHasMore,\n setHasNewer,\n getVListElement,\n scrollToBottom,\n jumpingRef,\n });\n\n // React to jumpToMessageId from context (e.g. search panel)\n useEffect(() => {\n if (jumpToMessageId) {\n scrollToMessage(jumpToMessageId);\n setJumpToMessageId(null);\n }\n }, [jumpToMessageId, scrollToMessage, setJumpToMessageId]);\n\n useChannelMessages({\n scrollToBottom,\n jumpingRef,\n isAtBottomRef,\n onChannelSwitch: useCallback(() => {\n setHasMore(true);\n setHasNewer(false);\n loadingMoreRef.current = false;\n loadingNewerRef.current = false;\n }, [setHasMore, setHasNewer]),\n });\n\n const renderers = useMemo(\n () => ({ ...defaultMessageRenderers, ...customRenderers }),\n [customRenderers],\n );\n\n /* ---------- Compute read-by map (message.id → readers) ---------- */\n const readByMap = useMemo(() => {\n const map: Record<string, Array<{ id: string; name?: string; avatar?: string; last_read?: Date | string }>> = {};\n if (!readState) return map;\n for (const userId of Object.keys(readState)) {\n if (userId === currentUserId) continue; // exclude self\n const entry = readState[userId];\n if (entry.last_read_message_id) {\n if (!map[entry.last_read_message_id]) {\n map[entry.last_read_message_id] = [];\n }\n map[entry.last_read_message_id].push({\n id: userId,\n name: entry.user?.name,\n avatar: entry.user?.avatar,\n last_read: entry.last_read,\n });\n }\n }\n return map;\n }, [readState, currentUserId]);\n\n /* ---------- Memoized message elements ---------- */\n const messageElements = useMemo(() => {\n return messages.map((message, index) => {\n const isOwnMessage =\n message.user_id === currentUserId || message.user?.id === currentUserId;\n const messageType = (message.type || 'regular') as MessageLabel;\n\n // Date separator\n const prevMsg = index > 0 ? messages[index - 1] : null;\n const showDateSeparator =\n !prevMsg || getDateKey(message.created_at) !== getDateKey(prevMsg.created_at);\n const dateSeparator = showDateSeparator ? (\n <DateSeparatorComponent label={formatDateLabel(message.created_at)} />\n ) : null;\n\n if (renderMessage) {\n return (\n <div key={message.id || `msg-${index}`}>\n {dateSeparator}\n <div>{renderMessage(message, isOwnMessage)}</div>\n </div>\n );\n }\n\n if (messageType === 'system') {\n return (\n <div key={message.id || `msg-${index}`}>\n {dateSeparator}\n <SystemMessageItemComponent\n message={message}\n isOwnMessage={isOwnMessage}\n SystemRenderer={renderers.system}\n />\n </div>\n );\n }\n\n // Message grouping\n const prevType = (prevMsg?.type || 'regular') as MessageLabel;\n const isFirstInGroup =\n showDateSeparator ||\n !prevMsg ||\n prevType === 'system' ||\n prevType === 'signal' ||\n getMessageUserId(prevMsg) !== getMessageUserId(message);\n\n const nextMsg = index < messages.length - 1 ? messages[index + 1] : null;\n const nextType = (nextMsg?.type || 'regular') as MessageLabel;\n const nextShowDateSeparator = nextMsg\n ? getDateKey(nextMsg.created_at) !== getDateKey(message.created_at)\n : false;\n\n const isLastInGroup =\n !nextMsg ||\n nextShowDateSeparator ||\n nextType === 'system' ||\n nextType === 'signal' ||\n getMessageUserId(nextMsg) !== getMessageUserId(message);\n\n const MessageRenderer = renderers[messageType] || renderers.regular;\n\n return (\n <div key={message.id || `msg-${index}`}>\n {dateSeparator}\n <MessageItemComponent\n message={message}\n isOwnMessage={isOwnMessage}\n isFirstInGroup={isFirstInGroup}\n isLastInGroup={isLastInGroup}\n isHighlighted={highlightedId === message.id}\n AvatarComponent={AvatarComponent}\n MessageBubble={MessageBubble}\n MessageRenderer={MessageRenderer}\n onClickQuote={scrollToMessage}\n QuotedMessagePreviewComponent={QuotedMessagePreviewComponent}\n MessageActionsBoxComponent={MessageActionsBoxComponent}\n MessageReactionsComponent={MessageReactionsComponent}\n />\n {/* Read receipts — full width, right-aligned */}\n {showReadReceipts && (\n <ReadReceiptsComponent\n readers={readByMap[message.id!] || []}\n maxAvatars={readReceiptsMaxAvatars}\n AvatarComponent={AvatarComponent}\n TooltipComponent={ReadReceiptsTooltipComponent}\n isOwnMessage={isOwnMessage}\n isLastInGroup={isLastInGroup}\n status={message.status}\n />\n )}\n </div>\n );\n });\n }, [\n messages,\n currentUserId,\n highlightedId,\n renderers,\n renderMessage,\n AvatarComponent,\n MessageBubble,\n scrollToMessage,\n DateSeparatorComponent,\n MessageItemComponent,\n SystemMessageItemComponent,\n QuotedMessagePreviewComponent,\n MessageActionsBoxComponent,\n MessageReactionsComponent,\n readByMap,\n showReadReceipts,\n ReadReceiptsComponent,\n ReadReceiptsTooltipComponent,\n readReceiptsMaxAvatars,\n ]);\n\n const blockedClass = isBlocked ? ' ermis-message-list--blocked' : '';\n\n return (\n <div ref={containerRef} className={`ermis-message-list${isBanned ? ' ermis-message-list--banned' : ''}${blockedClass}${className ? ` ${className}` : ''}`}>\n {!isBanned && !isBlocked && showPinnedMessages && <PinnedMessagesComponent onClickMessage={scrollToMessage} AvatarComponent={AvatarComponent} />}\n\n {messages.length === 0 && !isBanned && !isPending && (\n EmptyStateIndicator === DefaultEmpty\n ? <DefaultEmpty title={emptyTitle} subtitle={emptySubtitle} />\n : <EmptyStateIndicator />\n )}\n\n {/* VList always rendered so virtua keeps its viewport measurement */}\n <VList\n key={activeChannel?.cid || 'empty'}\n ref={vlistRef}\n shift={shiftMode}\n onScroll={handleScroll}\n className=\"ermis-message-list__vlist\"\n >\n {isPending && !isBanned && !isBlocked ? (\n <div className=\"ermis-message-list__pending-overlay\">\n <div className=\"ermis-message-list__pending-card\">\n <Avatar image={channelImage} name={channelName} size={64} className=\"ermis-message-list__pending-avatar\" />\n <span className=\"ermis-message-list__pending-overlay-title\">{pendingOverlayTitle}</span>\n <div className=\"ermis-message-list__pending-channel-name\">{channelName}</div>\n <span className=\"ermis-message-list__pending-overlay-subtitle\">{pendingOverlaySubtitle}</span>\n <div className=\"ermis-message-list__pending-actions\">\n <button className=\"ermis-message-list__reject-btn\" onClick={handleRejectInvite}>{pendingRejectLabel}</button>\n <button className=\"ermis-message-list__accept-btn\" onClick={handleAcceptInvite}>{pendingAcceptLabel}</button>\n </div>\n </div>\n </div>\n ) : (isBanned || isBlocked) && !isPending ? (\n <div className=\"ermis-message-list__banned-overlay\">\n <div className=\"ermis-message-list__banned-overlay-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__banned-overlay-title\">{isBlocked ? blockedOverlayTitle : bannedOverlayTitle}</span>\n <span className=\"ermis-message-list__banned-overlay-subtitle\">{isBlocked ? blockedOverlaySubtitle : bannedOverlaySubtitle}</span>\n {isBlocked && activeChannel && (\n <button\n className=\"ermis-message-list__unblock-btn\"\n onClick={() => { activeChannel.unblockUser().catch((e: any) => console.error('Error unblocking user', e)); }}\n >\n Unblock\n </button>\n )}\n </div>\n ) : messageElements}\n </VList>\n\n {/* Typing indicator */}\n {!isBanned && !isBlocked && !isPending && showTypingIndicator && <TypingIndicatorComponent />}\n\n {/* Jump to latest button */}\n {!isBanned && !isBlocked && !isPending && hasNewer && (\n JumpToLatestButton === DefaultJumpToLatest\n ? <DefaultJumpToLatest onClick={jumpToLatest} label={jumpToLatestLabel} />\n : <JumpToLatestButton onClick={jumpToLatest} />\n )}\n </div>\n );\n});\n\nVirtualMessageList.displayName = 'VirtualMessageList';\n","import { useState, useRef, useCallback, useEffect } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { formatMessage } from '@ermis-network/ermis-chat-sdk';\nimport type { VListHandle } from 'virtua';\nimport { useChatClient } from './useChatClient';\n\nconst LOAD_MORE_THRESHOLD = 200;\n\n/** Filter out messages whose id already exists in `existing` (or self-dedup if omitted). */\nexport const dedupMessages = (incoming: any[], existing?: any[]) => {\n const ids = new Set(existing?.map((m) => m.id) ?? []);\n return incoming.filter((m: any) => {\n if (!m.id || ids.has(m.id)) return false;\n ids.add(m.id);\n return true;\n });\n};\n\nexport type UseLoadMessagesOptions = {\n vlistRef: React.RefObject<VListHandle | null>;\n messagesRef: React.MutableRefObject<FormatMessageResponse[]>;\n /** Shared guard ref — skip scroll-triggered loads during jump transitions */\n jumpingRef: React.MutableRefObject<boolean>;\n loadMoreLimit?: number;\n};\n\nexport type UseLoadMessagesReturn = {\n /** VList shift mode — true during prepend, auto-resets to false */\n shiftMode: boolean;\n hasMore: boolean;\n setHasMore: React.Dispatch<React.SetStateAction<boolean>>;\n hasNewer: boolean;\n setHasNewer: React.Dispatch<React.SetStateAction<boolean>>;\n hasMoreRef: React.RefObject<boolean>;\n hasNewerRef: React.RefObject<boolean>;\n loadingMoreRef: React.MutableRefObject<boolean>;\n loadingNewerRef: React.MutableRefObject<boolean>;\n loadMore: () => Promise<void>;\n loadNewer: () => Promise<void>;\n handleScroll: (offset: number) => void;\n isAtBottomRef: React.MutableRefObject<boolean>;\n};\n\nexport function useLoadMessages({\n vlistRef,\n messagesRef,\n jumpingRef,\n loadMoreLimit = 25,\n}: UseLoadMessagesOptions): UseLoadMessagesReturn {\n const { activeChannel, setMessages } = useChatClient();\n const [hasMore, setHasMore] = useState(true);\n const [hasNewer, setHasNewer] = useState(false);\n const [shiftMode, setShiftMode] = useState(false);\n\n // Auto-reset shiftMode after each prepend render\n useEffect(() => {\n if (shiftMode) {\n requestAnimationFrame(() => setShiftMode(false));\n }\n }, [shiftMode]);\n\n // Refs synced from state (avoid handleScroll recreation on state change)\n const hasMoreRef = useRef(true);\n hasMoreRef.current = hasMore;\n const hasNewerRef = useRef(false);\n hasNewerRef.current = hasNewer;\n const isAtBottomRef = useRef(true);\n\n // Concurrency guards\n const loadingMoreRef = useRef(false);\n const loadingNewerRef = useRef(false);\n\n const loadMore = useCallback(async () => {\n if (!activeChannel || loadingMoreRef.current) return;\n\n const currentMessages = messagesRef.current;\n const oldestMessage = currentMessages[0];\n if (!oldestMessage?.id) return;\n\n loadingMoreRef.current = true;\n try {\n const olderRaw = await activeChannel.queryMessagesLessThanId(oldestMessage.id, loadMoreLimit);\n\n if (olderRaw.length === 0) {\n setHasMore(false);\n return;\n }\n\n const olderFormatted = olderRaw.map((msg: any) => formatMessage(msg));\n setShiftMode(true);\n setMessages((prev) => {\n const unique = dedupMessages(olderFormatted, prev);\n if (unique.length === 0) {\n setHasMore(false);\n }\n return [...unique, ...prev];\n });\n } catch (err) {\n console.error('Failed to load more messages:', err);\n } finally {\n loadingMoreRef.current = false;\n }\n }, [activeChannel, loadMoreLimit, setMessages]);\n\n const loadNewer = useCallback(async () => {\n if (!activeChannel || loadingNewerRef.current) return;\n\n const currentMessages = messagesRef.current;\n const newestMessage = currentMessages[currentMessages.length - 1];\n if (!newestMessage?.id) return;\n\n loadingNewerRef.current = true;\n try {\n const newerRaw = await activeChannel.queryMessagesGreaterThanId(newestMessage.id, loadMoreLimit);\n\n if (newerRaw.length === 0) {\n setHasNewer(false);\n return;\n }\n\n const newerFormatted = newerRaw.map((msg: any) => formatMessage(msg));\n setMessages((prev) => {\n const unique = dedupMessages(newerFormatted, prev);\n if (unique.length === 0) {\n setHasNewer(false);\n }\n return [...prev, ...unique];\n });\n } catch (err) {\n console.error('Failed to load newer messages:', err);\n } finally {\n loadingNewerRef.current = false;\n }\n }, [activeChannel, loadMoreLimit, setMessages]);\n\n const handleScroll = useCallback(\n (offset: number) => {\n if (jumpingRef.current) return;\n const handle = vlistRef.current;\n if (!handle) return;\n const { scrollSize, viewportSize } = handle;\n\n const isBottom = Math.ceil(offset + viewportSize) >= scrollSize - 20;\n isAtBottomRef.current = isBottom;\n\n // Skip if content doesn't fill the viewport\n if (scrollSize <= viewportSize) {\n isAtBottomRef.current = true;\n return;\n }\n\n if (offset <= LOAD_MORE_THRESHOLD && hasMoreRef.current) {\n loadMore();\n }\n\n if (offset + viewportSize >= scrollSize - LOAD_MORE_THRESHOLD && hasNewerRef.current) {\n loadNewer();\n }\n },\n [loadMore, loadNewer],\n );\n\n return {\n shiftMode,\n hasMore,\n setHasMore,\n hasNewer,\n setHasNewer,\n hasMoreRef,\n hasNewerRef,\n loadingMoreRef,\n loadingNewerRef,\n loadMore,\n loadNewer,\n handleScroll,\n isAtBottomRef,\n };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { formatMessage } from '@ermis-network/ermis-chat-sdk';\nimport type { VListHandle } from 'virtua';\nimport { dedupMessages } from './useLoadMessages';\nimport { useChatClient } from './useChatClient';\n\nexport type UseScrollToMessageOptions = {\n vlistRef: React.RefObject<VListHandle | null>;\n messagesRef: React.MutableRefObject<FormatMessageResponse[]>;\n setHasMore: React.Dispatch<React.SetStateAction<boolean>>;\n setHasNewer: React.Dispatch<React.SetStateAction<boolean>>;\n /** Getter to access the VList DOM element (scoped to container) */\n getVListElement: () => HTMLElement | null;\n scrollToBottom: (smooth: boolean) => void;\n /** Shared guard ref — blocks scroll-triggered loads during jumps */\n jumpingRef: React.MutableRefObject<boolean>;\n};\n\nexport type UseScrollToMessageReturn = {\n highlightedId: string | null;\n scrollToMessage: (messageId: string) => void;\n jumpToLatest: () => void;\n};\n\nexport function useScrollToMessage({\n vlistRef,\n messagesRef,\n setHasMore,\n setHasNewer,\n getVListElement,\n scrollToBottom,\n jumpingRef,\n}: UseScrollToMessageOptions): UseScrollToMessageReturn {\n const { activeChannel, setMessages } = useChatClient();\n const [highlightedId, setHighlightedId] = useState<string | null>(null);\n const highlightTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Cleanup highlight timer on unmount\n useEffect(() => {\n return () => {\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n };\n }, []);\n\n const highlight = useCallback((messageId: string) => {\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n setHighlightedId(messageId);\n highlightTimerRef.current = setTimeout(() => {\n setHighlightedId(null);\n highlightTimerRef.current = null;\n }, 2500);\n }, []);\n\n const scrollToMessage = useCallback(\n async (messageId: string) => {\n // Prevent concurrent calls\n if (jumpingRef.current) return;\n\n // Case 1: message is already in current list\n const idx = messagesRef.current.findIndex((m) => m.id === messageId);\n if (idx !== -1) {\n vlistRef.current?.scrollToIndex(idx, { align: 'center', smooth: true });\n highlight(messageId);\n return;\n }\n\n // Case 2: message NOT in list — fetch around it\n if (!activeChannel) return;\n\n jumpingRef.current = true;\n\n const vlistEl = getVListElement();\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 150ms ease-out';\n vlistEl.style.opacity = '0';\n }\n\n try {\n const rawMessages = await activeChannel.queryMessagesAroundId(messageId, 25);\n if (!rawMessages || rawMessages.length === 0) {\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n return;\n }\n\n const formatted = rawMessages.map((msg: any) => formatMessage(msg));\n const unique = dedupMessages(formatted);\n\n setHasMore(true);\n setHasNewer(true);\n setMessages(unique);\n\n // Wait for VList to render, then jump while hidden, then fade in\n setTimeout(() => {\n const newIdx = unique.findIndex((m: any) => m.id === messageId);\n if (newIdx === -1) {\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n return;\n }\n\n vlistRef.current?.scrollToIndex(newIdx, { align: 'center' });\n\n setTimeout(() => {\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 200ms ease-in';\n vlistEl.style.opacity = '1';\n }\n highlight(messageId);\n setTimeout(() => {\n jumpingRef.current = false;\n }, 500);\n }, 100);\n }, 200);\n } catch (err) {\n console.error('Failed to fetch messages around ID:', err);\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n }\n },\n [activeChannel, highlight, setMessages, setHasMore, setHasNewer, getVListElement],\n );\n\n const jumpToLatest = useCallback(() => {\n if (!activeChannel) return;\n jumpingRef.current = true;\n\n const vlistEl = getVListElement();\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 150ms ease-out';\n vlistEl.style.opacity = '0';\n }\n\n const latestMsgs = [...activeChannel.state.latestMessages];\n setMessages(latestMsgs);\n setHasNewer(false);\n setHasMore(true);\n\n setTimeout(() => {\n scrollToBottom(false);\n setTimeout(() => {\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 200ms ease-in';\n vlistEl.style.opacity = '1';\n }\n setTimeout(() => {\n jumpingRef.current = false;\n }, 500);\n }, 100);\n }, 200);\n }, [activeChannel, scrollToBottom, getVListElement, setMessages, setHasMore, setHasNewer]);\n\n return { highlightedId, scrollToMessage, jumpToLatest };\n}\n","import { useEffect, useCallback } from 'react';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\n\nexport type UseChannelMessagesOptions = {\n scrollToBottom: (smooth: boolean) => void;\n /** Shared guard ref — blocks scroll-triggered loads during channel switch */\n jumpingRef: React.MutableRefObject<boolean>;\n isAtBottomRef: React.MutableRefObject<boolean>;\n /** Called to reset load-more state when channel switches */\n onChannelSwitch?: () => void;\n};\n\n/**\n * Schedule multiple scroll-to-bottom attempts with increasing delays.\n * Handles content that changes height after initial render (images, embeds).\n */\nconst SCROLL_DELAYS = [50, 200, 500, 1000];\n\n/**\n * Subscribes to channel message events and handles:\n * - message.new → sync + scroll to bottom\n * - message.updated / message.deleted → sync only\n * - Channel switch → reset state + scroll to bottom\n */\nexport function useChannelMessages({\n scrollToBottom,\n jumpingRef,\n isAtBottomRef,\n onChannelSwitch,\n}: UseChannelMessagesOptions): void {\n const { client, activeChannel, syncMessages, setReadState } = useChatClient();\n\n const scheduleScrollToBottom = useCallback(\n (smooth: boolean) => {\n if (smooth) {\n // Trigger smooth scroll exactly once, otherwise browsers will\n // cancel the smooth animation if called multiple times in a row\n setTimeout(() => scrollToBottom(true), 100);\n } else {\n SCROLL_DELAYS.forEach((delay) => {\n setTimeout(() => scrollToBottom(false), delay);\n });\n }\n },\n [scrollToBottom],\n );\n\n useEffect(() => {\n if (!activeChannel) return;\n\n // Reset state for the new channel\n onChannelSwitch?.();\n\n // Manually force isAtBottom to true because we are jumping to the bottom.\n // jumpingRef blocks the resulting scroll event from updating isAtBottomRef,\n // so if it was false in the previous channel, it would stay false!\n isAtBottomRef.current = true;\n\n // Block scroll triggers during channel-switch scroll\n jumpingRef.current = true;\n // Defer scroll outside React lifecycle to avoid virtua flushSync warning\n setTimeout(() => {\n scrollToBottom(false);\n // Wait long enough for scrollToBottom's internal retries and the browser\n // to execute the scroll event\n setTimeout(() => {\n jumpingRef.current = false;\n }, 100);\n }, 0);\n\n const handleNewMessage = (event: Event) => {\n // Capture scroll state BEFORE sync causes re-render\n const wasAtBottom = isAtBottomRef.current;\n\n syncMessages();\n\n const isOwnMessage = event.message?.user?.id === client.userID || event.message?.user_id === client.userID;\n\n if (isOwnMessage || wasAtBottom) {\n scheduleScrollToBottom(true);\n }\n };\n\n const handleMessageChange = (_event: Event) => {\n syncMessages();\n };\n\n const handleMessageRead = (_event: Event) => {\n // SDK already updated channel.state.read — sync into React state\n setReadState({ ...activeChannel.state.read });\n };\n\n const handleUnblocked = (event: Event) => {\n // If the current user's block status was updated (meaning we unblocked someone)\n if (event.member?.user_id === client.userID) {\n // Refetch latest messages to fill in any missed during the block period\n activeChannel\n .query({ messages: { limit: 30 } })\n .then(() => {\n syncMessages();\n scheduleScrollToBottom(false);\n const isPending =\n activeChannel.state?.membership?.channel_role === 'pending' ||\n (activeChannel.state?.membership as any)?.role === 'pending';\n if (!isPending) {\n activeChannel.markRead().catch(() => {});\n }\n })\n .catch((e) => console.error('Failed to sync messages after unblock', e));\n }\n };\n\n const handleInviteAccepted = (event: Event) => {\n // Make sure the accepted invite corresponds to the actively opened channel\n const eventCid =\n event.cid ||\n event.channel?.cid ||\n ((event as any).channel_id ? `${(event as any).channel_type}:${(event as any).channel_id}` : undefined);\n if (eventCid === activeChannel.cid) {\n activeChannel\n .query({ messages: { limit: 30 } })\n .then(() => {\n syncMessages();\n scheduleScrollToBottom(false);\n activeChannel.markRead().catch(() => {});\n })\n .catch((e) => console.error('Failed to sync messages after accepting invite', e));\n }\n };\n\n const client = activeChannel.getClient();\n const sub1 = activeChannel.on('message.new', handleNewMessage);\n const sub2 = activeChannel.on('message.updated', handleMessageChange);\n const sub3 = activeChannel.on('message.deleted', handleMessageChange);\n const sub4 = activeChannel.on('message.pinned', handleMessageChange);\n const sub5 = activeChannel.on('message.unpinned', handleMessageChange);\n const sub6 = activeChannel.on('message.read', handleMessageRead);\n const sub7 = activeChannel.on('message.deleted_for_me', handleMessageChange);\n const sub8 = activeChannel.on('reaction.new', handleMessageChange);\n const sub9 = activeChannel.on('reaction.deleted', handleMessageChange);\n const sub10 = activeChannel.on('member.unblocked', handleUnblocked);\n const sub11 = client.on('notification.invite_accepted', handleInviteAccepted);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n };\n }, [activeChannel, scrollToBottom, scheduleScrollToBottom, syncMessages, onChannelSwitch, setReadState]);\n}\n","import { useState, useEffect, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\nexport const useChannelMembers = (channel: Channel | null | undefined) => {\n const [memberUpdateCount, setMemberUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!channel) return;\n const updateMembers = () => setMemberUpdateCount(c => c + 1);\n\n const sub1 = channel.on('member.added', updateMembers);\n const sub2 = channel.on('member.removed', updateMembers);\n const sub3 = channel.on('member.updated', updateMembers);\n const sub4 = channel.on('member.promoted', updateMembers);\n const sub5 = channel.on('member.demoted', updateMembers);\n const sub6 = channel.on('member.banned', updateMembers);\n const sub7 = channel.on('member.unbanned', updateMembers);\n const sub8 = channel.on('notification.invite_rejected', updateMembers);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n };\n }, [channel]);\n\n const membersArray = useMemo(() => {\n if (!channel?.state?.members) return [];\n return Object.values(channel.state.members) as Array<Record<string, unknown>>;\n }, [channel?.state?.members, memberUpdateCount]);\n\n return { members: membersArray, memberUpdateCount };\n};\n\nexport const useChannelProfile = (channel: Channel | null | undefined) => {\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!channel) return;\n const updateChannel = () => setChannelUpdateCount(c => c + 1);\n const sub = channel.on('channel.updated', updateChannel);\n return () => sub.unsubscribe();\n }, [channel]);\n\n const channelName = useMemo(() => channel?.data?.name || channel?.cid || 'Unknown Channel', [channel?.data?.name, channel?.cid, channelUpdateCount]);\n const channelImage = useMemo(() => channel?.data?.image as string | undefined, [channel?.data?.image, channelUpdateCount]);\n const channelDescription = useMemo(() => channel?.data?.description as string | undefined, [channel?.data?.description, channelUpdateCount]);\n\n return { channelName, channelImage, channelDescription };\n};\n","import React from 'react';\nimport type { MessageItemProps, SystemMessageItemProps } from '../types';\nimport { QuotedMessagePreview } from './QuotedMessagePreview';\nimport { MessageActionsBox } from './MessageActionsBox';\nimport { MessageReactions } from './MessageReactions';\nimport { MessageQuickReactions } from './MessageQuickReactions';\nimport { useChannelCapabilities } from '../hooks/useChannelCapabilities';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { formatTime } from '../utils';\n\nexport type { MessageItemProps, SystemMessageItemProps } from '../types';\n\n/* ----------------------------------------------------------\n MessageItem — single regular/signal message row\n ---------------------------------------------------------- */\n/* Inline status icon for own messages (sent / sending / error) */\nconst InlineStatusIcon: React.FC<{ status?: string; isOwnMessage: boolean; isLastInGroup: boolean }> = React.memo(({\n status,\n isOwnMessage,\n isLastInGroup,\n}) => {\n if (!isOwnMessage) return null;\n\n const isError = status === 'error' || status === 'failed_offline';\n if (!isLastInGroup && !isError) return null;\n\n if (isError) {\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--failed\" title=\"Failed to send\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line>\n </svg>\n </span>\n );\n }\n\n if (status === 'sending') {\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--sending\" title=\"Sending...\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <polyline points=\"12 6 12 12 16 14\"></polyline>\n </svg>\n </span>\n );\n }\n\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--sent\" title=\"Sent\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n </span>\n );\n});\nInlineStatusIcon.displayName = 'InlineStatusIcon';\n\nexport const MessageItem: React.FC<MessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n isFirstInGroup,\n isLastInGroup,\n isHighlighted,\n AvatarComponent,\n MessageBubble,\n MessageRenderer,\n onClickQuote,\n QuotedMessagePreviewComponent = QuotedMessagePreview,\n MessageActionsBoxComponent = MessageActionsBox,\n MessageReactionsComponent = MessageReactions,\n forwardedLabel = 'Forwarded',\n editedLabel = 'Edited',\n}) => {\n const { activeChannel, client } = useChatClient();\n const { hasCapability } = useChannelCapabilities();\n \n const canReact = hasCapability('send-reaction');\n\n const userName = message.user?.name || message.user_id;\n const userAvatar = message.user?.avatar;\n\n const quotedMessage = (message as any).quoted_message;\n const isForwarded = !!(message as any).forward_cid;\n const oldTexts = (message as any).old_texts;\n const isEdited = oldTexts && oldTexts.length > 0;\n const hasAttachments = message.attachments && message.attachments.length > 0;\n\n const handleReactionToggle = React.useCallback(async (type: string) => {\n if (!activeChannel || !canReact) return;\n const currentUserId = client?.userID;\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some((r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId));\n\n try {\n if (isOwn) {\n await activeChannel.deleteReaction(message.id!, type);\n } else {\n await activeChannel.sendReaction(message.id!, type);\n }\n } catch (err) {\n console.error('Failed to toggle reaction', err);\n }\n }, [activeChannel, message, client?.userID]);\n\n const statusClass =\n message.status === 'sending'\n ? 'ermis-message--sending'\n : (message.status === 'error' || message.status === 'failed_offline')\n ? 'ermis-message--error'\n : '';\n\n const isNewMessage = React.useMemo(() => {\n if (!message.created_at) return false;\n return Date.now() - new Date(message.created_at).getTime() < 1000;\n }, [message.created_at]);\n\n const itemClass = [\n 'ermis-message-list__item',\n isOwnMessage ? 'ermis-message-list__item--own' : 'ermis-message-list__item--other',\n isFirstInGroup ? 'ermis-message-list__item--group-start' : 'ermis-message-list__item--group-cont',\n isHighlighted ? 'ermis-message-list__item--highlighted' : '',\n isNewMessage ? 'ermis-message-list__item--new' : '',\n statusClass,\n ].filter(Boolean).join(' ');\n\n const contentClass = [\n 'ermis-message-list__item-content',\n hasAttachments ? 'ermis-message-list__item-content--has-attachments' : '',\n ].filter(Boolean).join(' ');\n\n return (\n <div className={itemClass} data-message-id={message.id}>\n {/* Avatar area: show avatar only on first message, otherwise placeholder for alignment */}\n {!isOwnMessage && (\n <div className=\"ermis-message-list__item-avatar\">\n {isFirstInGroup\n ? <AvatarComponent image={userAvatar} name={userName} size={28} />\n : <div style={{ width: 28 }} />\n }\n </div>\n )}\n <div className={contentClass}>\n {!isOwnMessage && isFirstInGroup && (\n <span className=\"ermis-message-list__item-user\">{userName}</span>\n )}\n {/* Quoted message preview */}\n {quotedMessage && onClickQuote && (\n <QuotedMessagePreviewComponent\n quotedMessage={quotedMessage}\n isOwnMessage={isOwnMessage}\n onClick={onClickQuote}\n />\n )}\n <div className=\"ermis-message-list__bubble-wrapper\">\n <div style={!canReact ? { opacity: 0.5, pointerEvents: 'none' } : {}}>\n <MessageQuickReactions message={message} isOwnMessage={isOwnMessage} />\n </div>\n <MessageBubble message={message} isOwnMessage={isOwnMessage}>\n {isForwarded && (\n <span className=\"ermis-message-list__forwarded-indicator\">{forwardedLabel}</span>\n )}\n <MessageRenderer message={message} isOwnMessage={isOwnMessage} />\n <span className=\"ermis-message-list__item-time\">\n {isEdited && (\n <span\n className=\"ermis-message-list__edited-indicator\"\n // data-tooltip={oldTexts.map((ot: any) => `[${formatTime(ot.created_at)}] ${ot.text}`).join('\\n')}\n >\n {editedLabel}\n </span>\n )}\n {formatTime(message.created_at)}\n <InlineStatusIcon status={message.status} isOwnMessage={isOwnMessage} isLastInGroup={isLastInGroup} />\n </span>\n </MessageBubble>\n\n {/* Actions: hover buttons + dropdown menu */}\n {message.type !== 'system' && (\n <MessageActionsBoxComponent\n message={message}\n isOwnMessage={isOwnMessage}\n />\n )}\n\n {/* Message Reactions */}\n {MessageReactionsComponent && (\n <div style={!canReact ? { opacity: 0.8, pointerEvents: 'none' } : {}}>\n <MessageReactionsComponent\n reactionCounts={(message as any).reaction_counts}\n ownReactions={(message as any).own_reactions}\n latestReactions={(message as any).latest_reactions}\n onClickReaction={handleReactionToggle}\n />\n </div>\n )}\n </div>\n </div>\n </div>\n );\n});\nMessageItem.displayName = 'MessageItem';\n\n/* ----------------------------------------------------------\n SystemMessageItem — system/notification message row\n ---------------------------------------------------------- */\nexport const SystemMessageItem: React.FC<SystemMessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n SystemRenderer,\n}) => (\n <div className=\"ermis-message-list__system\">\n <SystemRenderer message={message} isOwnMessage={isOwnMessage} />\n </div>\n));\nSystemMessageItem.displayName = 'SystemMessageItem';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { QuotedMessagePreviewProps } from '../types';\n\nexport type { QuotedMessagePreviewProps } from '../types';\n\nconst MAX_PREVIEW_LENGTH = 100;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\nexport const QuotedMessagePreview: React.FC<QuotedMessagePreviewProps> = React.memo(({\n quotedMessage,\n isOwnMessage,\n onClick,\n}) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const authorName = quotedMessage.user?.name || quotedMessage.user?.id || 'Unknown';\n \n const rawText = quotedMessage.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, quotedMessage as any, userMap), [rawText, quotedMessage, userMap]);\n \n const previewText = formattedText\n ? truncateText(formattedText, MAX_PREVIEW_LENGTH)\n : 'Attachment';\n\n const handleClick = () => {\n onClick(quotedMessage.id);\n };\n\n return (\n <div\n className={`ermis-quoted-message ${isOwnMessage ? 'ermis-quoted-message--own' : ''}`}\n onClick={handleClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleClick();\n }}\n >\n <span className=\"ermis-quoted-message__author\">{authorName}</span>\n <span className=\"ermis-quoted-message__text\">{previewText}</span>\n </div>\n );\n});\n\nQuotedMessagePreview.displayName = 'QuotedMessagePreview';\n","import React, { useCallback } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { useMessageActions } from '../hooks/useMessageActions';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { MessageActionsBoxProps } from '../types';\nimport { Dropdown, closeAllDropdowns } from './Dropdown';\n\n// Aliased for backward compatibility\nexport const closeAllActionBoxes = closeAllDropdowns;\n\nexport const MessageActionsBox: React.FC<MessageActionsBoxProps> = ({\n message,\n isOwnMessage,\n onReply: onReplyProp,\n onForward,\n onPinToggle,\n onEdit,\n onCopy,\n onDelete,\n onDeleteForMe,\n pinLabel = 'Pin',\n unpinLabel = 'Unpin',\n editLabel = 'Edit',\n copyLabel = 'Copy',\n deleteForMeLabel = 'Delete for me',\n deleteForEveryoneLabel = 'Delete for everyone',\n}) => {\n const { setQuotedMessage, setEditingMessage, setForwardingMessage, activeChannel } = useChatClient();\n const [anchorRect, setAnchorRect] = React.useState<DOMRect | null>(null);\n const actions = useMessageActions(message, isOwnMessage);\n\n // Default handlers\n const onReply = onReplyProp ?? ((msg: FormatMessageResponse) => setQuotedMessage(msg));\n const onForwardHandler = onForward ?? ((msg: FormatMessageResponse) => setForwardingMessage(msg));\n const onPinToggleHandler = onPinToggle ?? (async (msg: FormatMessageResponse, isPinned: boolean) => {\n if (!activeChannel) return;\n try {\n if (isPinned) {\n await activeChannel.unpinMessage(msg.id!);\n } else {\n await activeChannel.pinMessage(msg.id!);\n }\n } catch (err) {\n console.error('Failed to toggle pin', err);\n }\n });\n const onEditHandler = onEdit ?? ((msg: FormatMessageResponse) => setEditingMessage(msg));\n\n const onDeleteForEveryoneHandler = onDelete ?? (async (msg: FormatMessageResponse) => {\n if (!activeChannel) return;\n try {\n await activeChannel.deleteMessage(msg.id!);\n } catch (err) {\n console.error('Failed to delete message', err);\n }\n });\n\n const onDeleteForMeHandler = onDeleteForMe ?? (async (msg: FormatMessageResponse) => {\n if (!activeChannel) return;\n try {\n await activeChannel.deleteMessageForMe(msg.id!);\n } catch (err) {\n console.error('Failed to delete message for me', err);\n }\n });\n\n const isOpen = anchorRect !== null;\n const onClose = useCallback(() => setAnchorRect(null), []);\n\n const handleMoreClick = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n setAnchorRect(rect);\n };\n\n const handleCopy = async () => {\n if (onCopy) {\n onCopy(message);\n } else if (message.text) {\n try {\n await navigator.clipboard.writeText(message.text);\n } catch (err) {\n console.error('Failed to copy text:', err);\n }\n }\n onClose();\n };\n\n return (\n <>\n <div className={`ermis-message-list__actions ${isOpen ? 'ermis-message-list__actions--active' : ''}`}>\n {actions.canReply && (\n <button \n className=\"ermis-message-list__actions-trigger\" \n onClick={() => onReply?.(message)} \n title=\"Reply\"\n disabled={!actions.hasCapReply}\n >\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M11.192 15.757c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L9.373 5c-1.368.647-2.525 1.612-3.468 2.895-.943 1.28-1.452 2.673-1.526 4.174-.015.228-.022.463-.022.705 0 1.594.417 2.9 1.25 3.918.835 1.019 1.955 1.53 3.36 1.53 1.048 0 1.903-.311 2.565-.933.66-.622.99-1.465.99-2.53zm10.455 0c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L19.828 5c-1.368.647-2.525 1.612-3.468 2.895-.943 1.28-1.452 2.673-1.526 4.174-.015.228-.022.463-.022.705 0 1.594.417 2.9 1.25 3.918.835 1.019 1.954 1.53 3.36 1.53 1.048 0 1.903-.311 2.565-.933.66-.622.99-1.465.99-2.53z\" />\n </svg>\n </button>\n )}\n {actions.canForward && (\n <button \n className=\"ermis-message-list__actions-trigger\" \n onClick={() => onForwardHandler(message)} \n title=\"Forward\"\n disabled={!actions.hasCapQuote}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 14 20 9 15 4\" />\n <path d=\"M4 20v-7a4 4 0 0 1 4-4h12\" />\n </svg>\n </button>\n )}\n <button\n className={`ermis-message-list__actions-trigger ${isOpen ? 'ermis-message-list__actions-trigger--active' : ''}`}\n onClick={handleMoreClick}\n title=\"More actions\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </button>\n </div>\n\n <Dropdown \n isOpen={isOpen} \n anchorRect={anchorRect} \n onClose={onClose} \n align={isOwnMessage ? 'right' : 'left'}\n >\n <div className=\"ermis-dropdown__menu\">\n {actions.canPin && (\n <button \n className=\"ermis-dropdown__item\" \n onClick={() => { onPinToggleHandler(message, actions.isPinned); onClose(); }}\n disabled={!actions.hasCapPin}\n >\n {actions.isPinned ? unpinLabel : pinLabel}\n </button>\n )}\n {actions.canEdit && (\n <button \n className=\"ermis-dropdown__item\" \n onClick={() => { onEditHandler(message); onClose(); }}\n disabled={!actions.hasCapEdit}\n >\n {editLabel}\n </button>\n )}\n {actions.canCopy && (\n <button className=\"ermis-dropdown__item\" onClick={handleCopy}>\n {copyLabel}\n </button>\n )}\n\n {(actions.canDelete || actions.canDeleteForMe) && <div className=\"ermis-dropdown__divider\" />}\n\n {actions.canDeleteForMe && (\n <button \n className=\"ermis-dropdown__item ermis-dropdown__item--danger\" \n onClick={() => { onDeleteForMeHandler(message); onClose(); }}\n disabled={!actions.hasCapDeleteForMe}\n >\n {deleteForMeLabel}\n </button>\n )}\n {actions.canDelete && (\n <button \n className=\"ermis-dropdown__item ermis-dropdown__item--danger\" \n onClick={() => { onDeleteForEveryoneHandler(message); onClose(); }}\n disabled={!actions.hasCapDelete}\n >\n {deleteForEveryoneLabel}\n </button>\n )}\n </div>\n </Dropdown>\n </>\n );\n};\n","import { useMemo } from 'react';\nimport { useChatClient } from './useChatClient';\nimport { useChannelCapabilities } from './useChannelCapabilities';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\n\nexport type MessageActionList = {\n canEdit: boolean;\n canDelete: boolean;\n canDeleteForMe: boolean;\n canReply: boolean;\n canQuote: boolean;\n canForward: boolean;\n canPin: boolean;\n canCopy: boolean;\n isPinned: boolean;\n hasCapEdit: boolean;\n hasCapDelete: boolean;\n hasCapDeleteForMe: boolean;\n hasCapPin: boolean;\n hasCapReply: boolean;\n hasCapQuote: boolean;\n};\n\nexport const useMessageActions = (message: FormatMessageResponse, isOwnMessage: boolean): MessageActionList => {\n const { activeChannel, client } = useChatClient();\n const { isTeamChannel: isTeam, isOwner, hasCapability } = useChannelCapabilities();\n\n // Only depend on the specific message fields we actually read\n const messageType = message.type;\n const isPinnedFlag = message.pinned || !!message.pinned_at;\n\n return useMemo(() => {\n if (!activeChannel) {\n return {\n canEdit: false,\n canDelete: false,\n canDeleteForMe: false,\n canReply: false,\n canQuote: false,\n canForward: false,\n canPin: false,\n canCopy: false,\n isPinned: false,\n hasCapEdit: false,\n hasCapDelete: false,\n hasCapDeleteForMe: false,\n hasCapPin: false,\n hasCapReply: false,\n hasCapQuote: false,\n };\n }\n\n const isSystem = messageType === 'system';\n const isSignal = messageType === 'signal';\n const isPinned = isPinnedFlag;\n\n const canEdit = !isSystem && !isSignal && isOwnMessage;\n \n // Delete for everyone:\n // + Team channel: only the owner can perform this action natively.\n // + Messaging channel: only own messages can be deleted\n const canDeleteForEveryoneTeam = isTeam && isOwner;\n const canDeleteForEveryoneMessaging = !isTeam && isOwnMessage;\n \n const canDelete = !isSystem && (canDeleteForEveryoneTeam || canDeleteForEveryoneMessaging);\n const canDeleteForMe = !isSystem;\n const canReply = !isSystem && !isSignal;\n const canQuote = !isSystem && !isSignal;\n const canForward = !isSystem && !isSignal;\n const canPin = !isSystem && !isSignal;\n const canCopy = !isSystem && !isSignal && Boolean(message.text?.trim());\n\n const hasCapEdit = hasCapability('update-own-message');\n const hasCapDelete = !isTeam || isOwner || (isOwnMessage && hasCapability('delete-own-message'));\n // Apply the delete-own-message capability to the \"delete for me\" action for own messages\n const hasCapDeleteForMe = !isTeam || isOwner || !isOwnMessage || hasCapability('delete-own-message');\n \n const hasCapReply = hasCapability('send-reply');\n const hasCapQuote = hasCapability('quote-message');\n const hasCapPin = hasCapability('pin-message');\n\n return { \n canEdit, canDelete, canDeleteForMe, canReply, canQuote, canForward, canPin, canCopy, isPinned,\n hasCapEdit, hasCapDelete, hasCapDeleteForMe, hasCapPin, hasCapReply, hasCapQuote \n };\n }, [activeChannel, isTeam, isOwner, hasCapability, messageType, message.text, isPinnedFlag, isOwnMessage]); // Use capabilities from hook\n};\n","import { useState, useEffect, useCallback } from 'react';\nimport { useChatClient } from './useChatClient';\n\nexport const useChannelCapabilities = () => {\n const { activeChannel, client } = useChatClient();\n const [updateTick, setUpdateTick] = useState(0);\n\n // Real-time synchronization for channel adjustments\n useEffect(() => {\n if (!activeChannel) return;\n const handleUpdate = () => setUpdateTick(t => t + 1);\n \n activeChannel.on('channel.updated', handleUpdate);\n return () => {\n activeChannel.off('channel.updated', handleUpdate);\n };\n }, [activeChannel]);\n\n const currentUserId = client?.userID || '';\n const isTeamChannel = activeChannel?.type === 'team';\n const role = (activeChannel?.state as any)?.members?.[currentUserId]?.channel_role;\n \n const isOwner = role === 'owner' || activeChannel?.data?.created_by_id === currentUserId;\n const isModerator = role === 'moder';\n const isOwnerOrModerator = isOwner || isModerator;\n\n const capabilities: string[] = isTeamChannel ? (activeChannel?.data as any)?.member_capabilities || [] : [];\n\n const hasCapability = useCallback((cap: string) => {\n return !isTeamChannel || isOwnerOrModerator || capabilities.includes(cap);\n }, [isTeamChannel, isOwnerOrModerator, capabilities, updateTick]); // React to updateTick correctly\n\n return {\n isTeamChannel,\n isOwner,\n isModerator,\n isOwnerOrModerator,\n hasCapability,\n role,\n capabilities\n };\n};\n","import React, { useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\n\n// Global event name used to close any other open dropdowns\nconst CLOSE_ALL_EVENT = 'ermis:close-all-dropdowns';\n\n/** Dispatch a global event to close all open dropdowns */\nexport const closeAllDropdowns = () => {\n document.dispatchEvent(new CustomEvent(CLOSE_ALL_EVENT));\n};\n\nexport interface DropdownProps {\n /** Whether the dropdown is open */\n isOpen: boolean;\n /** Rect from getBoundingClientRect() of the anchor element */\n anchorRect: DOMRect | null;\n /** Callback when dropdown requests to close (e.g., click outside, scroll, Escape) */\n onClose: () => void;\n /** Dropdown menu content */\n children: React.ReactNode;\n /** Horizontal alignment relative to the anchor. Default: 'left' */\n align?: 'left' | 'right';\n /** Optional custom CSS class for the container */\n className?: string;\n /** Optional custom CSS style for the container */\n style?: React.CSSProperties;\n}\n\nexport const Dropdown: React.FC<DropdownProps> = ({\n isOpen,\n anchorRect,\n onClose,\n children,\n align = 'left',\n className = '',\n style: propStyle = {},\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const instanceId = useRef(Math.random().toString(36).slice(2));\n\n // Listen for global close event — only register when open to avoid N listeners\n useEffect(() => {\n if (!isOpen) return;\n\n // Broadcast: close all OTHER open dropdowns\n document.dispatchEvent(new CustomEvent(CLOSE_ALL_EVENT, { detail: instanceId.current }));\n\n const handleGlobalClose = (e: Event) => {\n const detail = (e as CustomEvent).detail;\n if (!detail || detail !== instanceId.current) {\n onClose();\n }\n };\n\n const handleClickOutside = (e: MouseEvent) => {\n // Allow the click to process if it's on a trigger button so it can toggle itself\n // We rely on the trigger stopping propagation or using the global close event.\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n\n const handleScroll = () => onClose();\n\n // Delay click listener to prevent instant close from the opening click\n const tid = setTimeout(() => {\n document.addEventListener('click', handleClickOutside);\n }, 10);\n\n document.addEventListener(CLOSE_ALL_EVENT, handleGlobalClose);\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('scroll', handleScroll, true);\n\n return () => {\n clearTimeout(tid);\n document.removeEventListener(CLOSE_ALL_EVENT, handleGlobalClose);\n document.removeEventListener('click', handleClickOutside);\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('scroll', handleScroll, true);\n };\n }, [isOpen, onClose]);\n\n if (!isOpen || !anchorRect) return null;\n\n const spaceBelow = window.innerHeight - anchorRect.bottom;\n const spaceAbove = anchorRect.top;\n const estimatedDropdownHeight = 250;\n\n let verticalStyle: React.CSSProperties = {};\n if (spaceBelow < estimatedDropdownHeight && spaceAbove > spaceBelow) {\n // Open upwards (bottom-aligned to the top of the trigger)\n verticalStyle = { bottom: window.innerHeight - anchorRect.top + 4 };\n } else {\n // Open downwards\n verticalStyle = { top: anchorRect.bottom + 4 };\n }\n\n const style: React.CSSProperties = {\n position: 'fixed',\n zIndex: 99999,\n ...verticalStyle,\n ...(align === 'right'\n ? { right: window.innerWidth - anchorRect.right }\n : { left: anchorRect.left }),\n ...propStyle\n };\n\n const portalTarget = document.querySelector('.ermis-chat') || document.body;\n\n return createPortal(\n <div ref={containerRef} className={`ermis-dropdown ${className}`.trim()} style={style}>\n {children}\n </div>,\n portalTarget\n );\n};\n","import React from 'react';\nimport type { MessageReactionsProps } from '../types';\n\nimport { useChatClient } from '../hooks/useChatClient';\n\nconst defaultReactionEmojiMap: Record<string, string> = {\n like: '👍',\n love: '❤️',\n haha: '😂',\n sad: '😢',\n fire: '🔥',\n};\n\nexport const MessageReactions: React.FC<MessageReactionsProps> = React.memo(({\n reactionCounts,\n ownReactions,\n latestReactions,\n onClickReaction,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n\n if (!reactionCounts || Object.keys(reactionCounts).length === 0) return null;\n\n return (\n <div className=\"ermis-message-reactions\">\n {Object.entries(reactionCounts).map(([type, count]) => {\n const isOwn = \n ownReactions?.some((r) => r.type === type) ||\n latestReactions?.some((r) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId));\n \n // Find users who reacted with this type for the tooltip\n const userNames = latestReactions\n ?.filter((r) => r.type === type)\n .map((r: any) => r.user?.name || r.user?.id || r.user_id || 'Someone');\n \n const tooltip = userNames && userNames.length > 0 ? userNames.join('\\n') : type;\n const emoji = defaultReactionEmojiMap[type] || type;\n\n return (\n <button\n key={type}\n className={`ermis-message-reactions__item ${\n isOwn ? 'ermis-message-reactions__item--active' : ''\n }`}\n data-tooltip={tooltip}\n onClick={() => onClickReaction?.(type)}\n type=\"button\"\n >\n <span className=\"ermis-message-reactions__emoji\">{emoji}</span>\n <span className=\"ermis-message-reactions__count\">{count}</span>\n </button>\n );\n })}\n </div>\n );\n});\n\nMessageReactions.displayName = 'MessageReactions';\n","import React, { useCallback } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\n\nconst QUICK_REACTIONS = ['like', 'love', 'haha', 'sad', 'fire'];\nconst EMOJI_MAP: Record<string, string> = {\n like: '👍',\n love: '❤️',\n haha: '😂',\n sad: '😢',\n fire: '🔥',\n};\n\nexport const MessageQuickReactions: React.FC<{\n message: FormatMessageResponse;\n isOwnMessage: boolean;\n}> = React.memo(({ message, isOwnMessage }) => {\n const { activeChannel, client } = useChatClient();\n const currentUserId = client?.userID;\n\n const handleReactionToggle = useCallback(\n async (type: string) => {\n if (!activeChannel) return;\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some(\n (r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId)\n );\n\n try {\n if (isOwn) {\n await activeChannel.deleteReaction(message.id!, type);\n } else {\n await activeChannel.sendReaction(message.id!, type);\n }\n } catch (err) {\n console.error('Failed to toggle reaction', err);\n }\n },\n [activeChannel, message, currentUserId]\n );\n\n return (\n <div className={`ermis-message-quick-reactions ${isOwnMessage ? 'ermis-message-quick-reactions--own' : ''}`}>\n {QUICK_REACTIONS.map((type) => {\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some(\n (r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId)\n );\n\n return (\n <button\n key={type}\n className={`ermis-message-quick-reactions__btn ${\n isOwn ? 'ermis-message-quick-reactions__btn--active' : ''\n }`}\n title={type}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n handleReactionToggle(type);\n }}\n >\n {EMOJI_MAP[type]}\n </button>\n );\n })}\n </div>\n );\n});\n\nMessageQuickReactions.displayName = 'MessageQuickReactions';\n","import React, { useState, useMemo } from 'react';\nimport { preloadImage, isImagePreloaded } from '../utils';\nimport type { FormatMessageResponse, Attachment, MessageLabel } from '@ermis-network/ermis-chat-sdk';\nimport { parseSystemMessage, parseSignalMessage, CallType } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { buildUserMap } from '../utils';\nimport type { AttachmentProps, MessageRendererProps, MessageBubbleProps } from '../types';\n\nexport type { AttachmentProps, MessageRendererProps, MessageBubbleProps } from '../types';\n\n/* ----------------------------------------------------------\n Attachment type helpers\n ---------------------------------------------------------- */\nfunction isImage(attachment: Attachment): boolean {\n return !!(\n attachment.type === 'image' ||\n (!attachment.type && (attachment.mime_type?.startsWith('image/') || attachment.image_url))\n );\n}\n\nfunction isVideo(attachment: Attachment): boolean {\n return !!(attachment.type === 'video' || (!attachment.type && attachment.mime_type?.startsWith('video/')));\n}\n\nfunction isVoiceRecording(attachment: Attachment): boolean {\n return attachment.type === 'voiceRecording';\n}\n\nfunction isLinkPreview(attachment: Attachment): boolean {\n return attachment.type === 'linkPreview';\n}\n\n/* ----------------------------------------------------------\n Attachment renderers\n ---------------------------------------------------------- */\nconst ImageAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const src = attachment.image_url || attachment.thumb_url || attachment.url;\n const thumbSrc = attachment.thumb_url;\n if (!src) return null;\n\n const alreadyCached = isImagePreloaded(src);\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Trigger background preload (no-op if already cached)\n useMemo(() => { preloadImage(src); }, [src]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, src]);\n\n return (\n <div className=\"ermis-attachment-aspect-box\" style={{ paddingBottom: '75%' }}>\n {/* Blur placeholder: use thumb if available, otherwise shimmer */}\n {!loaded && (\n thumbSrc && thumbSrc !== src ? (\n <img\n className=\"ermis-attachment-blur-preview\"\n src={thumbSrc}\n alt=\"\"\n aria-hidden\n />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n )\n )}\n <img\n ref={imgRef}\n className={`ermis-attachment ermis-attachment--image${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n alt={attachment.file_name || attachment.title || 'image'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n </div>\n );\n}, (prev, next) => {\n const prevSrc = prev.attachment.image_url || prev.attachment.thumb_url || prev.attachment.url;\n const nextSrc = next.attachment.image_url || next.attachment.thumb_url || next.attachment.url;\n return prevSrc === nextSrc;\n});\n(ImageAttachment as any).displayName = 'ImageAttachment';\n\nconst VideoAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const src = attachment.asset_url || attachment.url;\n const posterSrc = attachment.image_url || attachment.thumb_url;\n const blurThumb = attachment.thumb_url;\n if (!src) return null;\n\n const alreadyCached = posterSrc ? isImagePreloaded(posterSrc) : true;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (posterSrc) preloadImage(posterSrc);\n }, [posterSrc]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, posterSrc]);\n\n return (\n <div className=\"ermis-attachment-aspect-box\" style={{ paddingBottom: '75%' }}>\n {!loaded && (\n blurThumb && blurThumb !== posterSrc ? (\n <img\n className=\"ermis-attachment-blur-preview\"\n src={blurThumb}\n alt=\"\"\n aria-hidden\n />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n )\n )}\n {posterSrc && !loaded && (\n <img\n ref={imgRef}\n src={posterSrc}\n style={{ display: 'none' }}\n onLoad={() => setLoaded(true)}\n alt=\"poster-loader\"\n />\n )}\n <video\n className={`ermis-attachment ermis-attachment--video${loaded || !posterSrc ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n poster={posterSrc}\n controls\n preload=\"metadata\"\n onLoadedData={() => {\n if (!posterSrc) setLoaded(true);\n }}\n />\n </div>\n );\n}, (prev, next) => {\n return (prev.attachment.asset_url || prev.attachment.url) ===\n (next.attachment.asset_url || next.attachment.url);\n});\n(VideoAttachment as any).displayName = 'VideoAttachment';\n\nconst FileAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const url = attachment.url || attachment.asset_url;\n const name = attachment.file_name || attachment.title || 'File';\n const size = attachment.file_size;\n\n return (\n <a\n className=\"ermis-attachment ermis-attachment--file\"\n href={url}\n download={name}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span className=\"ermis-attachment__file-icon\">⬇️</span>\n <span className=\"ermis-attachment__file-info\">\n <span className=\"ermis-attachment__file-name\">{name}</span>\n {size && (\n <span className=\"ermis-attachment__file-size\">\n {typeof size === 'number' ? `${(size / 1024).toFixed(1)} KB` : size}\n </span>\n )}\n </span>\n </a>\n );\n}, (prev, next) => {\n return (prev.attachment.url || prev.attachment.asset_url) ===\n (next.attachment.url || next.attachment.asset_url);\n});\n(FileAttachment as any).displayName = 'FileAttachment';\n\nconst VoiceRecordingAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const src = attachment.asset_url || attachment.url;\n if (!src) return null;\n\n const durationSec = attachment.duration ?? 0;\n const mins = Math.floor(durationSec / 60);\n const secs = Math.round(durationSec % 60);\n const durationLabel = `${mins}:${secs.toString().padStart(2, '0')}`;\n\n return (\n <div className=\"ermis-attachment ermis-attachment--voice\">\n <span className=\"ermis-attachment__voice-icon\">🎙️</span>\n <audio src={src} controls preload=\"metadata\" className=\"ermis-attachment__voice-player\" />\n <span className=\"ermis-attachment__voice-duration\">{durationLabel}</span>\n </div>\n );\n}, (prev, next) => {\n return (prev.attachment.asset_url || prev.attachment.url) ===\n (next.attachment.asset_url || next.attachment.url);\n});\n(VoiceRecordingAttachment as any).displayName = 'VoiceRecordingAttachment';\n\nconst LinkPreviewAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const url = attachment.link_url || attachment.og_scrape_url || attachment.title_link || attachment.url;\n const title = attachment.title;\n const description = attachment.text;\n const image = attachment.image_url;\n\n const alreadyCached = image ? isImagePreloaded(image) : false;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (image) preloadImage(image);\n }, [image]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, image]);\n\n if (!title) return null;\n\n return (\n <a\n className=\"ermis-attachment ermis-attachment--link-preview\"\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {image && (\n <div style={{ position: 'relative', width: '100%', minHeight: '120px', backgroundColor: 'var(--ermis-bg-hover, #2a2a4a)', overflow: 'hidden' }}>\n {!loaded && <div className=\"ermis-attachment-shimmer\" />}\n <img\n ref={imgRef}\n className={`ermis-attachment__link-image${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={image}\n alt={title || 'preview'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease', display: 'block', width: '100%', height: '100%', objectFit: 'cover', position: 'absolute', top: 0, left: 0 }}\n />\n </div>\n )}\n <div className=\"ermis-attachment__link-info\">\n {title && <span className=\"ermis-attachment__link-title\">{title}</span>}\n {description && <span className=\"ermis-attachment__link-description\">{description}</span>}\n {url && (\n <span className=\"ermis-attachment__link-url\">\n {new URL(url).hostname}\n </span>\n )}\n </div>\n </a>\n );\n}, (prev, next) => {\n return (prev.attachment.link_url || prev.attachment.og_scrape_url || prev.attachment.url) ===\n (next.attachment.link_url || next.attachment.og_scrape_url || next.attachment.url);\n});\n(LinkPreviewAttachment as any).displayName = 'LinkPreviewAttachment';\n\nexport const MessageAttachment: React.FC<AttachmentProps> = ({ attachment }) => {\n if (isImage(attachment)) return <ImageAttachment attachment={attachment} />;\n if (isVideo(attachment)) return <VideoAttachment attachment={attachment} />;\n if (isVoiceRecording(attachment)) return <VoiceRecordingAttachment attachment={attachment} />;\n if (isLinkPreview(attachment)) return <LinkPreviewAttachment attachment={attachment} />;\n return <FileAttachment attachment={attachment} />;\n};\n\nexport const AttachmentList: React.FC<{ attachments?: Attachment[] }> = React.memo(({ attachments }) => {\n if (!attachments || attachments.length === 0) return null;\n\n // Group by type\n const media = attachments.filter((a) => isImage(a) || isVideo(a));\n const files = attachments.filter((a) => !isImage(a) && !isVideo(a) && !isVoiceRecording(a) && !isLinkPreview(a));\n const voices = attachments.filter(isVoiceRecording);\n const links = attachments.filter(isLinkPreview);\n\n const mediaGridClass = media.length === 1\n ? 'ermis-attachment-grid ermis-attachment-grid--single'\n : 'ermis-attachment-grid ermis-attachment-grid--multi';\n\n return (\n <div className=\"ermis-attachment-list\">\n {/* Media group: images + videos in grid */}\n {media.length > 0 && (\n <div className={mediaGridClass}>\n {media.map((att, i) => (\n isImage(att)\n ? <ImageAttachment key={att.id || `img-${i}`} attachment={att} />\n : <VideoAttachment key={att.id || `vid-${i}`} attachment={att} />\n ))}\n </div>\n )}\n {/* File group */}\n {files.map((att, i) => (\n <FileAttachment key={att.id || `file-${i}`} attachment={att} />\n ))}\n {/* Voice recording group */}\n {voices.map((att, i) => (\n <VoiceRecordingAttachment key={att.id || `voice-${i}`} attachment={att} />\n ))}\n {/* Link preview group */}\n {links.map((att, i) => (\n <LinkPreviewAttachment key={att.id || `link-${i}`} attachment={att} />\n ))}\n </div>\n );\n}, (prev, next) => {\n // Skip re-render if same attachment array reference\n if (prev.attachments === next.attachments) return true;\n if (!prev.attachments || !next.attachments) return false;\n if (prev.attachments.length !== next.attachments.length) return false;\n return prev.attachments.every((a, i) => a.id === next.attachments![i].id);\n});\n(AttachmentList as any).displayName = 'AttachmentList';\n\n/* ----------------------------------------------------------\n Message renderers by MessageLabel type\n ---------------------------------------------------------- */\n\n/**\n * Detect URLs and emails in plain text, wrapping them in <a> tags.\n * Returns an array of React nodes (strings and link elements).\n */\nconst URL_REGEX = /(https?:\\/\\/[^\\s<>]+|www\\.[^\\s<>]+|[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,})/g;\n\nfunction linkifyText(text: string, keyPrefix: string): React.ReactNode[] {\n const parts = text.split(URL_REGEX);\n if (parts.length === 1) return [text];\n\n return parts.map((part, i) => {\n if (URL_REGEX.test(part)) {\n // Reset lastIndex since we reuse the regex\n URL_REGEX.lastIndex = 0;\n const isEmail = part.includes('@') && !part.startsWith('http');\n const href = isEmail ? `mailto:${part}` : (part.startsWith('http') ? part : `https://${part}`);\n return (\n <a\n key={`${keyPrefix}-link-${i}`}\n className=\"ermis-text-link\"\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {part}\n </a>\n );\n }\n // Reset lastIndex\n URL_REGEX.lastIndex = 0;\n return part;\n });\n}\n\n/**\n * Parse message text: render @mentions as highlighted spans,\n * and auto-detect URLs/emails in non-mention text parts.\n */\nfunction renderTextWithMentions(\n text: string,\n message: FormatMessageResponse,\n userMap: Record<string, string>,\n): React.ReactNode {\n const mentionedUsers: string[] = (message as any).mentioned_users ?? [];\n const mentionedAll: boolean = (message as any).mentioned_all ?? false;\n\n // If no mentions, just linkify the text\n if (mentionedUsers.length === 0 && !mentionedAll) {\n return linkifyText(text, 'txt');\n }\n\n // Build a list of patterns to replace: @userId → @userName\n const replacements: { pattern: string; label: string }[] = [];\n\n for (const userId of mentionedUsers) {\n replacements.push({\n pattern: `@${userId}`,\n label: `@${userMap[userId] ?? userId}`,\n });\n }\n\n if (mentionedAll) {\n replacements.push({ pattern: '@all', label: '@all' });\n }\n\n // Build a regex that matches any of the mention patterns\n const escaped = replacements.map((r) =>\n r.pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n );\n const regex = new RegExp(`(${escaped.join('|')})`, 'g');\n\n const parts = text.split(regex);\n\n // Map from pattern → label for quick lookup\n const patternToLabel = new Map(replacements.map((r) => [r.pattern, r.label]));\n\n return parts.flatMap((part, i) => {\n const label = patternToLabel.get(part);\n if (label) {\n // Mention — render as span, do NOT linkify\n return (\n <span key={`mention-${i}`} className=\"ermis-mention\">\n {label}\n </span>\n );\n }\n // Non-mention text — linkify URLs/emails\n return linkifyText(part, `p${i}`);\n });\n}\n\n/** Regular message: text with @mentions + attachments */\nexport const RegularMessage: React.FC<MessageRendererProps> = React.memo(({ message }) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n const textContent = message.text\n ? renderTextWithMentions(message.text, message, userMap)\n : null;\n\n const attachmentsToRender = useMemo(() => {\n if (!message.attachments || message.attachments.length === 0) return [];\n\n const text = (message.text || '').trim();\n const URL_REGEX_STRICT = /^(https?:\\/\\/[^\\s<>]+|www\\.[^\\s<>]+)$/;\n const isOnlyUrl = URL_REGEX_STRICT.test(text);\n\n return message.attachments.filter(att => {\n if (isLinkPreview(att)) return isOnlyUrl;\n return true;\n });\n }, [message.attachments, message.text]);\n\n const hasAttachments = attachmentsToRender.length > 0;\n\n if (hasAttachments) {\n return (\n <div className=\"ermis-message-content--with-attachments\">\n {textContent && (\n <span className=\"ermis-message-list__item-text\">{textContent}</span>\n )}\n <AttachmentList attachments={attachmentsToRender} />\n </div>\n );\n }\n\n return (\n <>\n {textContent && (\n <span className=\"ermis-message-list__item-text\">{textContent}</span>\n )}\n </>\n );\n}, (prev, next) => {\n return prev.message.id === next.message.id &&\n prev.message.updated_at === next.message.updated_at &&\n prev.message.text === next.message.text &&\n prev.isOwnMessage === next.isOwnMessage;\n});\nRegularMessage.displayName = 'RegularMessage';\n\n/** System message: centered info text, parsed from raw format */\nexport const SystemMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n const parsedText = useMemo(\n () => (message.text ? parseSystemMessage(message.text, userMap) : ''),\n [message.text, userMap],\n );\n\n return (\n <span className=\"ermis-message-list__system-text\">\n {parsedText || message.text}\n </span>\n );\n};\n\n/** Signal message: call events */\nexport const SignalMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const { client } = useChatClient();\n\n const rawText = message.text ?? '';\n const result = rawText ? parseSignalMessage(rawText, client.userID || '') : null;\n\n if (!result) {\n return (\n <span className=\"ermis-message-list__signal-text\">\n {rawText}\n </span>\n );\n }\n\n const isSuccess = !!result.duration;\n const colorModifier = isSuccess ? 'success' : 'missed';\n const isAudio = result.callType === CallType.AUDIO;\n\n return (\n <div className=\"ermis-signal-message\">\n <div className={`ermis-signal-message__icon ermis-signal-message__icon--${colorModifier}`}>\n {isAudio ? (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\" />\n </svg>\n ) : (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\" />\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\" />\n </svg>\n )}\n </div>\n <div className=\"ermis-signal-message__body\">\n <span className={`ermis-signal-message__text ermis-signal-message__text--${colorModifier}`}>\n {result.text}\n </span>\n {result.duration && (\n <span className=\"ermis-signal-message__duration\">{result.duration}</span>\n )}\n </div>\n </div>\n );\n};\n\n/** Poll message */\nexport const PollMessage: React.FC<MessageRendererProps> = ({ message }) => (\n <div className=\"ermis-message-poll\">\n <span className=\"ermis-message-poll__icon\">📊</span>\n <span className=\"ermis-message-poll__text\">{message.text || 'Poll'}</span>\n </div>\n);\n\n/** Sticker message */\nexport const StickerMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const stickerUrl = (message as any).sticker_url;\n\n const alreadyCached = stickerUrl ? isImagePreloaded(stickerUrl) : false;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (stickerUrl) preloadImage(stickerUrl);\n }, [stickerUrl]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, stickerUrl]);\n\n if (stickerUrl) {\n return (\n <div style={{ position: 'relative', width: '120px', height: '120px', overflow: 'hidden' }}>\n {!loaded && <div className=\"ermis-attachment-shimmer\" />}\n <img\n ref={imgRef}\n className=\"ermis-message-sticker\"\n src={stickerUrl}\n alt=\"sticker\"\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease', position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'contain' }}\n />\n </div>\n );\n }\n return <span className=\"ermis-message-list__item-text\">{message.text}</span>;\n};\n\n/** Error message */\nexport const ErrorMessage: React.FC<MessageRendererProps> = ({ message }) => (\n <span className=\"ermis-message-error\">{message.text || 'Message failed'}</span>\n);\n\n/**\n * Map from MessageLabel → component.\n * Consumer can override individual renderers via the `messageRenderers` prop.\n */\nexport const defaultMessageRenderers: Record<\n MessageLabel,\n React.ComponentType<MessageRendererProps>\n> = {\n regular: RegularMessage,\n system: SystemMessage,\n signal: SignalMessage,\n poll: PollMessage,\n sticker: StickerMessage,\n error: ErrorMessage,\n};\n","import React, { useState, useEffect, useMemo, useCallback } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { PinnedMessageItemProps, PinnedMessagesProps } from '../types';\n\n/* ----------------------------------------------------------\n Default PinnedMessageItem\n ---------------------------------------------------------- */\nconst DefaultPinnedMessageItem: React.FC<PinnedMessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n onClickMessage,\n onUnpin,\n AvatarComponent,\n}) => {\n const { activeChannel } = useChatClient();\n const userName = message.user?.name || message.user_id || 'Unknown';\n const userAvatar = message.user?.avatar;\n const hasAttachments = message.attachments && message.attachments.length > 0;\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n let previewText = message.text || '';\n const isSticker = message.type === 'sticker';\n\n if (!previewText && hasAttachments) {\n const firstAttach = message.attachments![0];\n previewText = firstAttach.title || `${firstAttach.type || 'file'}`;\n } else if (isSticker) {\n previewText = 'Sticker';\n }\n\n // Convert @userId → @UserName in preview text\n if (previewText) {\n previewText = replaceMentionsForPreview(previewText, message, userMap);\n }\n\n // Attachment icon prefix\n let attachIcon = '';\n if (hasAttachments) {\n const type = message.attachments![0].type;\n if (type === 'image') attachIcon = '📷 ';\n else if (type === 'video') attachIcon = '🎥 ';\n else if (type === 'audio') attachIcon = '🎵 ';\n else attachIcon = '📄 ';\n } else if (isSticker) {\n attachIcon = '😀 ';\n }\n\n return (\n <div\n className={`ermis-pinned-messages__item ${isOwnMessage ? 'ermis-pinned-messages__item--own' : ''}`}\n onClick={() => onClickMessage?.(message.id)}\n role=\"button\"\n tabIndex={0}\n >\n <AvatarComponent image={userAvatar} name={userName} size={28} />\n <div className=\"ermis-pinned-messages__item-content\">\n <span className=\"ermis-pinned-messages__item-user\">{userName}</span>\n <span className=\"ermis-pinned-messages__item-text\">{attachIcon}{previewText || 'Attachment'}</span>\n </div>\n <button\n className=\"ermis-pinned-messages__unpin-btn\"\n onClick={(e) => { e.stopPropagation(); onUnpin?.(message.id); }}\n title=\"Unpin message\"\n aria-label=\"Unpin message\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"2\" y1=\"2\" x2=\"22\" y2=\"22\" />\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n </button>\n </div>\n );\n});\nDefaultPinnedMessageItem.displayName = 'DefaultPinnedMessageItem';\n\n/* ----------------------------------------------------------\n PinnedMessages component\n ---------------------------------------------------------- */\nexport const PinnedMessages: React.FC<PinnedMessagesProps> = React.memo(({\n className,\n AvatarComponent = Avatar,\n PinnedMessageItemComponent = DefaultPinnedMessageItem,\n onClickMessage,\n maxCollapsed = 1,\n}) => {\n const { activeChannel, client, messages } = useChatClient();\n const [expanded, setExpanded] = useState(false);\n const currentUserId = client.userID;\n\n // Reset expanded state when switching channels\n useEffect(() => {\n setExpanded(false);\n }, [activeChannel]);\n\n const pinnedMessages = useMemo<FormatMessageResponse[]>(() => {\n if (!activeChannel) return [];\n const pinned = (activeChannel.state as any)?.pinnedMessages;\n return Array.isArray(pinned) ? pinned : [];\n }, [activeChannel, messages]);\n\n const toggleExpanded = useCallback(() => {\n setExpanded((prev) => !prev);\n }, []);\n\n const handleUnpin = useCallback(async (messageId: string) => {\n if (!activeChannel) return;\n try {\n await activeChannel.unpinMessage(messageId);\n } catch (err) {\n console.error('Failed to unpin message', err);\n }\n }, [activeChannel]);\n\n if (pinnedMessages.length === 0) return null;\n\n const displayedMessages = expanded\n ? pinnedMessages\n : pinnedMessages.slice(0, maxCollapsed);\n\n const hasMore = pinnedMessages.length > maxCollapsed;\n\n return (\n <div className={`ermis-pinned-messages${expanded ? ' ermis-pinned-messages--expanded' : ''}${className ? ` ${className}` : ''}`}>\n {/* Header bar */}\n <div className=\"ermis-pinned-messages__header\" onClick={toggleExpanded}>\n <svg className=\"ermis-pinned-messages__icon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n <span className=\"ermis-pinned-messages__label\">\n {pinnedMessages.length} pinned message{pinnedMessages.length > 1 ? 's' : ''}\n </span>\n {hasMore && (\n <button\n className=\"ermis-pinned-messages__toggle\"\n onClick={(e) => { e.stopPropagation(); toggleExpanded(); }}\n >\n {expanded ? 'Collapse' : 'See all'}\n </button>\n )}\n </div>\n\n {/* Pinned message list */}\n <div className=\"ermis-pinned-messages__list\">\n {displayedMessages.map((msg) => (\n <PinnedMessageItemComponent\n key={msg.id}\n message={msg}\n isOwnMessage={msg.user_id === currentUserId || msg.user?.id === currentUserId}\n onClickMessage={onClickMessage}\n onUnpin={handleUnpin}\n AvatarComponent={AvatarComponent}\n />\n ))}\n </div>\n </div>\n );\n});\n\nPinnedMessages.displayName = 'PinnedMessages';\n","import React from 'react';\nimport type { ReadReceiptsProps, ReadReceiptsTooltipProps } from '../types';\nimport { Avatar } from './Avatar';\nimport { formatReadTimestamp } from '../utils';\n\nexport type { ReadReceiptsProps, ReadReceiptsTooltipProps } from '../types';\n\n/* ----------------------------------------------------------\n Default Tooltip — shown on hover\n ---------------------------------------------------------- */\nconst DefaultReadReceiptsTooltip: React.FC<ReadReceiptsTooltipProps> = React.memo(({\n readers,\n AvatarComponent,\n}) => (\n <div className=\"ermis-read-receipts__tooltip-wrapper\">\n <div className=\"ermis-read-receipts__tooltip\">\n {readers.map((reader) => (\n <div key={reader.id} className=\"ermis-read-receipts__tooltip-item\">\n <AvatarComponent\n image={reader.avatar}\n name={reader.name || reader.id}\n size={20}\n />\n <div className=\"ermis-read-receipts__tooltip-info\">\n <span className=\"ermis-read-receipts__tooltip-name\">{reader.name || reader.id}</span>\n <span className=\"ermis-read-receipts__tooltip-time\">{formatReadTimestamp(reader.last_read)}</span>\n </div>\n </div>\n ))}\n </div>\n </div>\n));\nDefaultReadReceiptsTooltip.displayName = 'DefaultReadReceiptsTooltip';\n\n/* ----------------------------------------------------------\n ReadReceipts — main component\n ---------------------------------------------------------- */\nexport const ReadReceipts: React.FC<ReadReceiptsProps> = React.memo(({\n readers,\n maxAvatars = 5,\n AvatarComponent = Avatar,\n TooltipComponent = DefaultReadReceiptsTooltip,\n showTooltip = true,\n}) => {\n // Only render when there are actual readers (avatar-based display)\n // Sent/Sending/Error status icons are now rendered inline inside the message bubble\n if (!readers || readers.length === 0) {\n return null;\n }\n\n const visible = readers.slice(0, maxAvatars);\n const overflow = readers.length - maxAvatars;\n\n return (\n <div className=\"ermis-read-receipts\">\n <div className=\"ermis-read-receipts__avatars\">\n {visible.map((reader) => (\n <AvatarComponent\n key={reader.id}\n image={reader.avatar}\n name={reader.name || reader.id}\n size={16}\n className=\"ermis-read-receipts__avatar\"\n />\n ))}\n {overflow > 0 && (\n <span className=\"ermis-read-receipts__overflow\">+{overflow}</span>\n )}\n {showTooltip && (\n <TooltipComponent\n readers={readers}\n AvatarComponent={AvatarComponent}\n />\n )}\n </div>\n </div>\n );\n});\n\nReadReceipts.displayName = 'ReadReceipts';\n","import React from 'react';\nimport { useTypingIndicator, type TypingUser } from '../hooks/useTypingIndicator';\n\nexport type TypingIndicatorProps = {\n /** Custom render function for the typing text */\n renderText?: (users: TypingUser[]) => React.ReactNode;\n};\n\n/**\n * Displays a \"X is typing...\" indicator below the message list.\n * Automatically subscribes to typing events via the useTypingIndicator hook.\n */\nexport const TypingIndicator: React.FC<TypingIndicatorProps> = React.memo(({ renderText }) => {\n const { typingUsers } = useTypingIndicator();\n\n const isActive = typingUsers.length > 0;\n\n const text = isActive\n ? (renderText ? renderText(typingUsers) : formatTypingText(typingUsers))\n : null;\n\n return (\n <div className={`ermis-typing-indicator${isActive ? ' ermis-typing-indicator--active' : ''}`}>\n {isActive && (\n <>\n <div className=\"ermis-typing-indicator__dots\">\n <span className=\"ermis-typing-indicator__dot\" />\n <span className=\"ermis-typing-indicator__dot\" />\n <span className=\"ermis-typing-indicator__dot\" />\n </div>\n <span className=\"ermis-typing-indicator__text\">{text}</span>\n </>\n )}\n </div>\n );\n});\n\nTypingIndicator.displayName = 'TypingIndicator';\n\n/**\n * Format typing text based on number of users:\n * - 1 user: \"Alice is typing...\"\n * - 2 users: \"Alice and Bob are typing...\"\n * - 3+ users: \"Alice, Bob and 2 others are typing...\"\n */\nfunction formatTypingText(users: TypingUser[]): string {\n const names = users.map((u) => u.name || u.id);\n\n if (names.length === 1) {\n return `${names[0]} is typing...`;\n }\n if (names.length === 2) {\n return `${names[0]} and ${names[1]} are typing...`;\n }\n const remaining = names.length - 2;\n return `${names[0]}, ${names[1]} and ${remaining} other${remaining > 1 ? 's' : ''} are typing...`;\n}\n","import { useState, useEffect, useRef } from 'react';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\n\nexport type TypingUser = {\n id: string;\n name?: string;\n};\n\n/**\n * Hook that subscribes to typing events on the active channel\n * and returns the list of currently‑typing users (excluding the current user).\n *\n * Stale entries are auto‑cleaned every 7 seconds, consistent with\n * the SDK's `channel.state.clean()` behaviour.\n */\nexport function useTypingIndicator() {\n const { activeChannel, client } = useChatClient();\n const [typingUsers, setTypingUsers] = useState<TypingUser[]>([]);\n const currentUserId = client.userID;\n\n // Keep a mutable map so event handlers can read/write without\n // creating stale‑closure issues.\n const typingMapRef = useRef<Map<string, { user: TypingUser; timestamp: number }>>(new Map());\n\n useEffect(() => {\n if (!activeChannel) {\n setTypingUsers([]);\n typingMapRef.current.clear();\n return;\n }\n\n // Reset when channel switches\n typingMapRef.current.clear();\n setTypingUsers([]);\n\n const syncState = () => {\n const users = Array.from(typingMapRef.current.values()).map((v) => v.user);\n setTypingUsers(users);\n };\n\n const handleTypingStart = (event: Event) => {\n const userId = event.user?.id;\n if (!userId || userId === currentUserId) return;\n\n typingMapRef.current.set(userId, {\n user: { id: userId, name: event.user?.name },\n timestamp: Date.now(),\n });\n syncState();\n };\n\n const handleTypingStop = (event: Event) => {\n const userId = event.user?.id;\n if (!userId) return;\n\n typingMapRef.current.delete(userId);\n syncState();\n };\n\n const sub1 = activeChannel.on('typing.start', handleTypingStart);\n const sub2 = activeChannel.on('typing.stop', handleTypingStop);\n\n // Auto‑clean stale entries every 7 seconds\n const cleanupInterval = setInterval(() => {\n const now = Date.now();\n let changed = false;\n for (const [uid, entry] of typingMapRef.current.entries()) {\n if (now - entry.timestamp > 7000) {\n typingMapRef.current.delete(uid);\n changed = true;\n }\n }\n if (changed) syncState();\n }, 3000);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n clearInterval(cleanupInterval);\n typingMapRef.current.clear();\n };\n }, [activeChannel, currentUserId]);\n\n return { typingUsers };\n}\n","import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { useMentions } from '../hooks/useMentions';\nimport { useFileUpload } from '../hooks/useFileUpload';\nimport { useEmojiPicker } from '../hooks/useEmojiPicker';\nimport { useMessageSend } from '../hooks/useMessageSend';\nimport { DefaultSendButton, DefaultAttachButton, DefaultEmojiButton } from './MessageInputDefaults';\nimport { MentionSuggestions } from './MentionSuggestions';\nimport { FilesPreview } from './FilesPreview';\nimport { ReplyPreview } from './ReplyPreview';\nimport { EditPreview } from './EditPreview';\nimport { buildUserMap, replaceMentionsForPreview, moveCaretToEnd } from '../utils';\nimport { getMentionHtml } from '../hooks/useMentions';\nimport { useChannelCapabilities } from '../hooks/useChannelCapabilities';\nimport type { MentionMember, MessageInputProps, FilePreviewItem } from '../types';\n\nexport type { MessageInputProps, SendButtonProps, AttachButtonProps, EmojiPickerProps, EmojiButtonProps } from '../types';\n\nexport const MessageInput: React.FC<MessageInputProps> = React.memo(({\n placeholder = 'Type a message...',\n onSend,\n className,\n SendButton = DefaultSendButton,\n AttachButton = DefaultAttachButton,\n FilesPreviewComponent = FilesPreview,\n MentionSuggestionsComponent = MentionSuggestions,\n disableAttachments = false,\n disableMentions = false,\n renderAbove,\n onBeforeSend,\n EmojiPickerComponent,\n EmojiButtonComponent = DefaultEmojiButton,\n ReplyPreviewComponent = ReplyPreview,\n EditPreviewComponent = EditPreview,\n bannedLabel = 'You have been blocked from this channel',\n blockedLabel = 'You have blocked this user. Unblock to send messages.',\n linksDisabledLabel = 'Message blocked: Sending links is disabled for members.',\n keywordBlockedLabel = (match: string) => `Message blocked: Contains restricted word \"${match}\".`,\n sendDisabledLabel = 'Sending messages is disabled in this channel.',\n slowModeLabel = (cooldown: number) => (\n <>Slow mode is active. You can send another message in <strong>{cooldown}s</strong>.</>\n ),\n}) => {\n const { client, activeChannel, syncMessages, quotedMessage, setQuotedMessage, editingMessage, setEditingMessage } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n const { isPending } = usePendingState(activeChannel, client.userID);\n const editableRef = React.useRef<HTMLDivElement>(null);\n const [hasContent, setHasContent] = useState(false);\n\n const { role, isTeamChannel, hasCapability } = useChannelCapabilities();\n\n // Slow Mode Logic\n const [memberMessageCooldown, setMemberMessageCooldown] = useState(Number(activeChannel?.data?.member_message_cooldown) || 0);\n\n useEffect(() => {\n if (!activeChannel) return;\n setMemberMessageCooldown(Number(activeChannel.data?.member_message_cooldown) || 0);\n const handleUpdate = (event: Record<string, unknown>) => {\n const channelData = (event?.channel as Record<string, unknown>) || activeChannel.data;\n setMemberMessageCooldown(Number(channelData?.member_message_cooldown) || 0);\n };\n activeChannel.on('channel.updated', handleUpdate);\n return () => {\n activeChannel.off('channel.updated', handleUpdate);\n };\n }, [activeChannel]);\n\n const isSlowModeApplied = isTeamChannel && role === 'member' && memberMessageCooldown > 0;\n\n const [cooldownEnd, setCooldownEnd] = useState<number | null>(null);\n const [cooldown, setCooldown] = useState(0);\n const lastMsgSentAtRef = useRef<number>(0);\n\n // Initialize cooldown state periodically or on change\n useEffect(() => {\n if (!isSlowModeApplied) {\n setCooldownEnd(null);\n setCooldown(0);\n return;\n }\n\n let lastMsgSentAt = lastMsgSentAtRef.current || 0;\n const messages = activeChannel?.state?.messages || [];\n\n // Iterate from newest to oldest to find actual highest timestamp\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].user?.id === client.userID) {\n const msgTime = new Date(messages[i].created_at).getTime();\n if (msgTime && !isNaN(msgTime) && msgTime > lastMsgSentAt) {\n lastMsgSentAt = msgTime;\n }\n break;\n }\n }\n\n if (lastMsgSentAt) {\n const cdEnd = lastMsgSentAt + memberMessageCooldown;\n if (cdEnd > Date.now()) {\n setCooldownEnd(cdEnd);\n } else {\n setCooldownEnd(null);\n setCooldown(0);\n }\n } else {\n setCooldownEnd(null);\n setCooldown(0);\n }\n }, [isSlowModeApplied, activeChannel, memberMessageCooldown, client.userID]);\n\n // Tick the countdown visualization\n useEffect(() => {\n if (!cooldownEnd || cooldownEnd <= Date.now()) {\n setCooldown(0);\n return;\n }\n const updateCd = () => {\n const remaining = cooldownEnd - Date.now();\n if (remaining <= 0) {\n setCooldown(0);\n } else {\n setCooldown(Math.ceil(remaining / 1000));\n }\n };\n updateCd();\n const timer = setInterval(updateCd, 1000);\n return () => clearInterval(timer);\n }, [cooldownEnd]);\n\n const isSlowModeBlocked = isSlowModeApplied && cooldown > 0 && !editingMessage;\n\n const canSendMessage = hasCapability('send-message');\n const canSendLinks = hasCapability('send-links');\n\n const [keywordError, setKeywordError] = useState<string | null>(null);\n\n // Auto-clear link restriction banner if admin suddenly restores the capability\n useEffect(() => {\n if (keywordError?.includes('links') && canSendLinks) {\n setKeywordError(null);\n }\n }, [canSendLinks, keywordError]);\n\n const localOnBeforeSend = useCallback(async (text: string, attachments: FilePreviewItem[]) => {\n // Permission validation: Send Links\n if (!canSendLinks && text) {\n // Basic URL matching config\n const urlRegex = /(https?:\\/\\/[^\\s]+)|(www\\.[^\\s]+)|([a-zA-Z0-9-]+\\.[a-zA-Z]{2,}(\\/[^\\s]*)?)/i;\n if (urlRegex.test(text)) {\n setKeywordError(linksDisabledLabel);\n return false;\n }\n }\n\n // Custom Keyword validation\n const words = (activeChannel?.data?.filter_words as string[]) || [];\n if (words.length > 0 && text) {\n const lowerText = text.toLowerCase();\n const match = words.find(w => lowerText.includes(w.toLowerCase()));\n if (match) {\n setKeywordError(keywordBlockedLabel(match));\n // We could also visually shake the input box here\n return false;\n }\n }\n setKeywordError(null);\n if (onBeforeSend) {\n return await onBeforeSend(text, attachments);\n }\n return true;\n }, [activeChannel, onBeforeSend, canSendLinks]);\n\n const handleMessageSent = useCallback((text: string) => {\n if (isSlowModeApplied) {\n lastMsgSentAtRef.current = Date.now();\n setCooldownEnd(Date.now() + memberMessageCooldown);\n }\n onSend?.(text);\n }, [isSlowModeApplied, memberMessageCooldown, onSend]);\n\n // Auto-focus when channel changes or when reply/edit is selected\n useEffect(() => {\n if (activeChannel && editableRef.current) {\n editableRef.current.focus();\n }\n }, [activeChannel, quotedMessage, editingMessage]);\n\n\n /* ---------- Hooks ---------- */\n const {\n files, setFiles, fileInputRef,\n handleFilesSelected, handleRemoveFile, handleAttachClick, cleanupFiles,\n } = useFileUpload({ activeChannel, editableRef, setHasContent });\n\n // Pre-fill text and legacy attachments when editingMessage is set\n useEffect(() => {\n if (editingMessage && editableRef.current) {\n // 1. Prefill text content\n const rawText = editingMessage.text || '';\n\n // Extract user map locally since we have `activeChannel.state.members`\n const userMap = buildUserMap(activeChannel?.state);\n\n const htmlText = rawText\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\\n/g, '<br>');\n\n editableRef.current.innerHTML = replaceMentionsForPreview(\n htmlText,\n editingMessage,\n userMap,\n getMentionHtml\n );\n\n // Move cursor to the end\n moveCaretToEnd(editableRef.current);\n\n // The API does not support attachment modifications during edits.\n // Flush any active files and only allow text/mention modifications.\n setFiles([]);\n setHasContent(!!editingMessage.text);\n }\n }, [editingMessage, setFiles]);\n\n // Cleanup blob URLs on unmount\n useEffect(() => {\n return () => cleanupFiles();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const {\n emojiPickerOpen,\n handleEmojiSelect,\n handleEmojiClose,\n toggleEmojiPicker,\n } = useEmojiPicker({ editableRef, setHasContent });\n\n // Build member list from channel state (only for team channels)\n const members = useMemo<MentionMember[]>(() => {\n if (!isTeamChannel) return [];\n const list: MentionMember[] = [];\n const stateMembers = activeChannel?.state?.members as Record<string, unknown> | undefined;\n if (stateMembers && typeof stateMembers === 'object') {\n for (const [id, memberVal] of Object.entries(stateMembers)) {\n const member = memberVal as Record<string, any>;\n list.push({\n id,\n name: member?.user?.name || member?.user_id || id,\n avatar: member?.user?.avatar,\n });\n }\n }\n return list;\n }, [activeChannel, isTeamChannel]);\n\n const {\n showSuggestions, filteredMembers, highlightIndex,\n handleInput: mentionHandleInput,\n handleKeyDown: mentionHandleKeyDown,\n selectMention, buildPayload, reset,\n } = useMentions({\n members,\n currentUserId: client.userID,\n editableRef,\n });\n\n const cancelEdit = useCallback(() => {\n setEditingMessage(null);\n cleanupFiles();\n setFiles([]);\n setHasContent(false);\n reset();\n if (editableRef.current) {\n editableRef.current.innerHTML = '';\n }\n }, [setEditingMessage, cleanupFiles, setFiles, setHasContent, reset]);\n\n const { sending, handleSend } = useMessageSend({\n activeChannel,\n editableRef,\n files,\n setFiles,\n hasContent,\n setHasContent,\n isTeamChannel,\n buildPayload,\n reset,\n syncMessages,\n onSend: handleMessageSent,\n onBeforeSend: localOnBeforeSend,\n quotedMessage,\n clearQuotedMessage: () => setQuotedMessage(null),\n editingMessage,\n clearEditingMessage: () => setEditingMessage(null),\n });\n\n useEffect(() => {\n reset();\n handleEmojiClose();\n setFiles((prev) => {\n prev.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n return [];\n });\n setHasContent(false);\n\n // Stop typing indicator on channel switch / unmount\n return () => {\n activeChannel?.stopTyping();\n };\n }, [activeChannel, reset, handleEmojiClose, setFiles]);\n\n /* ---------- Input event handlers ---------- */\n const handleInput = useCallback(() => {\n const el = editableRef.current;\n const content = el?.textContent?.trim() ?? '';\n setHasContent(content.length > 0 || files.length > 0);\n setKeywordError(null); // clear keyword error if user modifies input\n if (isTeamChannel && !disableMentions) {\n mentionHandleInput();\n }\n // Send typing indicator (SDK throttles to 1 event per 2s)\n activeChannel?.keystroke();\n }, [isTeamChannel, disableMentions, mentionHandleInput, files.length, activeChannel]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n // Prevent reacting to \"Enter\" when constructing characters with an IME (e.g. Vietnamese telex)\n if (e.nativeEvent.isComposing) return;\n\n if (e.key === 'Escape') {\n if (editingMessage) {\n cancelEdit();\n return;\n }\n if (quotedMessage) {\n setQuotedMessage(null);\n return;\n }\n }\n if (isTeamChannel && !disableMentions) {\n const consumed = mentionHandleKeyDown(e);\n if (consumed) return;\n }\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n if (!isSlowModeBlocked) {\n handleSend();\n }\n }\n },\n [isTeamChannel, disableMentions, mentionHandleKeyDown, handleSend, editingMessage, quotedMessage, setEditingMessage, setQuotedMessage, reset],\n );\n\n const handlePaste = useCallback((e: React.ClipboardEvent) => {\n e.preventDefault();\n const plainText = e.clipboardData.getData('text/plain');\n document.execCommand('insertText', false, plainText);\n }, []);\n\n if (!activeChannel) return null;\n\n // Don't show input for pending invitations at all\n if (isPending) return null;\n\n // Show banned banner instead of input\n if (isBanned) {\n return (\n <div className={`ermis-message-input ermis-message-input--banned${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__banned-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n <span>{bannedLabel}</span>\n </div>\n </div>\n );\n }\n\n // Show blocked banner instead of input (messaging channels only)\n if (isBlocked) {\n return (\n <div className={`ermis-message-input ermis-message-input--blocked${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__blocked-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n <span>{blockedLabel}</span>\n </div>\n </div>\n );\n }\n\n const isStillUploading = files.some((f) => f.status === 'uploading');\n\n return (\n <div className={`ermis-message-input${className ? ` ${className}` : ''}`}>\n {/* Reply preview */}\n {quotedMessage && !editingMessage && (\n <ReplyPreviewComponent\n message={quotedMessage}\n onDismiss={() => setQuotedMessage(null)}\n />\n )}\n\n {/* Edit preview */}\n {editingMessage && (\n <EditPreviewComponent\n message={editingMessage}\n onDismiss={cancelEdit}\n />\n )}\n\n {/* Custom content above input */}\n {renderAbove?.()}\n\n {/* File previews */}\n {!disableAttachments && <FilesPreviewComponent files={files} onRemove={handleRemoveFile} />}\n\n {/* Keyword Error Banner */}\n {keywordError && (\n <div className=\"ermis-message-input__keyword-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\n {keywordError}\n </div>\n )}\n\n {/* Permission Disabled Banner */}\n {!canSendMessage && !editingMessage && (\n <div className=\"ermis-message-input__permission-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>\n {sendDisabledLabel}\n </div>\n )}\n\n {/* Slow Mode Cooldown Banner */}\n {canSendMessage && isSlowModeBlocked && !keywordError && (\n <div className=\"ermis-message-input__slow-mode-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><polyline points=\"12 6 12 12 16 14\"></polyline></svg>\n {typeof slowModeLabel === 'function' ? slowModeLabel(cooldown) : slowModeLabel}\n </div>\n )}\n\n {/* Text input + send row */}\n <div className={`ermis-message-input__row${(!canSendMessage || isSlowModeBlocked || keywordError) ? ' ermis-message-input__row--banners-active' : ''}`}>\n <div className=\"ermis-message-input__editable-wrapper\">\n {canSendMessage && isTeamChannel && !disableMentions && showSuggestions && (\n <MentionSuggestionsComponent\n members={filteredMembers}\n highlightIndex={highlightIndex}\n onSelect={selectMention}\n />\n )}\n\n {/* Attach button */}\n {!disableAttachments && (\n <AttachButton disabled={sending || !!editingMessage || isSlowModeBlocked || !canSendMessage} onClick={handleAttachClick} />\n )}\n\n {/* Hidden file input */}\n {!disableAttachments && (\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"ermis-message-input__file-input\"\n onChange={(e) => {\n handleFilesSelected(e.target.files);\n e.target.value = '';\n }}\n disabled={!!editingMessage || isSlowModeBlocked || !canSendMessage}\n />\n )}\n\n <div\n ref={editableRef}\n className=\"ermis-message-input__editable\"\n contentEditable={!sending && !isSlowModeBlocked && canSendMessage}\n role=\"textbox\"\n aria-placeholder={placeholder}\n data-placeholder={placeholder}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n suppressContentEditableWarning\n />\n\n {/* Emoji button — shown only when EmojiPickerComponent is provided */}\n {EmojiPickerComponent && (\n <EmojiButtonComponent active={emojiPickerOpen} onClick={isSlowModeBlocked ? () => { } : toggleEmojiPicker} />\n )}\n </div>\n <SendButton disabled={!hasContent || sending || isStillUploading || isSlowModeBlocked} onClick={handleSend} />\n </div>\n\n {/* Emoji picker — positioned above input */}\n {EmojiPickerComponent && emojiPickerOpen && (\n <div className=\"ermis-message-input__emoji-picker\">\n <EmojiPickerComponent onSelect={handleEmojiSelect} onClose={handleEmojiClose} />\n </div>\n )}\n </div>\n );\n});\n\nMessageInput.displayName = 'MessageInput';\n","import { useState, useCallback, useRef, useDeferredValue, useMemo } from 'react';\nimport { moveCaretAfterNode } from '../utils';\nimport type {\n MentionMember,\n MentionPayload,\n UseMentionsOptions,\n UseMentionsReturn,\n} from '../types';\n\nexport type { MentionMember, MentionPayload, UseMentionsOptions, UseMentionsReturn } from '../types';\n\nexport const MENTION_SPAN_CLASS = 'ermis-message-input__mention-span';\n\n/**\n * Returns the raw HTML string for a mention span, useful for initializing contenteditable divs.\n */\nexport function getMentionHtml(userId: string, displayName: string): string {\n const safeName = displayName.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n return `<span class=\"${MENTION_SPAN_CLASS}\" data-mention-id=\"${userId}\" contenteditable=\"false\">@${safeName}</span> `;\n}\n\n/**\n * Insert an atomic mention <span> at the current cursor position inside a\n * contenteditable element, followed by a trailing space.\n */\nfunction insertMentionAtCursor(\n editableEl: HTMLElement,\n userId: string,\n displayName: string,\n) {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n\n const range = sel.getRangeAt(0);\n\n const { startContainer, startOffset } = range;\n if (startContainer.nodeType === Node.TEXT_NODE) {\n const textBefore = startContainer.textContent?.slice(0, startOffset) ?? '';\n const atIndex = textBefore.lastIndexOf('@');\n if (atIndex !== -1) {\n range.setStart(startContainer, atIndex);\n range.deleteContents();\n }\n }\n\n const span = document.createElement('span');\n span.className = MENTION_SPAN_CLASS;\n span.setAttribute('data-mention-id', userId);\n span.contentEditable = 'false';\n span.textContent = `@${displayName}`;\n\n range.insertNode(span);\n\n const space = document.createTextNode('\\u00A0');\n span.after(space);\n moveCaretAfterNode(space);\n\n editableEl.dispatchEvent(new Event('input', { bubbles: true }));\n}\n\n/**\n * Parse the DOM of a contenteditable div to produce a mention payload.\n */\nfunction buildPayloadFromDOM(editableEl: HTMLElement): MentionPayload {\n let text = '';\n let mentionedAll = false;\n const mentionedUsers: string[] = [];\n\n function walk(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent ?? '';\n return;\n }\n\n if (node instanceof HTMLElement) {\n const mentionId = node.getAttribute('data-mention-id');\n if (mentionId && node.classList.contains(MENTION_SPAN_CLASS)) {\n if (mentionId === '__all__') {\n mentionedAll = true;\n text += '@all';\n } else {\n if (!mentionedUsers.includes(mentionId)) {\n mentionedUsers.push(mentionId);\n }\n text += `@${mentionId}`;\n }\n return;\n }\n\n if (node.tagName === 'BR') {\n text += '\\n';\n return;\n }\n\n if (node.tagName === 'DIV' && text.length > 0 && !text.endsWith('\\n')) {\n text += '\\n';\n }\n }\n\n node.childNodes.forEach(walk);\n }\n\n walk(editableEl);\n text = text.replace(/\\u00A0/g, ' ').trim();\n\n return { text, mentioned_all: mentionedAll, mentioned_users: mentionedUsers };\n}\n\n/**\n * Scan the DOM for currently present mention spans and return their IDs.\n */\nfunction getActiveMentionIds(editableEl: HTMLElement): Set<string> {\n const ids = new Set<string>();\n const spans = editableEl.querySelectorAll(`.${MENTION_SPAN_CLASS}`);\n spans.forEach((span) => {\n const id = span.getAttribute('data-mention-id');\n if (id) ids.add(id);\n });\n return ids;\n}\n\nexport function useMentions({\n members,\n currentUserId,\n editableRef,\n}: UseMentionsOptions): UseMentionsReturn {\n const [showSuggestions, setShowSuggestions] = useState(false);\n const [query, setQuery] = useState('');\n const [highlightIndex, setHighlightIndex] = useState(0);\n const [activeMentionIds, setActiveMentionIds] = useState<Set<string>>(new Set());\n\n const deferredQuery = useDeferredValue(query);\n\n // All item: special entry\n const allItem: MentionMember = useMemo(\n () => ({ id: '__all__', name: 'all' }),\n [],\n );\n\n // Filter members based on deferred query, exclude self and already-mentioned\n const filteredMembers = useMemo(() => {\n const q = deferredQuery.toLowerCase();\n\n // Start with @all if not already selected\n const result: MentionMember[] = [];\n if (!activeMentionIds.has('__all__')) {\n if (!q || 'all'.includes(q)) {\n result.push(allItem);\n }\n }\n\n for (const m of members) {\n if (m.id === currentUserId) continue; // skip self\n if (activeMentionIds.has(m.id)) continue; // skip already mentioned\n if (q && !m.name.toLowerCase().includes(q)) continue; // filter by query\n result.push(m);\n }\n\n return result;\n }, [members, deferredQuery, activeMentionIds, currentUserId, allItem]);\n\n // Detect @ trigger from cursor position\n const detectTrigger = useCallback((): { triggered: boolean; query: string } => {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) {\n return { triggered: false, query: '' };\n }\n\n const { anchorNode, anchorOffset } = sel;\n if (!anchorNode || anchorNode.nodeType !== Node.TEXT_NODE) {\n return { triggered: false, query: '' };\n }\n\n const textBefore = anchorNode.textContent?.slice(0, anchorOffset) ?? '';\n\n // Find the last @ that is preceded by a space or is at the start\n const match = textBefore.match(/(^|[\\s\\u00A0])@(\\S*)$/);\n if (!match) {\n return { triggered: false, query: '' };\n }\n\n return { triggered: true, query: match[2] };\n }, []);\n\n const handleInput = useCallback(() => {\n const el = editableRef.current;\n if (!el) return;\n\n // Update active mention IDs by scanning DOM\n setActiveMentionIds(getActiveMentionIds(el));\n\n // Detect @ trigger\n const result = detectTrigger();\n if (result.triggered) {\n setShowSuggestions(true);\n setQuery(result.query);\n setHighlightIndex(0);\n } else {\n setShowSuggestions(false);\n setQuery('');\n }\n }, [editableRef, detectTrigger]);\n\n const selectMention = useCallback(\n (member: MentionMember) => {\n const el = editableRef.current;\n if (!el) return;\n\n insertMentionAtCursor(el, member.id, member.name);\n\n // Update tracking\n setActiveMentionIds((prev) => new Set(prev).add(member.id));\n setShowSuggestions(false);\n setQuery('');\n\n // Re-focus the editable\n el.focus();\n },\n [editableRef],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent): boolean => {\n if (!showSuggestions || filteredMembers.length === 0) return false;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n setHighlightIndex((prev) =>\n prev < filteredMembers.length - 1 ? prev + 1 : 0,\n );\n return true;\n\n case 'ArrowUp':\n e.preventDefault();\n setHighlightIndex((prev) =>\n prev > 0 ? prev - 1 : filteredMembers.length - 1,\n );\n return true;\n\n case 'Enter':\n e.preventDefault();\n if (filteredMembers[highlightIndex]) {\n selectMention(filteredMembers[highlightIndex]);\n }\n return true;\n\n case 'Escape':\n e.preventDefault();\n setShowSuggestions(false);\n return true;\n\n default:\n return false;\n }\n },\n [showSuggestions, filteredMembers, highlightIndex, selectMention],\n );\n\n const buildPayload = useCallback((): MentionPayload => {\n const el = editableRef.current;\n if (!el) return { text: '', mentioned_all: false, mentioned_users: [] };\n return buildPayloadFromDOM(el);\n }, [editableRef]);\n\n const reset = useCallback(() => {\n setShowSuggestions(false);\n setQuery('');\n setHighlightIndex(0);\n setActiveMentionIds(new Set());\n const el = editableRef.current;\n if (el) {\n el.innerHTML = '';\n }\n }, [editableRef]);\n\n return {\n showSuggestions,\n filteredMembers,\n highlightIndex,\n handleInput,\n handleKeyDown,\n selectMention,\n buildPayload,\n reset,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { isHeicFile, isVideoFile, normalizeFileName } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport type { FilePreviewItem } from '../types';\n\nlet _fileIdCounter = 0;\nfunction nextFileId(): string {\n return `file-${Date.now()}-${++_fileIdCounter}`;\n}\n\nexport type UseFileUploadOptions = {\n activeChannel: Channel | null;\n editableRef: React.RefObject<HTMLDivElement | null>;\n setHasContent: (value: boolean) => void;\n};\n\nexport function useFileUpload({ activeChannel, editableRef, setHasContent }: UseFileUploadOptions) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [files, setFiles] = useState<FilePreviewItem[]>([]);\n\n /**\n * Upload a single file immediately:\n * 1. Normalize file name\n * 2. Call sendFile API\n * 3. For video: generate + upload thumbnail\n * 4. Update file item state with uploaded URL\n */\n const uploadSingleFile = useCallback(async (item: FilePreviewItem) => {\n if (!activeChannel) return;\n\n try {\n const file = item.file!;\n const normalizedName = normalizeFileName(file.name);\n const fileToUpload = normalizedName !== file.name\n ? new File([file], normalizedName, { type: file.type, lastModified: file.lastModified })\n : file;\n\n const response = await activeChannel.sendFile(fileToUpload, fileToUpload.name, fileToUpload.type);\n const uploadedUrl = response.file;\n\n let thumbUrl = '';\n if (isVideoFile(file)) {\n try {\n const thumbBlob = await activeChannel.getThumbBlobVideo(file);\n if (thumbBlob) {\n const thumbFile = new File([thumbBlob], `thumb_${normalizedName}.jpg`, { type: 'image/jpeg' });\n const thumbResp = await activeChannel.sendFile(thumbFile, thumbFile.name, 'image/jpeg');\n thumbUrl = thumbResp.file;\n }\n } catch {\n // Thumbnail failure is non-critical\n }\n }\n\n setFiles((prev) =>\n prev.map((f) =>\n f.id === item.id\n ? { ...f, status: 'done' as const, uploadedUrl, thumbUrl, normalizedFile: fileToUpload }\n : f,\n ),\n );\n } catch (err: any) {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === item.id\n ? { ...f, status: 'error' as const, error: err?.message || 'Upload failed' }\n : f,\n ),\n );\n }\n }, [activeChannel]);\n\n const handleFilesSelected = useCallback((selectedFiles: FileList | null) => {\n if (!selectedFiles || selectedFiles.length === 0) return;\n\n const newItems: FilePreviewItem[] = Array.from(selectedFiles).map((file) => {\n const isPreviewable =\n (file.type.startsWith('image/') && !isHeicFile(file)) ||\n file.type.startsWith('video/');\n return {\n id: nextFileId(),\n file,\n previewUrl: isPreviewable ? URL.createObjectURL(file) : undefined,\n status: 'uploading' as const,\n };\n });\n\n setFiles((prev) => [...prev, ...newItems]);\n setHasContent(true);\n\n newItems.forEach((item) => uploadSingleFile(item));\n }, [uploadSingleFile, setHasContent]);\n\n const handleRemoveFile = useCallback((id: string) => {\n setFiles((prev) => {\n const item = prev.find((f) => f.id === id);\n if (item?.previewUrl) URL.revokeObjectURL(item.previewUrl);\n const remaining = prev.filter((f) => f.id !== id);\n const el = editableRef.current;\n const textContent = el?.textContent?.trim() ?? '';\n if (remaining.length === 0 && textContent.length === 0) {\n setHasContent(false);\n }\n return remaining;\n });\n }, [editableRef, setHasContent]);\n\n const handleAttachClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n // Cleanup blob URLs\n const cleanupFiles = useCallback(() => {\n files.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n }, [files]);\n\n return {\n files,\n setFiles,\n fileInputRef,\n handleFilesSelected,\n handleRemoveFile,\n handleAttachClick,\n cleanupFiles,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { moveCaretToEnd } from '../utils';\n\nexport type UseEmojiPickerOptions = {\n editableRef: React.RefObject<HTMLDivElement | null>;\n setHasContent: (value: boolean) => void;\n};\n\nexport function useEmojiPicker({ editableRef, setHasContent }: UseEmojiPickerOptions) {\n const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);\n const savedRangeRef = useRef<Range | null>(null);\n\n const handleEmojiSelect = useCallback((emoji: string) => {\n const el = editableRef.current;\n if (!el) return;\n\n // Restore saved cursor position, or move to end\n el.focus();\n const sel = window.getSelection();\n if (sel && savedRangeRef.current) {\n sel.removeAllRanges();\n sel.addRange(savedRangeRef.current);\n savedRangeRef.current = null;\n } else {\n moveCaretToEnd(el);\n }\n\n document.execCommand('insertText', false, emoji + ' ');\n setHasContent(true);\n setEmojiPickerOpen(false);\n }, [editableRef, setHasContent]);\n\n const handleEmojiClose = useCallback(() => {\n setEmojiPickerOpen(false);\n savedRangeRef.current = null;\n }, []);\n\n const toggleEmojiPicker = useCallback(() => {\n // Save current cursor position before picker steals focus\n const sel = window.getSelection();\n if (sel && sel.rangeCount > 0) {\n savedRangeRef.current = sel.getRangeAt(0).cloneRange();\n }\n setEmojiPickerOpen((prev) => !prev);\n }, []);\n\n return {\n emojiPickerOpen,\n handleEmojiSelect,\n handleEmojiClose,\n toggleEmojiPicker,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { buildAttachmentPayload } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { FilePreviewItem } from '../types';\n\nexport type UseMessageSendOptions = {\n activeChannel: Channel | null;\n editableRef: React.RefObject<HTMLDivElement | null>;\n files: FilePreviewItem[];\n setFiles: React.Dispatch<React.SetStateAction<FilePreviewItem[]>>;\n hasContent: boolean;\n setHasContent: (value: boolean) => void;\n isTeamChannel: boolean;\n buildPayload: () => { text: string; mentioned_all: boolean; mentioned_users: string[] };\n reset: () => void;\n syncMessages: () => void;\n onSend?: (text: string) => void;\n onBeforeSend?: (text: string, attachments: FilePreviewItem[]) => boolean | Promise<boolean>;\n /** Message being replied to */\n quotedMessage?: FormatMessageResponse | null;\n /** Clear quoted message after send */\n clearQuotedMessage?: () => void;\n /** Message being edited */\n editingMessage?: FormatMessageResponse | null;\n /** Clear edited message after send */\n clearEditingMessage?: () => void;\n};\n\nexport function useMessageSend({\n activeChannel,\n editableRef,\n files,\n setFiles,\n hasContent,\n setHasContent,\n isTeamChannel,\n buildPayload,\n reset,\n syncMessages,\n onSend,\n onBeforeSend,\n quotedMessage,\n clearQuotedMessage,\n editingMessage,\n clearEditingMessage,\n}: UseMessageSendOptions) {\n const [sending, setSending] = useState(false);\n const isProcessingRef = useRef(false);\n\n const handleSend = useCallback(async () => {\n if (!activeChannel || !hasContent || sending || isProcessingRef.current) return;\n\n // Wait for all files to finish uploading\n const stillUploading = files.some((f) => f.status === 'uploading');\n if (stillUploading) return;\n\n isProcessingRef.current = true;\n\n const payload = buildPayload();\n const text = payload.text.trim();\n const uploadedFiles = files.filter((f) => f.status === 'done');\n\n if (!text && uploadedFiles.length === 0) return;\n\n // onBeforeSend hook — return false to cancel\n if (onBeforeSend) {\n const proceed = await onBeforeSend(text, uploadedFiles);\n if (!proceed) {\n isProcessingRef.current = false;\n return;\n }\n }\n\n try {\n setSending(true);\n\n // Build attachment payloads from already-uploaded files (only applied on new messages)\n const attachments = uploadedFiles.map((f) => {\n if (f.originalAttachment) {\n return f.originalAttachment;\n }\n const fileObj = f.normalizedFile || f.file!;\n return buildAttachmentPayload(fileObj, f.uploadedUrl!, f.thumbUrl);\n });\n\n // Build message\n const message: Record<string, any> = { text };\n\n // The API does not accept attachment arrays during standard text editing\n if (!editingMessage && attachments.length > 0) {\n message.attachments = attachments;\n }\n\n if (isTeamChannel) {\n message.mentioned_all = payload.mentioned_all;\n message.mentioned_users = payload.mentioned_users;\n }\n let sendPromise;\n\n if (editingMessage?.id) {\n sendPromise = activeChannel.editMessage(editingMessage.id, message as any);\n } else {\n if (quotedMessage?.id) {\n message.quoted_message_id = quotedMessage.id;\n }\n sendPromise = activeChannel.sendMessage(message as any);\n }\n\n // --- 0. OPTIMISTIC UI UPDATE ---\n // Instantly injects the `status: 'sending'` message scaffold from SDK into the React map\n syncMessages();\n\n // --- 1. CLEAR UI IMMEDIATELY (FIRE AND FORGET) ---\n // Clear successful files\n files.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n\n const errorFiles = files.filter((f) => f.status === 'error');\n setFiles(errorFiles);\n setHasContent(errorFiles.length > 0);\n\n reset();\n clearQuotedMessage?.();\n clearEditingMessage?.();\n onSend?.(payload.text);\n // Stop typing indicator immediately on send\n activeChannel?.stopTyping();\n\n // --- 2. DELEGATE TO WEBSOCKET ---\n // The API call runs in background. We do not block the UI for resolution.\n // Message lists will automatically update when the backend blasts the `message.new` WS event.\n sendPromise.catch((err: Error) => {\n console.error('Failed to send message over API:', err);\n // Sync React to render the SDK's internal 'status: failed' UI state\n syncMessages();\n });\n } catch (err) {\n console.error('Failed to process message send:', err);\n } finally {\n isProcessingRef.current = false;\n setSending(false);\n requestAnimationFrame(() => {\n editableRef.current?.focus();\n });\n }\n }, [\n activeChannel,\n hasContent,\n sending,\n buildPayload,\n reset,\n onSend,\n isTeamChannel,\n files,\n onBeforeSend,\n syncMessages,\n editableRef,\n setFiles,\n setHasContent,\n ]);\n\n return { sending, handleSend };\n}\n","import React from 'react';\n\n/* ----------------------------------------------------------\n Default sub-components for MessageInput\n ---------------------------------------------------------- */\n\nexport const DefaultSendButton: React.FC<{ disabled: boolean; onClick: () => void }> = React.memo(({\n disabled,\n onClick,\n}) => (\n <button\n className=\"ermis-message-input__send-btn\"\n onClick={onClick}\n disabled={disabled}\n >\n Send\n </button>\n));\nDefaultSendButton.displayName = 'DefaultSendButton';\n\nexport const DefaultAttachButton: React.FC<{ disabled: boolean; onClick: () => void }> = React.memo(({\n disabled,\n onClick,\n}) => (\n <button\n className=\"ermis-message-input__attach-btn\"\n onClick={onClick}\n type=\"button\"\n aria-label=\"Attach files\"\n disabled={disabled}\n >\n 📎\n </button>\n));\nDefaultAttachButton.displayName = 'DefaultAttachButton';\n\nexport const DefaultEmojiButton: React.FC<{ active: boolean; onClick: () => void }> = React.memo(({\n active,\n onClick,\n}) => (\n <button\n className={`ermis-message-input__emoji-btn${active ? ' ermis-message-input__emoji-btn--active' : ''}`}\n onClick={onClick}\n type=\"button\"\n aria-label=\"Emoji\"\n >\n 😀\n </button>\n));\nDefaultEmojiButton.displayName = 'DefaultEmojiButton';\n","import React, { useEffect, useRef } from 'react';\nimport { VList, VListHandle } from 'virtua';\nimport { Avatar } from './Avatar';\nimport type { MentionSuggestionsProps } from '../types';\n\nexport type { MentionSuggestionsProps } from '../types';\n\n// Estimated item height\nconst ITEM_HEIGHT = 42; \n\nexport const MentionSuggestions: React.FC<MentionSuggestionsProps> = React.memo(({\n members,\n highlightIndex,\n onSelect,\n}) => {\n const listRef = useRef<VListHandle>(null);\n\n // Auto-scroll highlighted item into view\n useEffect(() => {\n // VList uses scrollToIndex\n listRef.current?.scrollToIndex(highlightIndex);\n }, [highlightIndex]);\n\n if (members.length === 0) return null;\n\n // Calculate dynamic height based on item count, cap at 200px\n const listHeight = Math.min(members.length * ITEM_HEIGHT, 200);\n\n return (\n <div className=\"ermis-mention-suggestions\" style={{ overflow: 'hidden' }}>\n <VList ref={listRef} style={{ height: listHeight }}>\n {members.map((member, index) => (\n <div\n key={member.id}\n className={`ermis-mention-suggestions__item${\n index === highlightIndex ? ' ermis-mention-suggestions__item--highlighted' : ''\n }`}\n onMouseDown={(e) => {\n // Use mousedown (not click) to fire before blur\n e.preventDefault();\n onSelect(member);\n }}\n >\n {member.id === '__all__' ? (\n <div className=\"ermis-mention-suggestions__all-icon\">@</div>\n ) : (\n <Avatar image={member.avatar} name={member.name} size={24} />\n )}\n <span className=\"ermis-mention-suggestions__name\">\n {member.id === '__all__' ? 'all' : member.name}\n </span>\n </div>\n ))}\n </VList>\n </div>\n );\n});\n\nMentionSuggestions.displayName = 'MentionSuggestions';\n","import React from 'react';\nimport { isHeicFile } from '@ermis-network/ermis-chat-sdk';\nimport type { FilesPreviewProps } from '../types';\n\nexport type { FilePreviewItem, FilesPreviewProps } from '../types';\n/**\n * Format file size into human-readable string.\n */\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Get a display icon for non-previewable file types.\n */\nfunction getFileIcon(mimeType: string): string {\n if (mimeType.startsWith('audio/')) return '🎵';\n if (mimeType.startsWith('video/')) return '🎬';\n if (mimeType.includes('pdf')) return '📄';\n if (mimeType.includes('zip') || mimeType.includes('rar') || mimeType.includes('tar')) return '📦';\n return '📎';\n}\n\n/**\n * FilesPreview — renders selected files with thumbnails and remove buttons.\n * Shown above the text input area in MessageInput.\n */\nexport const FilesPreview: React.FC<FilesPreviewProps> = React.memo(({ files, onRemove }) => {\n if (files.length === 0) return null;\n\n return (\n <div className=\"ermis-files-preview\">\n {files.map((item) => {\n const fileType = item.file?.type || item.originalAttachment?.mime_type || '';\n const fileName = item.file?.name || item.originalAttachment?.title || 'Unknown file';\n const fileSize = item.file?.size || item.originalAttachment?.file_size || 0;\n\n const isHeic = item.file ? isHeicFile(item.file) : (fileType === 'image/heic' || fileType === 'image/heif');\n const isImage = fileType.startsWith('image/') && !isHeic;\n const isVideo = fileType.startsWith('video/');\n const isUploading = item.status === 'uploading';\n const hasError = item.status === 'error';\n\n const previewUrl = item.previewUrl || item.originalAttachment?.image_url || item.originalAttachment?.asset_url;\n\n return (\n <div\n key={item.id}\n className={`ermis-files-preview__item${hasError ? ' ermis-files-preview__item--error' : ''}`}\n >\n {/* Remove button */}\n <button\n className=\"ermis-files-preview__remove\"\n onClick={() => onRemove(item.id)}\n aria-label=\"Remove file\"\n type=\"button\"\n >\n ✕\n </button>\n\n {/* Preview content */}\n {isImage && previewUrl ? (\n <img\n className=\"ermis-files-preview__thumb\"\n src={previewUrl}\n alt={fileName}\n />\n ) : isVideo && previewUrl ? (\n <video\n className=\"ermis-files-preview__thumb\"\n src={previewUrl}\n muted\n />\n ) : (\n <div className=\"ermis-files-preview__file-icon\">\n <span>{getFileIcon(fileType)}</span>\n </div>\n )}\n\n {/* File info */}\n <div className=\"ermis-files-preview__info\">\n <span className=\"ermis-files-preview__name\">{fileName}</span>\n <span className=\"ermis-files-preview__size\">{formatFileSize(Number(fileSize))}</span>\n </div>\n\n {/* Upload status overlay */}\n {isUploading && (\n <div className=\"ermis-files-preview__uploading\">\n <span className=\"ermis-files-preview__spinner\" />\n </div>\n )}\n\n {/* Error overlay */}\n {hasError && (\n <div className=\"ermis-files-preview__error-badge\" title={item.error}>\n ⚠\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n});\n\nFilesPreview.displayName = 'FilesPreview';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { ReplyPreviewProps } from '../types';\n\nconst MAX_PREVIEW_LENGTH = 120;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\n/** Get a human-readable summary of attachments */\nfunction getAttachmentSummary(attachments: any[]): string {\n if (!attachments || attachments.length === 0) return '';\n\n const types: Record<string, number> = {};\n for (const att of attachments) {\n const type = att.type || 'file';\n types[type] = (types[type] || 0) + 1;\n }\n\n const labels: string[] = [];\n const typeLabels: Record<string, string> = {\n image: '🖼️ Image',\n video: '🎬 Video',\n audio: '🎵 Audio',\n file: '📎 File',\n voiceRecording: '🎤 Voice',\n };\n\n for (const [type, count] of Object.entries(types)) {\n const label = typeLabels[type] || `📎 ${type}`;\n labels.push(count > 1 ? `${label} (${count})` : label);\n }\n\n return labels.join(', ');\n}\nexport const ReplyPreview: React.FC<ReplyPreviewProps> = React.memo(({\n message,\n onDismiss,\n replyingToLabel = 'Replying to',\n}) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const userName = message.user?.name || message.user_id || 'Unknown';\n \n const rawText = message.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, message, userMap), [rawText, message, userMap]);\n const hasText = !!formattedText.trim();\n const hasAttachments = message.attachments && message.attachments.length > 0;\n const isSticker = message.type === 'sticker';\n const attachmentSummary = hasAttachments ? getAttachmentSummary(message.attachments!) : '';\n\n // Build preview content\n let previewContent: React.ReactNode = null;\n if (isSticker) {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n 😀 Sticker\n </span>\n );\n } else {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n {hasText && truncateText(formattedText, MAX_PREVIEW_LENGTH)}\n {hasText && hasAttachments && ' · '}\n {hasAttachments && attachmentSummary}\n </span>\n );\n }\n\n return (\n <div className=\"ermis-message-input__reply-preview\">\n <div className=\"ermis-message-input__reply-preview-body\">\n <span className=\"ermis-message-input__reply-preview-label\">{replyingToLabel}</span>\n <span className=\"ermis-message-input__reply-preview-user\">{userName}</span>\n {previewContent}\n </div>\n <button\n className=\"ermis-message-input__reply-preview-dismiss\"\n onClick={onDismiss}\n title=\"Cancel reply\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n );\n});\n\nReplyPreview.displayName = 'ReplyPreview';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\n\nconst MAX_PREVIEW_LENGTH = 120;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\n/** Get a human-readable summary of attachments */\nfunction getAttachmentSummary(attachments: any[]): string {\n if (!attachments || attachments.length === 0) return '';\n\n const types: Record<string, number> = {};\n for (const att of attachments) {\n const type = att.type || 'file';\n types[type] = (types[type] || 0) + 1;\n }\n\n const labels: string[] = [];\n const typeLabels: Record<string, string> = {\n image: '🖼️ Image',\n video: '🎬 Video',\n audio: '🎵 Audio',\n file: '📎 File',\n voiceRecording: '🎤 Voice',\n };\n\n for (const [type, count] of Object.entries(types)) {\n const label = typeLabels[type] || `📎 ${type}`;\n labels.push(count > 1 ? `${label} (${count})` : label);\n }\n\n return labels.join(', ');\n}\nexport const EditPreview: React.FC<{\n message: FormatMessageResponse;\n onDismiss: () => void;\n}> = React.memo(({\n message,\n onDismiss,\n editingMessageLabel = 'Editing message',\n}: any) => {\n console.log('--message--', message)\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const userName = message.user?.name || message.user_id || 'Unknown';\n\n const rawText = message.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, message, userMap), [rawText, message, userMap]);\n const hasText = !!formattedText.trim();\n const hasAttachments = message.attachments && message.attachments.length > 0;\n const isSticker = message.type === 'sticker';\n const attachmentSummary = hasAttachments ? getAttachmentSummary(message.attachments!) : '';\n\n // Build preview content\n let previewContent: React.ReactNode = null;\n if (isSticker) {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n 😀 Sticker\n </span>\n );\n } else {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n {hasText && truncateText(formattedText, MAX_PREVIEW_LENGTH)}\n {hasText && hasAttachments && ' · '}\n {hasAttachments && attachmentSummary}\n </span>\n );\n }\n\n return (\n <div className=\"ermis-message-input__reply-preview\">\n <div className=\"ermis-message-input__reply-preview-body\">\n <span className=\"ermis-message-input__reply-preview-label\">{editingMessageLabel}</span>\n <span className=\"ermis-message-input__reply-preview-user\">{userName}</span>\n {previewContent}\n </div>\n <button\n className=\"ermis-message-input__reply-preview-dismiss\"\n onClick={onDismiss}\n title=\"Cancel edit\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n );\n});\n\nEditPreview.displayName = 'EditPreview';\n","import React, { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport { useBannedState } from '../../hooks/useBannedState';\nimport { useBlockedState } from '../../hooks/useBlockedState';\nimport { Avatar } from '../Avatar';\nimport { DefaultChannelInfoTabs } from './ChannelInfoTabs';\nimport { AddMemberModal } from './AddMemberModal';\nimport { EditChannelModal } from './EditChannelModal';\nimport { MessageSearchPanel } from './MessageSearchPanel';\nimport { ChannelSettingsPanel } from './ChannelSettingsPanel';\nimport type {\n ChannelInfoProps,\n ChannelInfoHeaderProps,\n ChannelInfoCoverProps,\n ChannelInfoActionsProps,\n} from '../../types';\nimport { useChannelMembers, useChannelProfile } from '../../hooks/useChannelData';\n\nexport const DefaultChannelInfoHeader: React.FC<ChannelInfoHeaderProps> = React.memo(({ title, onClose }) => {\n return (\n <div className=\"ermis-channel-info__header\">\n <h3 className=\"ermis-channel-info__title\">{title}</h3>\n {onClose && (\n <button className=\"ermis-channel-info__close\" onClick={onClose} aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n )}\n </div>\n );\n});\nDefaultChannelInfoHeader.displayName = 'DefaultChannelInfoHeader';\n\nexport const DefaultChannelInfoCover: React.FC<ChannelInfoCoverProps> = React.memo(({ channelName, channelImage, channelDescription, AvatarComponent, canEdit, onEditClick, isPublic, isTeamChannel }) => {\n return (\n <div className=\"ermis-channel-info__cover\">\n <AvatarComponent image={channelImage} name={channelName} size={80} className=\"ermis-channel-info__avatar\" />\n <div className=\"ermis-channel-info__name-row\">\n <h2 className=\"ermis-channel-info__name\">{channelName}</h2>\n {canEdit && onEditClick && (\n <button className=\"ermis-channel-info__cover-edit-btn\" onClick={onEditClick} aria-label=\"Edit channel\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" />\n </svg>\n </button>\n )}\n </div>\n {isTeamChannel && (\n <span className={`ermis-channel-info__type-badge ${isPublic ? 'ermis-channel-info__type-badge--public' : 'ermis-channel-info__type-badge--private'}`}>\n {isPublic ? (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\" />\n <path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\" />\n </svg>\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n )}\n {isPublic ? 'Public' : 'Private'}\n </span>\n )}\n {channelDescription && (\n <p className=\"ermis-channel-info__description\">{channelDescription}</p>\n )}\n </div>\n );\n});\nDefaultChannelInfoCover.displayName = 'DefaultChannelInfoCover';\n\nexport const DefaultChannelInfoActions: React.FC<ChannelInfoActionsProps> = React.memo(({\n onSearchClick, onSettingsClick, onLeaveChannel, onDeleteChannel,\n onBlockUser, onUnblockUser,\n isTeamChannel, isBlocked, currentUserRole,\n searchLabel = 'Search', settingsLabel = 'Settings', deleteLabel = 'Delete', leaveLabel = 'Leave',\n blockLabel = 'Block', unblockLabel = 'Unblock'\n}) => {\n return (\n <div className=\"ermis-channel-info__actions\">\n <button className=\"ermis-channel-info__action-btn\" onClick={onSearchClick} disabled={isBlocked}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n </svg>\n </div>\n <span>{searchLabel}</span>\n </button>\n {isTeamChannel && (currentUserRole === 'owner' || currentUserRole === 'moder') && (\n <button className=\"ermis-channel-info__action-btn\" onClick={onSettingsClick}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path>\n </svg>\n </div>\n <span>{settingsLabel}</span>\n </button>\n )}\n {isTeamChannel && (\n currentUserRole === 'owner' ? (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onDeleteChannel}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\"></polyline>\n <path d=\"M19 6V20a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n </svg>\n </div>\n <span>{deleteLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onLeaveChannel}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"></path>\n <polyline points=\"16 17 21 12 16 7\"></polyline>\n <line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"></line>\n </svg>\n </div>\n <span>{leaveLabel}</span>\n </button>\n )\n )}\n {/* Block/Unblock — messaging (1-1) channels only */}\n {!isTeamChannel && (\n isBlocked ? (\n <button className=\"ermis-channel-info__action-btn\" onClick={onUnblockUser}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span>{unblockLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onBlockUser}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span>{blockLabel}</span>\n </button>\n )\n )}\n </div>\n );\n});\nDefaultChannelInfoActions.displayName = 'DefaultChannelInfoActions';\n\nexport const ChannelInfo: React.FC<ChannelInfoProps> = React.memo((props) => {\n const {\n channel: channelProp,\n className = '',\n AvatarComponent = Avatar,\n onClose,\n title = 'Channel Info',\n HeaderComponent = DefaultChannelInfoHeader,\n CoverComponent = DefaultChannelInfoCover,\n ActionsComponent = DefaultChannelInfoActions,\n TabsComponent = DefaultChannelInfoTabs,\n AddMemberModalComponent,\n EditChannelModalComponent,\n actionsSearchLabel,\n actionsSettingsLabel,\n actionsDeleteLabel,\n actionsLeaveLabel,\n MemberItemComponent,\n MediaItemComponent,\n LinkItemComponent,\n FileItemComponent,\n EmptyStateComponent,\n LoadingComponent,\n onSearchClick,\n onLeaveChannel: onLeaveChannelProp,\n onDeleteChannel: onDeleteChannelProp,\n onAddMemberClick,\n onRemoveMember: onRemoveMemberProp,\n onBanMember: onBanMemberProp,\n onUnbanMember: onUnbanMemberProp,\n onPromoteMember: onPromoteMemberProp,\n onDemoteMember: onDemoteMemberProp,\n // Add Member customization\n addMemberModalTitle,\n addMemberSearchPlaceholder,\n addMemberLoadingText,\n addMemberEmptyText,\n addMemberAddLabel,\n addMemberAddingLabel,\n addMemberAddedLabel,\n addMemberButtonLabel,\n AddMemberButtonComponent,\n // Edit Channel customization\n onEditChannel: onEditChannelProp,\n editChannelModalTitle,\n editChannelNameLabel,\n editChannelDescriptionLabel,\n editChannelNamePlaceholder,\n editChannelDescriptionPlaceholder,\n editChannelPublicLabel,\n editChannelSaveLabel,\n editChannelCancelLabel,\n editChannelSavingLabel,\n editChannelChangeAvatarLabel,\n editChannelImageAccept,\n editChannelMaxImageSize,\n editChannelMaxImageSizeError,\n // Block/Unblock customization (messaging channels)\n onBlockUser: onBlockUserProp,\n onUnblockUser: onUnblockUserProp,\n actionsBlockLabel,\n actionsUnblockLabel,\n } = props;\n\n const { activeChannel, client } = useChatClient();\n const channel = channelProp || activeChannel;\n const { isBanned } = useBannedState(channel, client?.userID);\n const { isBlocked } = useBlockedState(channel, client?.userID);\n\n const currentUserId = client?.userID;\n const currentUserRole = currentUserId ? channel?.state?.members?.[currentUserId]?.channel_role : undefined;\n const isTeamChannel = channel?.type === 'team';\n\n const handleDeleteChannel = useCallback(async () => {\n if (onDeleteChannelProp) return onDeleteChannelProp();\n if (!channel) return;\n try {\n await channel.delete();\n } catch (e) {\n console.error(\"Error deleting channel\", e);\n }\n }, [channel, onDeleteChannelProp]);\n\n const handleLeaveChannel = useCallback(async () => {\n if (onLeaveChannelProp) return onLeaveChannelProp();\n if (!channel || !currentUserId) return;\n try {\n await channel.removeMembers([currentUserId]);\n } catch (e) {\n console.error(\"Error leaving channel\", e);\n }\n }, [channel, currentUserId, onLeaveChannelProp]);\n\n const handleRemoveMember = useCallback(async (memberId: string) => {\n if (onRemoveMemberProp) return onRemoveMemberProp(memberId);\n if (!channel) return;\n try {\n await channel.removeMembers([memberId]);\n } catch (e) {\n console.error(\"Error removing member\", e);\n }\n }, [channel, onRemoveMemberProp]);\n\n const handleBanMember = useCallback(async (memberId: string) => {\n if (onBanMemberProp) return onBanMemberProp(memberId);\n if (!channel) return;\n try { await channel.banMembers([memberId]); } catch (e) { console.error(\"Error banning member\", e); }\n }, [channel, onBanMemberProp]);\n\n const handleUnbanMember = useCallback(async (memberId: string) => {\n if (onUnbanMemberProp) return onUnbanMemberProp(memberId);\n if (!channel) return;\n try { await channel.unbanMembers([memberId]); } catch (e) { console.error(\"Error unbanning member\", e); }\n }, [channel, onUnbanMemberProp]);\n\n const handlePromoteMember = useCallback(async (memberId: string) => {\n if (onPromoteMemberProp) return onPromoteMemberProp(memberId);\n if (!channel) return;\n try { await channel.addModerators([memberId]); } catch (e) { console.error(\"Error promoting member\", e); }\n }, [channel, onPromoteMemberProp]);\n\n const handleDemoteMember = useCallback(async (memberId: string) => {\n if (onDemoteMemberProp) return onDemoteMemberProp(memberId);\n if (!channel) return;\n try { await channel.demoteModerators([memberId]); } catch (e) { console.error(\"Error demoting member\", e); }\n }, [channel, onDemoteMemberProp]);\n\n const handleBlockUser = useCallback(async () => {\n if (onBlockUserProp) return onBlockUserProp();\n if (!channel) return;\n try { await channel.blockUser(); } catch (e) { console.error('Error blocking user', e); }\n }, [channel, onBlockUserProp]);\n\n const handleUnblockUser = useCallback(async () => {\n if (onUnblockUserProp) return onUnblockUserProp();\n if (!channel) return;\n try { await channel.unblockUser(); } catch (e) { console.error('Error unblocking user', e); }\n }, [channel, onUnblockUserProp]);\n\n const { members } = useChannelMembers(channel);\n const { channelName, channelImage, channelDescription } = useChannelProfile(channel);\n\n const [showAddMemberModal, setShowAddMemberModal] = useState(false);\n const [showEditChannelModal, setShowEditChannelModal] = useState(false);\n const [showSearchPanel, setShowSearchPanel] = useState(false);\n const [showSettingsPanel, setShowSettingsPanel] = useState(false);\n\n // Permission: only owner or moderator can edit channel info (banned users cannot)\n const canEditChannel = isTeamChannel && !isBanned && (currentUserRole === 'owner' || currentUserRole === 'moder');\n\n const handleEditChannelClick = useCallback(() => {\n setShowEditChannelModal(true);\n }, []);\n\n const handleAddMemberClick = useCallback(() => {\n if (onAddMemberClick) return onAddMemberClick();\n setShowAddMemberModal(true);\n }, [onAddMemberClick]);\n\n\n\n if (!channel) return null;\n\n return (\n <div className={`ermis-channel-info ${className}`.trim()}>\n <HeaderComponent title={title} onClose={onClose} />\n\n <CoverComponent\n channelName={channelName}\n channelImage={channelImage}\n channelDescription={channelDescription}\n AvatarComponent={AvatarComponent}\n canEdit={canEditChannel}\n onEditClick={handleEditChannelClick}\n isPublic={Boolean(channel?.data?.public)}\n isTeamChannel={isTeamChannel}\n />\n\n {isBanned ? (\n <div className=\"ermis-channel-info__banned-banner\">\n <div className=\"ermis-channel-info__banned-banner-icon\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span className=\"ermis-channel-info__banned-banner-text\">You have been blocked from this channel</span>\n </div>\n ) : (\n <>\n <ActionsComponent\n onSearchClick={() => setShowSearchPanel(true)}\n onSettingsClick={() => setShowSettingsPanel(true)}\n onLeaveChannel={handleLeaveChannel}\n onDeleteChannel={handleDeleteChannel}\n onBlockUser={handleBlockUser}\n onUnblockUser={handleUnblockUser}\n isTeamChannel={isTeamChannel}\n isBlocked={isBlocked}\n currentUserRole={currentUserRole}\n searchLabel={actionsSearchLabel}\n settingsLabel={actionsSettingsLabel}\n deleteLabel={actionsDeleteLabel}\n leaveLabel={actionsLeaveLabel}\n blockLabel={actionsBlockLabel}\n unblockLabel={actionsUnblockLabel}\n />\n\n <TabsComponent\n channel={channel}\n members={members as any}\n AvatarComponent={AvatarComponent}\n currentUserId={currentUserId}\n currentUserRole={currentUserRole}\n onAddMemberClick={isTeamChannel ? handleAddMemberClick : undefined}\n onRemoveMember={handleRemoveMember}\n onBanMember={handleBanMember}\n onUnbanMember={handleUnbanMember}\n onPromoteMember={handlePromoteMember}\n onDemoteMember={handleDemoteMember}\n addMemberButtonLabel={addMemberButtonLabel}\n AddMemberButtonComponent={AddMemberButtonComponent}\n MemberItemComponent={MemberItemComponent}\n MediaItemComponent={MediaItemComponent}\n LinkItemComponent={LinkItemComponent}\n FileItemComponent={FileItemComponent}\n EmptyStateComponent={EmptyStateComponent}\n LoadingComponent={LoadingComponent}\n />\n\n {showAddMemberModal && (() => {\n const ModalComp = AddMemberModalComponent || AddMemberModal;\n return (\n <ModalComp\n channel={channel}\n currentMembers={members as any}\n onClose={() => setShowAddMemberModal(false)}\n AvatarComponent={AvatarComponent}\n title={addMemberModalTitle}\n searchPlaceholder={addMemberSearchPlaceholder}\n loadingText={addMemberLoadingText}\n emptyText={addMemberEmptyText}\n addLabel={addMemberAddLabel}\n addingLabel={addMemberAddingLabel}\n addedLabel={addMemberAddedLabel}\n />\n );\n })()}\n\n {showEditChannelModal && (() => {\n const EditComp = EditChannelModalComponent || EditChannelModal;\n return (\n <EditComp\n channel={channel}\n onClose={() => setShowEditChannelModal(false)}\n onSave={onEditChannelProp}\n AvatarComponent={AvatarComponent}\n title={editChannelModalTitle}\n nameLabel={editChannelNameLabel}\n descriptionLabel={editChannelDescriptionLabel}\n namePlaceholder={editChannelNamePlaceholder}\n descriptionPlaceholder={editChannelDescriptionPlaceholder}\n publicLabel={editChannelPublicLabel}\n saveLabel={editChannelSaveLabel}\n cancelLabel={editChannelCancelLabel}\n savingLabel={editChannelSavingLabel}\n changeAvatarLabel={editChannelChangeAvatarLabel}\n imageAccept={editChannelImageAccept}\n maxImageSize={editChannelMaxImageSize}\n maxImageSizeError={editChannelMaxImageSizeError}\n />\n );\n })()}\n </>\n )}\n\n {/* Search Panel — slides over entire ChannelInfo body */}\n {channel && showSearchPanel && (\n <MessageSearchPanel\n isOpen={showSearchPanel}\n onClose={() => setShowSearchPanel(false)}\n channel={channel}\n AvatarComponent={AvatarComponent}\n />\n )}\n\n {/* Settings Panel — slides over entire ChannelInfo body */}\n {channel && showSettingsPanel && (\n <ChannelSettingsPanel\n isOpen={showSettingsPanel}\n onClose={() => setShowSettingsPanel(false)}\n channel={channel}\n />\n )}\n </div>\n );\n});\n\nChannelInfo.displayName = 'ChannelInfo';\n","import React, { useState, useEffect, useMemo, useCallback, useDeferredValue } from 'react';\nimport { VList } from 'virtua';\nimport { ROLE_WEIGHTS, MESSAGING_TABS, ALL_TABS, PENDING_STYLE, READY_STYLE } from './utils';\nimport { useBannedState } from '../../hooks/useBannedState';\nimport { useBlockedState } from '../../hooks/useBlockedState';\nimport { MediaGridItem, MediaRow } from './MediaGridItem';\nimport { LinkListItem } from './LinkListItem';\nimport { FileListItem } from './FileListItem';\nimport { MemberListItem } from './MemberListItem';\nimport { TabEmptyState, TabLoadingState } from './States';\nimport type { ChannelInfoTabsProps, MediaTab, AttachmentItem } from '../../types';\n\nexport const DefaultChannelInfoTabs: React.FC<ChannelInfoTabsProps> = React.memo(({\n channel,\n members,\n AvatarComponent,\n currentUserId,\n currentUserRole,\n onAddMemberClick,\n onRemoveMember,\n onBanMember,\n onUnbanMember,\n onPromoteMember,\n onDemoteMember,\n addMemberButtonLabel = 'Add Member',\n AddMemberButtonComponent,\n MemberItemComponent,\n MediaItemComponent,\n LinkItemComponent,\n FileItemComponent,\n EmptyStateComponent,\n LoadingComponent,\n}) => {\n const isMessaging = channel?.type === 'messaging';\n const { isBanned } = useBannedState(channel, currentUserId);\n const { isBlocked } = useBlockedState(channel, currentUserId);\n\n const availableTabs: MediaTab[] = isMessaging ? MESSAGING_TABS : ALL_TABS;\n\n const [activeTab, setActiveTab] = useState<MediaTab>(availableTabs[0]);\n const contentTab = useDeferredValue(activeTab);\n const isPending = activeTab !== contentTab;\n\n // Always reset to the first available tab when the user switches channels\n useEffect(() => {\n setActiveTab(availableTabs[0]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [channel?.cid]);\n\n // Resolve sub-components with defaults\n const MemberItem = MemberItemComponent || MemberListItem;\n const MediaItem = MediaItemComponent || MediaGridItem;\n const LinkItem = LinkItemComponent || LinkListItem;\n const FileItem = FileItemComponent || FileListItem;\n const EmptyState = EmptyStateComponent || TabEmptyState;\n const Loading = LoadingComponent || TabLoadingState;\n\n const [allAttachments, setAllAttachments] = useState<AttachmentItem[]>([]);\n const [loading, setLoading] = useState(true);\n\n const sortedMembers = useMemo(() => {\n return [...members].sort((a, b) => {\n const aWeight = ROLE_WEIGHTS[a.channel_role || 'member'] || 0;\n const bWeight = ROLE_WEIGHTS[b.channel_role || 'member'] || 0;\n return bWeight - aWeight;\n });\n }, [members]);\n\n // Categorize attachments by type\n const mediaItems = useMemo(() =>\n allAttachments.filter(a => a.attachment_type === 'image' || a.attachment_type === 'video'),\n [allAttachments]\n );\n\n const linkItems = useMemo(() =>\n allAttachments.filter(a => a.attachment_type === 'linkPreview'),\n [allAttachments]\n );\n\n const fileItems = useMemo(() =>\n allAttachments.filter(a => a.attachment_type === 'file' || a.attachment_type === 'voiceRecording'),\n [allAttachments]\n );\n\n useEffect(() => {\n let active = true;\n\n // Don't fetch media/files if user is banned or blocked\n if (isBanned || isBlocked) {\n setAllAttachments([]);\n setLoading(false);\n return;\n }\n\n const fetchMedia = async () => {\n setLoading(true);\n try {\n const response: any = await channel.queryAttachmentMessages();\n\n if (active) {\n const items = response?.attachments || [];\n setAllAttachments(items);\n }\n } catch (err) {\n console.error(\"Failed to query media for channel info\", err);\n if (active) setAllAttachments([]);\n } finally {\n if (active) setLoading(false);\n }\n };\n\n fetchMedia();\n\n return () => { active = false; };\n }, [channel, isBanned, isBlocked]);\n\n const tabCounts = useMemo<Record<MediaTab, number>>(() => ({\n members: members.length,\n media: mediaItems.length,\n links: linkItems.length,\n files: fileItems.length,\n }), [members.length, mediaItems.length, linkItems.length, fileItems.length]);\n\n const handleOpenUrl = useCallback((url: string) => {\n window.open(url, '_blank', 'noopener,noreferrer');\n }, []);\n\n // Group media into rows of 3 for grid layout inside VList\n const mediaRows = useMemo(() => {\n const rows: AttachmentItem[][] = [];\n for (let i = 0; i < mediaItems.length; i += 3) {\n rows.push(mediaItems.slice(i, i + 3));\n }\n return rows;\n }, [mediaItems]);\n\n // Build VList children based on contentTab (deferred)\n const vlistChildren = useMemo(() => {\n switch (contentTab) {\n case 'members': {\n const items: React.ReactNode[] = [];\n if (onAddMemberClick) {\n if (AddMemberButtonComponent) {\n items.push(\n <div key=\"__add-member__\" className=\"ermis-channel-info__add-member-wrap\">\n <AddMemberButtonComponent onClick={onAddMemberClick} label={addMemberButtonLabel} />\n </div>\n );\n } else {\n items.push(\n <div key=\"__add-member__\" className=\"ermis-channel-info__add-member-wrap\">\n <button className=\"ermis-channel-info__add-member-btn\" onClick={onAddMemberClick}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\"></path>\n <circle cx=\"8.5\" cy=\"7\" r=\"4\"></circle>\n <line x1=\"20\" y1=\"8\" x2=\"20\" y2=\"14\"></line>\n <line x1=\"23\" y1=\"11\" x2=\"17\" y2=\"11\"></line>\n </svg>\n {addMemberButtonLabel}\n </button>\n </div>\n );\n }\n }\n sortedMembers.forEach(member => {\n const role = member.channel_role || 'member';\n const isTargetRemovable = role === 'member' || role === 'pending' || (currentUserRole === 'owner' && role === 'moder');\n\n const canRemove = Boolean(\n (currentUserRole === 'owner' || currentUserRole === 'moder') &&\n isTargetRemovable &&\n member.user_id !== currentUserId\n );\n\n const canBan = Boolean(\n (currentUserRole === 'owner' || currentUserRole === 'moder') &&\n isTargetRemovable &&\n role !== 'pending' &&\n member.user_id !== currentUserId &&\n !member.banned\n );\n\n const canUnban = Boolean(\n (currentUserRole === 'owner' || currentUserRole === 'moder') &&\n isTargetRemovable &&\n role !== 'pending' &&\n member.user_id !== currentUserId &&\n member.banned\n );\n\n const canPromote = Boolean(\n currentUserRole === 'owner' &&\n role === 'member' &&\n member.user_id !== currentUserId\n );\n\n const canDemote = Boolean(\n currentUserRole === 'owner' &&\n role === 'moder' &&\n member.user_id !== currentUserId\n );\n\n items.push(\n <MemberItem\n key={member?.user_id}\n member={member}\n AvatarComponent={AvatarComponent}\n onRemove={onRemoveMember}\n canRemove={canRemove}\n onBan={onBanMember}\n canBan={canBan}\n onUnban={onUnbanMember}\n canUnban={canUnban}\n onPromote={onPromoteMember}\n canPromote={canPromote}\n onDemote={onDemoteMember}\n canDemote={canDemote}\n />\n );\n });\n return items;\n }\n case 'media':\n if (MediaItem === MediaGridItem) {\n // Default: use grid rows\n return mediaRows.map((row, rowIdx) => (\n <MediaRow key={row[0]?.id || rowIdx} row={row} onClick={handleOpenUrl} />\n ));\n }\n // Custom: render each item individually\n return mediaItems.map((item, idx) => (\n <MediaItem key={item.id || idx} item={item} onClick={handleOpenUrl} />\n ));\n case 'links':\n return linkItems.map((item, idx) => (\n <LinkItem key={item.id || idx} item={item} />\n ));\n case 'files':\n return fileItems.map((item, idx) => (\n <FileItem key={item.id || idx} item={item} onClick={handleOpenUrl} />\n ));\n default:\n return [];\n }\n }, [contentTab, sortedMembers, mediaRows, mediaItems, linkItems, fileItems, onAddMemberClick, AvatarComponent, handleOpenUrl, MemberItem, MediaItem, LinkItem, FileItem]);\n\n // Check if content is empty for the content tab (deferred)\n const isTabEmpty = vlistChildren.length === 0 && !(loading && contentTab !== 'members');\n const emptyLabel = contentTab === 'members' ? 'members' : contentTab;\n\n return (\n <div className=\"ermis-channel-info__section ermis-channel-info__media-section\">\n <div className=\"ermis-channel-info__media-tabs\">\n {availableTabs.map(tab => (\n <button\n key={tab}\n className={`ermis-channel-info__media-tab ${activeTab === tab ? 'ermis-channel-info__media-tab--active' : ''}`}\n onClick={() => setActiveTab(tab)}\n >\n <span className=\"ermis-channel-info__media-tab-label\">\n {tab.charAt(0).toUpperCase() + tab.slice(1)}\n </span>\n {tabCounts[tab] > 0 && (\n <span className=\"ermis-channel-info__media-tab-count\">{tabCounts[tab]}</span>\n )}\n </button>\n ))}\n </div>\n\n <div\n className=\"ermis-channel-info__media-content\"\n style={isPending ? PENDING_STYLE : READY_STYLE}\n >\n {loading && contentTab !== 'members' ? <Loading /> : isTabEmpty ? <EmptyState label={emptyLabel} /> : (\n <VList style={{ height: '100%' }}>\n {vlistChildren}\n </VList>\n )}\n </div>\n </div>\n );\n});\n","import React from 'react';\nimport type { MediaTab } from '../../types';\n\nexport function getFileIcon(contentType: string, fileName: string): React.ReactNode {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n\n if (contentType.includes('pdf') || ext === 'pdf') {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\" />\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\" />\n <polyline points=\"10 9 9 9 8 9\" />\n </svg>\n );\n }\n\n if (contentType.includes('zip') || contentType.includes('rar') || contentType.includes('archive') || ['zip', 'rar', '7z', 'tar', 'gz'].includes(ext)) {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 8v13H3V3h13\" />\n <path d=\"M16 3v5h5\" />\n <path d=\"M10 12h4M10 16h4M10 8h1\" />\n </svg>\n );\n }\n\n // Default file icon\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n );\n}\n\nexport const ROLE_WEIGHTS: Record<string, number> = {\n owner: 4,\n moder: 3,\n member: 2,\n pending: 1,\n};\n\nexport const MESSAGING_TABS: MediaTab[] = ['media', 'links', 'files'];\nexport const ALL_TABS: MediaTab[] = ['members', 'media', 'links', 'files'];\n\nexport const PENDING_STYLE = { opacity: 0.7, transition: 'opacity 0.15s ease' } as const;\nexport const READY_STYLE = { opacity: 1, transition: 'opacity 0.15s ease' } as const;\n","import React, { useState, useMemo } from 'react';\nimport { preloadImage, isImagePreloaded } from '../../utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const MediaGridItem: React.FC<{\n item: AttachmentItem;\n onClick: (url: string) => void;\n}> = React.memo(({ item, onClick }) => {\n const src = item.thumb_url || item.url;\n const alreadyCached = isImagePreloaded(src);\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Trigger background preload (no-op if already cached)\n useMemo(() => { preloadImage(src); }, [src]);\n\n // Fallback checks for browser cache when JS preload didn't catch it\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, src]);\n\n const isVideo = item.attachment_type === 'video';\n\n return (\n <div\n className=\"ermis-channel-info__media-item\"\n onClick={() => onClick(item.url)}\n title={item.file_name}\n >\n {/* Shimmer placeholder while loading */}\n {!loaded && <div className=\"ermis-channel-info__media-shimmer\" />}\n\n {isVideo ? (\n <div className=\"ermis-channel-info__media-video-thumb\">\n {item.thumb_url ? (\n <img\n ref={imgRef}\n src={item.thumb_url}\n alt={item.file_name || 'video'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n ) : (\n <video\n src={item.url}\n preload=\"metadata\"\n onLoadedData={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n )}\n <div className=\"ermis-channel-info__media-play-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </div>\n </div>\n ) : (\n <img\n ref={imgRef}\n src={src}\n alt={item.file_name || 'media'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n )}\n </div>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(MediaGridItem as any).displayName = 'MediaGridItem';\n\nexport const MediaRow = React.memo(({ row, onClick }: { row: AttachmentItem[], onClick: (url: string) => void }) => {\n return (\n <div className=\"ermis-channel-info__media-grid-row\">\n {row.map(item => (\n <MediaGridItem key={item.id} item={item} onClick={onClick} />\n ))}\n {row.length < 3 && Array.from({ length: 3 - row.length }).map((_, i) => (\n <div key={`empty-${i}`} className=\"ermis-channel-info__media-item ermis-channel-info__media-item--empty\" />\n ))}\n </div>\n );\n}, (prev, next) => {\n if (prev.row.length !== next.row.length) return false;\n return prev.row.every((item, i) => item.id === next.row[i].id);\n});\n(MediaRow as any).displayName = 'MediaRow';\n","import React, { useState, useMemo } from 'react';\nimport { formatRelativeDate, extractDomain, isImagePreloaded, preloadImage } from '../../utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const LinkListItem: React.FC<{ item: AttachmentItem }> = React.memo(({ item }) => {\n const displayUrl = item.og_scrape_url || item.title_link || item.url;\n const domain = extractDomain(displayUrl);\n\n // Preload link preview image if available\n const imgSrc = item.image_url;\n const alreadyCached = imgSrc ? isImagePreloaded(imgSrc) : true;\n const [imgLoaded, setImgLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => { if (imgSrc) preloadImage(imgSrc); }, [imgSrc]);\n\n React.useEffect(() => {\n if (!imgLoaded && imgRef.current?.complete) {\n setImgLoaded(true);\n }\n }, [imgLoaded, imgSrc]);\n\n return (\n <a\n className=\"ermis-channel-info__link-item\"\n href={displayUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <div className=\"ermis-channel-info__link-icon\">\n {imgSrc ? (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {!imgLoaded && <div className=\"ermis-channel-info__media-shimmer\" style={{ borderRadius: '8px' }} />}\n <img\n ref={imgRef}\n src={imgSrc}\n alt=\"\"\n className=\"ermis-channel-info__link-preview-img\"\n loading=\"lazy\"\n onLoad={() => setImgLoaded(true)}\n style={{ opacity: imgLoaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n </div>\n ) : (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n )}\n </div>\n <div className=\"ermis-channel-info__link-content\">\n <span className=\"ermis-channel-info__link-title\">\n {item.title || item.file_name || domain}\n </span>\n <span className=\"ermis-channel-info__link-domain\">{domain}</span>\n </div>\n <span className=\"ermis-channel-info__link-date\">{formatRelativeDate(item.created_at)}</span>\n </a>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(LinkListItem as any).displayName = 'LinkListItem';\n","import React from 'react';\nimport { formatFileSize, formatRelativeDate, getDisplayName } from '../../utils';\nimport { getFileIcon } from './utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const FileListItem: React.FC<{\n item: AttachmentItem;\n onClick: (url: string) => void;\n}> = React.memo(({ item, onClick }) => {\n const displayName = getDisplayName(item.file_name);\n const ext = item.file_name.split('.').pop()?.toUpperCase() || 'FILE';\n\n return (\n <div\n className=\"ermis-channel-info__file-item\"\n onClick={() => onClick(item.url)}\n >\n <div className=\"ermis-channel-info__file-icon\">\n {getFileIcon(item.content_type, item.file_name)}\n <span className=\"ermis-channel-info__file-ext\">{ext}</span>\n </div>\n <div className=\"ermis-channel-info__file-info\">\n <span className=\"ermis-channel-info__file-name\" title={item.file_name}>\n {displayName}\n </span>\n <div className=\"ermis-channel-info__file-meta\">\n <span>{formatFileSize(item.content_length)}</span>\n <span className=\"ermis-channel-info__file-meta-dot\">·</span>\n <span>{formatRelativeDate(item.created_at)}</span>\n </div>\n </div>\n <button\n className=\"ermis-channel-info__file-download\"\n onClick={(e) => {\n e.stopPropagation();\n onClick(item.url);\n }}\n aria-label=\"Download\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n </div>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(FileListItem as any).displayName = 'FileListItem';\n","import React, { useState } from 'react';\nimport { Dropdown } from '../Dropdown';\nimport type { ChannelInfoMemberItemProps } from '../../types';\n\nexport const MemberListItem = React.memo(({\n member, AvatarComponent, \n onRemove, canRemove, \n onBan, canBan, \n onUnban, canUnban, \n onPromote, canPromote, \n onDemote, canDemote \n}: ChannelInfoMemberItemProps) => {\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n const isOpen = anchorRect !== null;\n\n if (!member) return null;\n const role = member.channel_role || 'member';\n const hasActions = canRemove || canBan || canUnban || canPromote || canDemote;\n\n return (\n <div className=\"ermis-channel-info__member-item\">\n <AvatarComponent image={member.user?.avatar} name={member.user?.name || member.user?.id} size={36} />\n <div className=\"ermis-channel-info__member-info\">\n <span className=\"ermis-channel-info__member-name\">{member.user?.name || member.user?.id}</span>\n <span className={`ermis-channel-info__member-role ermis-channel-info__member-role--${role.toLowerCase()}`}>\n {role.charAt(0).toUpperCase() + role.slice(1)}\n </span>\n </div>\n \n {hasActions && (\n <>\n <button\n className=\"ermis-channel-info__member-actions-btn\"\n onClick={(e) => {\n e.stopPropagation();\n setAnchorRect(e.currentTarget.getBoundingClientRect());\n }}\n aria-label=\"Member actions\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </button>\n \n <Dropdown\n isOpen={isOpen}\n anchorRect={anchorRect}\n onClose={() => setAnchorRect(null)}\n align=\"right\"\n >\n <div className=\"ermis-dropdown__menu\">\n {canPromote && onPromote && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onPromote(member.user?.id || member.user_id); setAnchorRect(null); }}>Promote to Moder</button>\n )}\n {canDemote && onDemote && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onDemote(member.user?.id || member.user_id); setAnchorRect(null); }}>Demote to Member</button>\n )}\n {canBan && onBan && (\n <button className=\"ermis-dropdown__item ermis-dropdown__item--danger\" onClick={() => { onBan(member.user?.id || member.user_id); setAnchorRect(null); }}>Ban Member</button>\n )}\n {canUnban && onUnban && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onUnban(member.user?.id || member.user_id); setAnchorRect(null); }}>Unban Member</button>\n )}\n {canRemove && onRemove && (\n <button className=\"ermis-dropdown__item ermis-dropdown__item--danger\" onClick={() => { onRemove(member.user?.id || member.user_id); setAnchorRect(null); }}>Remove from Channel</button>\n )}\n </div>\n </Dropdown>\n </>\n )}\n </div>\n );\n}, (prev, next) => {\n return prev.member?.user_id === next.member?.user_id &&\n prev.member?.channel_role === next.member?.channel_role &&\n prev.member?.banned === next.member?.banned &&\n prev.canRemove === next.canRemove &&\n prev.canBan === next.canBan &&\n prev.canUnban === next.canUnban &&\n prev.canPromote === next.canPromote &&\n prev.canDemote === next.canDemote;\n});\n(MemberListItem as any).displayName = 'MemberListItem';\n","import React from 'react';\n\nexport const TabEmptyState: React.FC<{ label: string }> = React.memo(({ label }) => (\n <div className=\"ermis-channel-info__media-empty\">\n <div className=\"ermis-channel-info__media-empty-icon\">\n {label === 'media' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n )}\n {label === 'links' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\n </svg>\n )}\n {label === 'files' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n )}\n </div>\n <span>No {label} shared yet</span>\n </div>\n));\n(TabEmptyState as any).displayName = 'TabEmptyState';\n\nexport const TabLoadingState: React.FC = React.memo(() => (\n <div className=\"ermis-channel-info__media-loading\">\n <div className=\"ermis-channel-info__media-spinner\" />\n </div>\n));\n(TabLoadingState as any).displayName = 'TabLoadingState';\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { Modal } from '../Modal';\nimport { UserPicker } from '../UserPicker';\nimport { Avatar } from '../Avatar';\nimport type { AddMemberModalProps, UserPickerUser } from '../../types';\n\nexport const AddMemberModal: React.FC<AddMemberModalProps> = ({\n channel,\n currentMembers,\n onClose,\n AvatarComponent = Avatar,\n title = 'Add Member',\n searchPlaceholder = 'Search by name, email or phone...',\n loadingText = 'Loading users...',\n emptyText = 'No users found.',\n addLabel = 'Add',\n addingLabel = 'Adding...',\n addedLabel = 'Added',\n UserItemComponent,\n SearchInputComponent,\n}) => {\n const [selectedUsers, setSelectedUsers] = useState<UserPickerUser[]>([]);\n const [isAdding, setIsAdding] = useState(false);\n\n // Exclude existing members from the picker\n const excludeUserIds = useMemo(\n () => currentMembers.map((m: any) => m.user_id),\n [currentMembers],\n );\n\n\n const handleSelectionChange = useCallback((users: UserPickerUser[]) => {\n setSelectedUsers(users);\n }, []);\n\n const handleAdd = useCallback(async () => {\n if (selectedUsers.length === 0 || isAdding) return;\n try {\n setIsAdding(true);\n await channel.addMembers(selectedUsers.map(u => u.id));\n onClose();\n } catch (err) {\n console.error('Failed to add members:', err);\n } finally {\n setIsAdding(false);\n }\n }, [selectedUsers, isAdding, channel, onClose]);\n\n const footer = (\n <button\n className=\"ermis-modal-add-btn\"\n onClick={handleAdd}\n disabled={selectedUsers.length === 0 || isAdding}\n >\n {isAdding\n ? addingLabel\n : `${addLabel} ${selectedUsers.length > 0 ? `(${selectedUsers.length})` : ''}`}\n </button>\n );\n\n return (\n <Modal isOpen onClose={onClose} title={title} maxWidth=\"480px\" footer={footer}>\n <UserPicker\n mode=\"checkbox\"\n onSelectionChange={handleSelectionChange}\n excludeUserIds={excludeUserIds}\n pageSize={30}\n AvatarComponent={AvatarComponent}\n UserItemComponent={UserItemComponent as any}\n SearchInputComponent={SearchInputComponent}\n searchPlaceholder={searchPlaceholder}\n loadingText={loadingText}\n emptyText={emptyText}\n selectedEmptyLabel=\"Select users to add...\"\n />\n </Modal>\n );\n};\n","import React, { useState, useEffect, useMemo, useCallback, useRef, useTransition } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { VList, type VListHandle } from 'virtua';\nimport type {\n UserPickerProps,\n UserPickerItemProps,\n UserPickerSelectedBoxProps,\n UserPickerUser,\n} from '../types';\n\n/* ---------- Constants ---------- */\nconst DEFAULT_PAGE_SIZE = 30;\nconst SEARCH_DEBOUNCE_MS = 500;\n\n/* ---------- Static styles ---------- */\nconst LIST_STYLE: React.CSSProperties = { height: '100%' };\n\n/* ==========================================================\n Default Sub-Components\n ========================================================== */\n\n/** Check icon for selected state */\nconst CheckIcon: React.FC = () => (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n);\n\n/** Default user row */\nconst DefaultUserItem: React.FC<UserPickerItemProps> = React.memo(({\n user, selected, disabled, mode, onToggle, AvatarComponent,\n}) => {\n const handleClick = useCallback(() => {\n if (!disabled) onToggle(user);\n }, [disabled, onToggle, user]);\n\n const inputClass = [\n 'ermis-user-picker__input',\n mode === 'radio' ? 'ermis-user-picker__input--radio' : 'ermis-user-picker__input--checkbox',\n selected ? 'ermis-user-picker__input--checked' : '',\n ].join(' ');\n\n const itemClass = [\n 'ermis-user-picker__item',\n selected ? 'ermis-user-picker__item--selected' : '',\n disabled ? 'ermis-user-picker__item--disabled' : '',\n ].join(' ');\n\n const detail = user.email || user.phone || '';\n\n return (\n <div className={itemClass} onClick={handleClick} role=\"option\" aria-selected={selected}>\n <div className={inputClass}>\n {selected && <CheckIcon />}\n </div>\n <AvatarComponent image={user.avatar} name={user.name || user.id} size={36} />\n <div className=\"ermis-user-picker__info\">\n <span className=\"ermis-user-picker__name\">{user.name || user.id}</span>\n {detail && <span className=\"ermis-user-picker__detail\">{detail}</span>}\n </div>\n </div>\n );\n});\nDefaultUserItem.displayName = 'DefaultUserItem';\n\n/** Default search input */\nconst DefaultSearchInput: React.FC<{ value: string; onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; placeholder: string }> = ({ value, onChange, placeholder }) => (\n <div className=\"ermis-user-picker__search\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n type=\"text\"\n placeholder={placeholder}\n value={value}\n onChange={onChange}\n autoFocus\n />\n </div>\n);\n\n/** Default selected users chip box */\nconst DefaultSelectedBox: React.FC<UserPickerSelectedBoxProps> = React.memo(({\n users, onRemove, AvatarComponent, emptyLabel,\n}) => (\n <div className=\"ermis-user-picker__selected-box\">\n {users.length === 0 && emptyLabel && (\n <span className=\"ermis-user-picker__selected-empty\">{emptyLabel}</span>\n )}\n {users.map(u => (\n <div key={u.id} className=\"ermis-user-picker__chip\">\n <AvatarComponent image={u.avatar} name={u.name || u.id} size={20} />\n <span className=\"ermis-user-picker__chip-name\">{u.name || u.id}</span>\n <button\n className=\"ermis-user-picker__chip-remove\"\n onClick={() => onRemove(u.id)}\n aria-label={`Remove ${u.name || u.id}`}\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n ))}\n </div>\n));\nDefaultSelectedBox.displayName = 'DefaultSelectedBox';\n\n/* ==========================================================\n UserPicker Component\n ========================================================== */\n\nexport const UserPicker: React.FC<UserPickerProps> = ({\n mode,\n onSelectionChange,\n excludeUserIds,\n initialSelectedUsers,\n pageSize = DEFAULT_PAGE_SIZE,\n AvatarComponent = Avatar,\n UserItemComponent,\n SelectedBoxComponent,\n SearchInputComponent,\n searchPlaceholder = 'Search by name, email or phone...',\n loadingText = 'Loading users...',\n emptyText = 'No users found.',\n loadingMoreText = 'Loading more...',\n selectedEmptyLabel,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n\n /* ---------- State ---------- */\n const [allUsers, setAllUsers] = useState<UserPickerUser[]>([]);\n const [page, setPage] = useState(1);\n const [hasMore, setHasMore] = useState(true);\n const [loading, setLoading] = useState(true);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const [remoteUsers, setRemoteUsers] = useState<UserPickerUser[]>([]);\n const [isSearching, setIsSearching] = useState(false);\n\n const [searchInput, setSearchInput] = useState('');\n const [search, setSearch] = useState('');\n const [isPendingFilter, startTransition] = useTransition();\n\n const [selectedMap, setSelectedMap] = useState<Map<string, UserPickerUser>>(() => {\n const map = new Map<string, UserPickerUser>();\n initialSelectedUsers?.forEach(u => map.set(u.id, u));\n return map;\n });\n\n const vlistRef = useRef<VListHandle>(null);\n\n /* ---------- Resolved sub-components ---------- */\n const UserRow = UserItemComponent || DefaultUserItem;\n const SearchInput = SearchInputComponent || DefaultSearchInput;\n const SelectedBox = SelectedBoxComponent || DefaultSelectedBox;\n\n /* ---------- Excluded IDs set ---------- */\n const excludeSet = useMemo(() => new Set(excludeUserIds || []), [excludeUserIds]);\n\n /* ---------- Search handler ---------- */\n const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n setSearchInput(val);\n startTransition(() => {\n setSearch(val);\n });\n }, [startTransition]);\n\n /* ---------- 1. Fetch initial page ---------- */\n useEffect(() => {\n let active = true;\n const fetchUsers = async () => {\n if (!client) return;\n try {\n setLoading(true);\n const response = await client.queryUsers(String(pageSize), 1);\n if (active && response.data) {\n setAllUsers(response.data);\n setHasMore(response.data.length >= pageSize);\n setPage(1);\n }\n } catch (err) {\n console.error('[UserPicker] Error fetching users:', err);\n } finally {\n if (active) setLoading(false);\n }\n };\n fetchUsers();\n return () => { active = false; };\n }, [client, pageSize]);\n\n /* ---------- 2. Load more (infinite scroll) ---------- */\n const loadMore = useCallback(async () => {\n if (!client || loadingMore || !hasMore || search.trim()) return;\n const nextPage = page + 1;\n setLoadingMore(true);\n try {\n const response = await client.queryUsers(String(pageSize), nextPage);\n if (response.data) {\n setAllUsers(prev => {\n const existingIds = new Set(prev.map(u => u.id));\n const newUsers = response.data.filter((u: UserPickerUser) => !existingIds.has(u.id));\n return [...prev, ...newUsers];\n });\n setHasMore(response.data.length >= pageSize);\n setPage(nextPage);\n }\n } catch (err) {\n console.error('[UserPicker] Error loading more users:', err);\n } finally {\n setLoadingMore(false);\n }\n }, [client, loadingMore, hasMore, page, pageSize, search]);\n\n /* ---------- 3. Local filter ---------- */\n const localFilteredUsers = useMemo(() => {\n const term = search.toLowerCase().trim();\n if (!term) return allUsers;\n return allUsers.filter(u => {\n const name = (u.name || '').toLowerCase();\n const email = (u.email || '').toLowerCase();\n const phone = (u.phone || '').toLowerCase();\n return name.includes(term) || email.includes(term) || phone.includes(term);\n });\n }, [search, allUsers]);\n\n /* ---------- 4. Remote search fallback ---------- */\n useEffect(() => {\n if (!search.trim() || localFilteredUsers.length > 0) {\n setRemoteUsers([]);\n setIsSearching(false);\n return;\n }\n\n let cancelled = false;\n const timer = setTimeout(async () => {\n setIsSearching(true);\n try {\n const response = await client.searchUsers(1, 25, search.trim());\n if (!cancelled && response.data) {\n setRemoteUsers(response.data);\n }\n } catch (err) {\n console.error('[UserPicker] Error searching remote users:', err);\n } finally {\n if (!cancelled) setIsSearching(false);\n }\n }, SEARCH_DEBOUNCE_MS);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n }, [search, localFilteredUsers.length, client, excludeSet]);\n\n /* ---------- 5. Derived display list ---------- */\n const usersToDisplay = (search.trim() && localFilteredUsers.length === 0)\n ? remoteUsers\n : localFilteredUsers;\n const isListLoading = loading || isSearching || isPendingFilter;\n\n /* ---------- 6. Selection handlers ---------- */\n const handleToggle = useCallback((user: UserPickerUser) => {\n // Don't allow toggling disabled users (current user or excluded)\n if (user.id === currentUserId || excludeSet.has(user.id)) return;\n\n setSelectedMap(prev => {\n const next = new Map(prev);\n if (mode === 'radio') {\n // Radio: clear all, set this one (or deselect if same)\n if (next.has(user.id)) {\n next.clear();\n } else {\n next.clear();\n next.set(user.id, user);\n }\n } else {\n // Checkbox: toggle\n if (next.has(user.id)) {\n next.delete(user.id);\n } else {\n next.set(user.id, user);\n }\n }\n return next;\n });\n }, [mode, currentUserId, excludeSet]);\n\n // Notify parent of selection changes\n useEffect(() => {\n onSelectionChange?.(Array.from(selectedMap.values()));\n }, [selectedMap, onSelectionChange]);\n\n const handleRemoveSelected = useCallback((userId: string) => {\n setSelectedMap(prev => {\n const next = new Map(prev);\n next.delete(userId);\n return next;\n });\n }, []);\n\n /* ---------- 7. Scroll handler for infinite scroll ---------- */\n const handleScroll = useCallback((offset: number) => {\n // VList provides scroll offset. We detect near-bottom using the ref\n const el = vlistRef.current;\n if (!el) return;\n // scrollSize = total scroll height, viewportSize = visible height\n const scrollSize = (el as any).scrollSize ?? 0;\n const viewportSize = (el as any).viewportSize ?? 0;\n if (scrollSize > 0 && offset + viewportSize >= scrollSize - 50) {\n loadMore();\n }\n }, [loadMore]);\n\n /* ---------- Render ---------- */\n const selectedArr = useMemo(() => Array.from(selectedMap.values()), [selectedMap]);\n\n return (\n <div className=\"ermis-user-picker\" role=\"listbox\" aria-multiselectable={mode === 'checkbox'}>\n {/* Selected Users Box (checkbox mode only) */}\n {mode === 'checkbox' && (\n <SelectedBox\n users={selectedArr}\n onRemove={handleRemoveSelected}\n AvatarComponent={AvatarComponent}\n emptyLabel={selectedEmptyLabel}\n />\n )}\n\n {/* Search Input */}\n <SearchInput\n value={searchInput}\n onChange={handleSearchChange}\n placeholder={searchPlaceholder}\n />\n\n {/* User List */}\n <div className=\"ermis-user-picker__list\">\n {isListLoading ? (\n <div className=\"ermis-user-picker__loading\">\n <span className=\"ermis-user-picker__spinner\" />\n {loadingText}\n </div>\n ) : usersToDisplay.length === 0 ? (\n <div className=\"ermis-user-picker__empty\">{emptyText}</div>\n ) : (\n <VList ref={vlistRef} style={LIST_STYLE} onScroll={handleScroll}>\n {usersToDisplay.map(user => (\n <UserRow\n key={user.id}\n user={user}\n selected={selectedMap.has(user.id)}\n disabled={user.id === currentUserId || excludeSet.has(user.id)}\n mode={mode}\n onToggle={handleToggle}\n AvatarComponent={AvatarComponent}\n />\n ))}\n {loadingMore && (\n <div className=\"ermis-user-picker__load-more\">\n <span className=\"ermis-user-picker__spinner\" />\n {loadingMoreText}\n </div>\n )}\n </VList>\n )}\n </div>\n </div>\n );\n};\n\nUserPicker.displayName = 'UserPicker';\n","import React, { useState, useRef, useCallback, useEffect } from 'react';\nimport { Modal } from '../Modal';\nimport type { EditChannelModalProps, EditChannelData } from '../../types';\n\nconst DEFAULT_MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5MB\n\nexport const EditChannelModal: React.FC<EditChannelModalProps> = React.memo(({\n channel,\n onClose,\n onSave,\n AvatarComponent,\n title = 'Edit Channel',\n nameLabel = 'Channel Name',\n descriptionLabel = 'Description',\n namePlaceholder = 'Enter channel name',\n descriptionPlaceholder = 'Enter channel description',\n publicLabel = 'Public Channel',\n saveLabel = 'Save',\n cancelLabel = 'Cancel',\n savingLabel = 'Saving...',\n changeAvatarLabel = 'Change Avatar',\n imageAccept = 'image/*',\n maxImageSize = DEFAULT_MAX_IMAGE_SIZE,\n maxImageSizeError = 'Image must be less than 5MB',\n}) => {\n // Original values from channel data\n const originalName = (channel.data?.name as string) || '';\n const originalImage = (channel.data?.image as string) || '';\n const originalDescription = (channel.data?.description as string) || '';\n const originalPublic = Boolean(channel.data?.public);\n const isTeamChannel = channel.type === 'team';\n\n // Form state\n const [name, setName] = useState(originalName);\n const [description, setDescription] = useState(originalDescription);\n const [isPublic, setIsPublic] = useState(originalPublic);\n const [previewUrl, setPreviewUrl] = useState<string | null>(null);\n const [selectedFile, setSelectedFile] = useState<File | null>(null);\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // Clean up object URL on unmount or when preview changes\n useEffect(() => {\n return () => {\n if (previewUrl) URL.revokeObjectURL(previewUrl);\n };\n }, [previewUrl]);\n\n const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n // Validate it's an image\n if (!file.type.startsWith('image/')) {\n setError('Only image files are allowed');\n return;\n }\n\n // Validate size\n if (file.size > maxImageSize) {\n setError(maxImageSizeError);\n return;\n }\n\n setError(null);\n // Revoke previous preview\n if (previewUrl) URL.revokeObjectURL(previewUrl);\n const url = URL.createObjectURL(file);\n setPreviewUrl(url);\n setSelectedFile(file);\n\n // Reset input so same file can be re-selected\n e.target.value = '';\n }, [maxImageSize, maxImageSizeError, previewUrl]);\n\n const handleAvatarClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n // Check if anything changed — only send changed fields\n const buildPayload = useCallback((): EditChannelData | null => {\n const payload: EditChannelData = {};\n let hasChanges = false;\n\n if (name.trim() !== originalName) {\n payload.name = name.trim();\n hasChanges = true;\n }\n if (description.trim() !== originalDescription) {\n payload.description = description.trim();\n hasChanges = true;\n }\n if (isTeamChannel && isPublic !== originalPublic) {\n payload.public = isPublic;\n hasChanges = true;\n }\n // Image is handled separately (upload first), but mark as changed\n if (selectedFile) {\n hasChanges = true;\n }\n\n return hasChanges ? payload : null;\n }, [name, description, isPublic, selectedFile, originalName, originalDescription, originalPublic, isTeamChannel]);\n\n const handleSave = useCallback(async () => {\n const payload = buildPayload();\n if (!payload && !selectedFile) {\n onClose();\n return;\n }\n\n setIsSaving(true);\n setError(null);\n\n try {\n // If consumer provides custom save handler, delegate entirely\n if (onSave) {\n if (selectedFile) {\n const response = await channel.sendFile(selectedFile, selectedFile.name, selectedFile.type);\n (payload || {} as EditChannelData).image = response.file;\n }\n await onSave(payload || {});\n onClose();\n return;\n }\n\n // Default save logic\n const finalPayload: EditChannelData = payload || {};\n\n // Upload image if changed\n if (selectedFile) {\n const response = await channel.sendFile(selectedFile, selectedFile.name, selectedFile.type);\n finalPayload.image = response.file;\n }\n\n // Only call update if there's something to update\n if (Object.keys(finalPayload).length > 0) {\n await channel.update(finalPayload as any);\n }\n\n onClose();\n } catch (err: any) {\n setError(err?.message || 'Failed to update channel');\n } finally {\n setIsSaving(false);\n }\n }, [buildPayload, selectedFile, onSave, channel, onClose]);\n\n // Determine displayed avatar image\n const displayImage = previewUrl || originalImage || undefined;\n\n const footerContent = (\n <div className=\"ermis-channel-info__edit-footer-buttons\">\n <button\n className=\"ermis-channel-info__edit-btn ermis-channel-info__edit-btn--cancel\"\n onClick={onClose}\n disabled={isSaving}\n >\n {cancelLabel}\n </button>\n <button\n className=\"ermis-channel-info__edit-btn ermis-channel-info__edit-btn--save\"\n onClick={handleSave}\n disabled={isSaving}\n >\n {isSaving ? savingLabel : saveLabel}\n </button>\n </div>\n );\n\n return (\n <Modal\n isOpen={true}\n onClose={isSaving ? () => {} : onClose}\n title={title}\n footer={footerContent}\n maxWidth=\"420px\"\n >\n <div className=\"ermis-channel-info__edit-body\">\n {/* Avatar section */}\n <div className=\"ermis-channel-info__edit-avatar-section\">\n <div className=\"ermis-channel-info__edit-avatar-wrap\" onClick={handleAvatarClick}>\n <AvatarComponent image={displayImage} name={name || originalName} size={80} />\n <div className=\"ermis-channel-info__edit-avatar-overlay\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z\" />\n <circle cx=\"12\" cy=\"13\" r=\"4\" />\n </svg>\n </div>\n </div>\n <button\n className=\"ermis-channel-info__edit-avatar-btn\"\n onClick={handleAvatarClick}\n type=\"button\"\n disabled={isSaving}\n >\n {changeAvatarLabel}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={imageAccept}\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n />\n </div>\n\n {/* Name field */}\n <div className=\"ermis-channel-info__edit-field\">\n <label className=\"ermis-channel-info__edit-label\">{nameLabel}</label>\n <input\n className=\"ermis-channel-info__edit-input\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={namePlaceholder}\n disabled={isSaving}\n maxLength={100}\n />\n </div>\n\n {/* Description field */}\n <div className=\"ermis-channel-info__edit-field\">\n <label className=\"ermis-channel-info__edit-label\">{descriptionLabel}</label>\n <textarea\n className=\"ermis-channel-info__edit-textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={descriptionPlaceholder}\n disabled={isSaving}\n rows={3}\n maxLength={500}\n />\n </div>\n\n {/* Public toggle — only for team channels */}\n {isTeamChannel && (\n <div className=\"ermis-channel-info__edit-field ermis-channel-info__edit-field--toggle\">\n <label className=\"ermis-channel-info__edit-label\">{publicLabel}</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPublic}\n className={`ermis-channel-info__edit-toggle ${isPublic ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => setIsPublic(v => !v)}\n disabled={isSaving}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"ermis-channel-info__edit-error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n </div>\n </Modal>\n );\n});\n\nEditChannelModal.displayName = 'EditChannelModal';\n","import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap, formatRelativeDate } from '../../utils';\nimport { Avatar } from '../Avatar';\nimport { Panel } from '../Panel';\nimport type { AvatarProps, SearchResultMessage, MessageSearchPanelProps } from '../../types';\n\n/* ----------------------------------------------------------\n Highlight utility (Accent-insensitive)\n ---------------------------------------------------------- */\nconst removeAccents = (str: string) => str.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');\n\nconst HighlightedText: React.FC<{ text: string; term: string }> = React.memo(({ text, term }) => {\n if (!term.trim()) return <>{text}</>;\n\n const cleanTerm = removeAccents(term).toLowerCase();\n if (!cleanTerm) return <>{text}</>;\n\n const parts = [];\n let currentIndex = 0;\n const cleanText = removeAccents(text).toLowerCase();\n\n while (true) {\n const startMatch = cleanText.indexOf(cleanTerm, currentIndex);\n if (startMatch === -1) {\n if (currentIndex < text.length) {\n parts.push(<span key={currentIndex}>{text.slice(currentIndex)}</span>);\n }\n break;\n }\n\n if (startMatch > currentIndex) {\n parts.push(<span key={`text-${currentIndex}`}>{text.slice(currentIndex, startMatch)}</span>);\n }\n\n const endMatch = startMatch + cleanTerm.length;\n parts.push(\n <mark key={`mark-${startMatch}`} className=\"ermis-search-panel__highlight\">\n {text.slice(startMatch, endMatch)}\n </mark>\n );\n\n currentIndex = endMatch;\n }\n\n return <>{parts.length > 0 ? parts : text}</>;\n});\nHighlightedText.displayName = 'HighlightedText';\n\n/* ----------------------------------------------------------\n MessageSearchPanel\n ---------------------------------------------------------- */\nexport const MessageSearchPanel: React.FC<MessageSearchPanelProps> = React.memo(({\n isOpen,\n onClose,\n channel,\n AvatarComponent = Avatar,\n placeholder = 'Search messages...',\n title = 'Search Messages',\n emptyText = 'No messages found',\n loadingText = 'Searching...',\n debounceMs = 500,\n}) => {\n const { setJumpToMessageId } = useChatClient();\n\n const [query, setQuery] = useState('');\n const [results, setResults] = useState<SearchResultMessage[]>([]);\n const [loading, setLoading] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const offsetRef = useRef(0);\n const queryRef = useRef('');\n\n // Reset all state when the channel changes (or panel closes)\n useEffect(() => {\n setQuery('');\n setResults([]);\n setLoading(false);\n setHasMore(false);\n setLoadingMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n }, [channel?.cid, isOpen]);\n\n // Auto-focus the input when panel opens\n useEffect(() => {\n if (isOpen) {\n setTimeout(() => inputRef.current?.focus(), 300);\n }\n }, [isOpen]);\n\n // Debounced search\n const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value;\n setQuery(value);\n\n if (debounceRef.current) clearTimeout(debounceRef.current);\n\n if (!value.trim()) {\n setResults([]);\n setLoading(false);\n setHasMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n return;\n }\n\n setLoading(true);\n\n debounceRef.current = setTimeout(async () => {\n queryRef.current = value;\n offsetRef.current = 0;\n\n try {\n const response = await channel.searchMessage(value, 0);\n // Only apply if this is still the latest query\n if (queryRef.current !== value) return;\n\n if (!response) {\n setResults([]);\n setHasMore(false);\n } else {\n setResults(response.messages || []);\n setHasMore((response.messages?.length || 0) >= 25);\n }\n } catch (err) {\n console.error('Search failed:', err);\n setResults([]);\n setHasMore(false);\n } finally {\n setLoading(false);\n }\n }, debounceMs);\n }, [channel, debounceMs]);\n\n // Infinite scroll: load more results\n const handleLoadMore = useCallback(async () => {\n if (loadingMore || !hasMore || !queryRef.current) return;\n\n setLoadingMore(true);\n const nextOffset = offsetRef.current + 25; // offset skips records, limit is 25\n\n try {\n const response = await channel.searchMessage(queryRef.current, nextOffset);\n\n if (!response || !response.messages?.length) {\n setHasMore(false);\n } else {\n offsetRef.current = nextOffset;\n setResults((prev) => [...prev, ...response.messages]);\n setHasMore(response.messages.length >= 25);\n }\n } catch (err) {\n console.error('Load more search results failed:', err);\n } finally {\n setLoadingMore(false);\n }\n }, [channel, hasMore, loadingMore]);\n\n // Scroll handler for infinite scroll\n const handleScroll = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n const threshold = 100;\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - threshold) {\n handleLoadMore();\n }\n }, [handleLoadMore]);\n\n // Click a result -> jump to that message\n const handleResultClick = useCallback((messageId: string) => {\n setJumpToMessageId(messageId);\n }, [setJumpToMessageId]);\n\n // Derived userMap for resolving mentions, with a lowercase variant for fast lookup\n const userMaps = useMemo(() => {\n const original = buildUserMap(channel.state);\n const lower: typeof original = {};\n for (const [id, name] of Object.entries(original)) {\n lower[id.toLowerCase()] = name;\n }\n return { original, lower };\n }, [channel.state]);\n\n return (\n <Panel isOpen={isOpen} onClose={onClose} title={title} className=\"ermis-search-panel\">\n {/* Search Input now inside body */}\n <div className=\"ermis-search-panel__search-box\">\n <div className=\"ermis-search-panel__input-wrap\">\n <svg className=\"ermis-search-panel__input-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n ref={inputRef}\n className=\"ermis-search-panel__input\"\n type=\"text\"\n value={query}\n onChange={handleInputChange}\n placeholder={placeholder}\n />\n {query && (\n <button\n className=\"ermis-search-panel__input-clear\"\n onClick={() => {\n setQuery('');\n setResults([]);\n setHasMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n inputRef.current?.focus();\n }}\n aria-label=\"Clear\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n <div\n ref={scrollRef}\n className=\"ermis-search-panel__results\"\n onScroll={handleScroll}\n >\n {/* Initial state — no query yet */}\n {!query.trim() && !loading && results.length === 0 && (\n <div className=\"ermis-search-panel__idle\">\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <span>{placeholder}</span>\n </div>\n )}\n\n {/* Loading state */}\n {loading && (\n <div className=\"ermis-search-panel__loading\">\n <div className=\"ermis-search-panel__spinner\" />\n <span>{loadingText}</span>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && query.trim() && results.length === 0 && (\n <div className=\"ermis-search-panel__empty\">\n <span>{emptyText}</span>\n </div>\n )}\n\n {/* Results */}\n {!loading && results.map((msg) => {\n let parsedText = '';\n if (msg.text) {\n // Try standard replacement first\n parsedText = replaceMentionsForPreview(msg.text, msg as any, userMaps.original);\n // Fallback: search API may omit mentioned_users array, so we map @0x IDs efficiently\n if (/@0x[a-fA-F0-9]+/i.test(parsedText)) {\n parsedText = parsedText.replace(/@0x[a-fA-F0-9]+/gi, (match) => {\n const matchedId = match.slice(1).toLowerCase();\n return userMaps.lower[matchedId] ? `@${userMaps.lower[matchedId]}` : match;\n });\n }\n }\n\n return (\n <div\n key={msg.id}\n role=\"button\"\n tabIndex={0}\n className=\"ermis-search-panel__result-item\"\n onClick={() => handleResultClick(msg.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleResultClick(msg.id);\n }\n }}\n >\n <AvatarComponent\n image={msg.user?.avatar || msg.user?.image || msg.user?.avatar_url}\n name={msg.user?.name || msg.user_id}\n size={36}\n />\n <div className=\"ermis-search-panel__result-body\">\n <div className=\"ermis-search-panel__result-meta\">\n <span className=\"ermis-search-panel__result-name\">\n {msg.user?.name || msg.user_id || 'Unknown'}\n </span>\n <span className=\"ermis-search-panel__result-time\">\n {msg.created_at ? formatRelativeDate(msg.created_at) : ''}\n </span>\n </div>\n <p className=\"ermis-search-panel__result-text\">\n {parsedText ? (\n <HighlightedText text={parsedText} term={query} />\n ) : (\n <em>Attachment</em>\n )}\n </p>\n </div>\n </div>\n );\n })}\n\n {/* End of results indicator */}\n {!loading && !loadingMore && !hasMore && results.length > 0 && query.trim() && (\n <div className=\"ermis-search-panel__end-indicator\">\n <span>{emptyText}</span>\n </div>\n )}\n\n {/* Loading more indicator */}\n {loadingMore && (\n <div className=\"ermis-search-panel__loading-more\">\n <div className=\"ermis-search-panel__spinner ermis-search-panel__spinner--small\" />\n </div>\n )}\n </div>\n </Panel>\n );\n});\nMessageSearchPanel.displayName = 'MessageSearchPanel';\n","import React, { useEffect, useRef } from 'react';\n\nexport type PanelProps = {\n /** Whether the panel is visible */\n isOpen: boolean;\n /** Called when user clicks the back button */\n onClose: () => void;\n /** Panel title shown in the header */\n title?: string;\n /** Panel body content */\n children: React.ReactNode;\n /** Optional header content (replaces default title + back button) */\n headerContent?: React.ReactNode;\n /** Additional CSS class name */\n className?: string;\n};\n\n/**\n * Reusable sliding panel component.\n * Slides in from the right to overlay itself on whatever container it's placed in.\n * Use it like a Modal but inside a sidebar — call `isOpen` to show/hide.\n */\nexport const Panel: React.FC<PanelProps> = React.memo(({\n isOpen,\n onClose,\n title,\n children,\n headerContent,\n className,\n}) => {\n const panelRef = useRef<HTMLDivElement>(null);\n\n // Focus trap: focus the panel when it opens for accessibility\n useEffect(() => {\n if (isOpen && panelRef.current) {\n panelRef.current.focus();\n }\n }, [isOpen]);\n\n return (\n <div\n ref={panelRef}\n className={`ermis-panel${isOpen ? ' ermis-panel--open' : ''}${className ? ` ${className}` : ''}`}\n tabIndex={-1}\n >\n {headerContent ? (\n headerContent\n ) : (\n <div className=\"ermis-panel__header\">\n <button className=\"ermis-panel__back\" onClick={onClose} aria-label=\"Back\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n {title && <h3 className=\"ermis-panel__title\">{title}</h3>}\n </div>\n )}\n <div className=\"ermis-panel__body\">\n {children}\n </div>\n </div>\n );\n});\nPanel.displayName = 'Panel';\n","import React, { useState, useEffect } from 'react';\nimport { Panel } from '../Panel';\nimport type { ChannelSettingsPanelProps } from '../../types';\n\nexport const ChannelSettingsPanel: React.FC<ChannelSettingsPanelProps> = React.memo(({\n isOpen,\n onClose,\n channel,\n title = 'Channel Settings',\n slowModeOptions = [\n { label: 'Off', value: 0 },\n { label: '10s', value: 10000 },\n { label: '30s', value: 30000 },\n { label: '1m', value: 60000 },\n { label: '5m', value: 300000 },\n { label: '15m', value: 900000 },\n { label: '1h', value: 3600000 },\n ],\n}) => {\n // Config state\n const [slowMode, setSlowMode] = useState<number>(0);\n const [capabilities, setCapabilities] = useState<Record<string, boolean>>({\n 'send-message': true,\n 'send-links': true,\n 'update-own-message': true,\n 'delete-own-message': true,\n 'send-reaction': true,\n 'pin-message': true,\n 'create-poll': true,\n 'vote-poll': true,\n });\n\n const [keywords, setKeywords] = useState<string[]>([]);\n const [newKeyword, setNewKeyword] = useState('');\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Sync state when panel opens or channel updates\n useEffect(() => {\n if (!channel) return;\n\n const syncData = (dataToSync = channel.data) => {\n console.log('---syncData---', dataToSync);\n setSlowMode((dataToSync?.member_message_cooldown as number) || 0);\n setKeywords((dataToSync?.filter_words as string[]) || []);\n\n const caps = dataToSync?.member_capabilities as string[] || [];\n setCapabilities({\n 'send-message': caps.includes('send-message'),\n 'send-links': caps.includes('send-links'),\n 'update-own-message': caps.includes('update-own-message'),\n 'delete-own-message': caps.includes('delete-own-message'),\n 'send-reaction': caps.includes('send-reaction'),\n 'pin-message': caps.includes('pin-message'),\n 'create-poll': caps.includes('create-poll'),\n 'vote-poll': caps.includes('vote-poll'),\n });\n setError(null);\n };\n\n if (isOpen) {\n syncData();\n }\n\n // Listen to real-time changes\n const subscription = channel.on('channel.updated', (event: any) => {\n const latestData = event?.channel || channel.data;\n // Force mutating local channel.data to ensure future syncData hits cache\n if (event?.channel && channel.data) {\n Object.assign(channel.data, event.channel);\n }\n\n if (isOpen) {\n syncData(latestData);\n }\n });\n\n return () => {\n subscription?.unsubscribe();\n };\n }, [isOpen, channel]);\n\n const toggleCapability = (key: string) => {\n setCapabilities(prev => ({ ...prev, [key]: !prev[key] }));\n };\n\n // Compute dirty state\n const isSlowModeChanged = slowMode !== ((channel?.data?.member_message_cooldown as number) || 0);\n\n const currentKeywordsSorted = [...keywords].sort().join(',');\n const originalKeywordsSorted = [...((channel?.data?.filter_words as string[]) || [])].sort().join(',');\n const isKeywordsChanged = currentKeywordsSorted !== originalKeywordsSorted;\n\n const originalCapabilities = channel?.data?.member_capabilities as string[] || [];\n const initialCapabilities: Record<string, boolean> = {\n 'send-message': originalCapabilities.includes('send-message'),\n 'send-links': originalCapabilities.includes('send-links'),\n 'update-own-message': originalCapabilities.includes('update-own-message'),\n 'delete-own-message': originalCapabilities.includes('delete-own-message'),\n 'send-reaction': originalCapabilities.includes('send-reaction'),\n 'pin-message': originalCapabilities.includes('pin-message'),\n 'create-poll': originalCapabilities.includes('create-poll'),\n 'vote-poll': originalCapabilities.includes('vote-poll'),\n };\n const isCapabilitiesChanged = Object.keys(capabilities).some(k => capabilities[k] !== initialCapabilities[k]);\n\n const isDirty = isSlowModeChanged || isKeywordsChanged || isCapabilitiesChanged;\n\n const handleAddNewKeyword = () => {\n if (newKeyword.trim()) {\n const keyword = newKeyword.trim().toLowerCase();\n if (!keywords.includes(keyword)) {\n setKeywords(prev => [...prev, keyword]);\n }\n setNewKeyword('');\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleAddNewKeyword();\n }\n };\n\n const handeRemoveKeyword = (kw: string) => {\n setKeywords(prev => prev.filter(k => k !== kw));\n };\n\n const handleSave = async () => {\n if (!channel) return;\n setIsSaving(true);\n setError(null);\n try {\n const dataUpdates: any = {};\n let capabilitiesArray: string[] | null = null;\n\n if (isSlowModeChanged) {\n dataUpdates.member_message_cooldown = slowMode;\n }\n\n if (isKeywordsChanged) {\n dataUpdates.filter_words = keywords;\n }\n\n if (isCapabilitiesChanged) {\n const controlledKeys = Object.keys(capabilities);\n const originalCaps = (channel.data?.member_capabilities as string[]) || [];\n\n // Preserve unmanaged original capabilities (e.g. create-call, join-call)\n const unmanagedCaps = originalCaps.filter(c => !controlledKeys.includes(c));\n\n // Extract managed capabilities that are currently enabled (true)\n const managedEnabledCaps = controlledKeys.filter(k => capabilities[k as keyof typeof capabilities]);\n\n // Merge into the final payload array\n capabilitiesArray = [...unmanagedCaps, ...managedEnabledCaps];\n }\n\n if (Object.keys(dataUpdates).length > 0 || capabilitiesArray !== null) {\n const payload: any = {};\n\n if (Object.keys(dataUpdates).length > 0) {\n payload.data = dataUpdates;\n if (channel.data) Object.assign(channel.data, dataUpdates);\n }\n\n if (capabilitiesArray !== null) {\n payload.capabilities = capabilitiesArray;\n if (channel.data) {\n // Local fallback naming to keep UI synchronous\n channel.data.member_capabilities = capabilitiesArray;\n }\n }\n\n // Use _update instead of update to safely construct root-level payloads\n await (channel as any)._update(payload);\n }\n onClose();\n } catch (err: any) {\n setError(err?.message || 'Failed to update settings');\n } finally {\n setIsSaving(false);\n }\n };\n\n // We do NOT return null based on !isOpen so the sliding CSS transition is preserved.\n return (\n <Panel isOpen={isOpen} onClose={onClose} title={title} className=\"ermis-settings-panel\">\n\n {/* \n This wrapper creates a neat scrollable area with subtle gray background\n which makes white cards pop out smoothly.\n */}\n <div\n className=\"ermis-settings-panel__body\"\n style={{\n flex: 1,\n minHeight: 0,\n padding: '16px',\n overflowY: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '16px',\n background: 'var(--ermis-bg-secondary)'\n }}\n >\n\n {/* Section 1: Permissions */}\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'var(--ermis-color-primary-light)', padding: '4px', borderRadius: '8px', color: 'var(--ermis-color-primary)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\" />\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n Member Permissions\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__field\" style={{ marginBottom: '16px' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Slow Mode\n </label>\n <div style={{ position: 'relative' }}>\n <select\n value={slowMode}\n onChange={e => setSlowMode(Number(e.target.value))}\n style={{\n width: '100%',\n padding: '10px 12px',\n borderRadius: '8px',\n border: '1px solid var(--ermis-border-color)',\n background: 'var(--ermis-bg-secondary)',\n color: 'var(--ermis-text-primary)',\n fontSize: '14px',\n fontWeight: 500,\n appearance: 'none',\n outline: 'none',\n cursor: isSaving ? 'not-allowed' : 'pointer',\n transition: 'border-color 0.2s'\n }}\n disabled={isSaving}\n >\n {slowModeOptions.map(opt => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n <div style={{ position: 'absolute', right: '14px', top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none', color: 'var(--ermis-text-secondary)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n </div>\n </div>\n\n <div className=\"ermis-settings-panel__toggles\" style={{ display: 'flex', flexDirection: 'column' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Capabilities\n </label>\n <div style={{ background: 'var(--ermis-bg-secondary)', borderRadius: '8px', overflow: 'hidden', border: '1px solid var(--ermis-border-color)' }}>\n {Object.entries(capabilities).map(([key, value], index, arr) => (\n <div\n key={key}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 14px',\n borderBottom: index < arr.length - 1 ? '1px solid var(--ermis-border-color)' : 'none'\n }}\n >\n <span style={{ fontSize: '14px', fontWeight: 500, color: 'var(--ermis-text-primary)' }}>\n {key.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}\n </span>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={value}\n className={`ermis-channel-info__edit-toggle ${value ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => toggleCapability(key)}\n disabled={isSaving}\n style={{ transform: 'scale(0.85)', transformOrigin: 'right center' }}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n ))}\n </div>\n </div>\n </section>\n\n {/* Section 2: Content Moderation */}\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'var(--ermis-color-danger-light)', padding: '4px', borderRadius: '8px', color: 'var(--ermis-color-danger)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"></path>\n <line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line>\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n Content Moderation\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__field\" style={{ marginBottom: '16px' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Keyword Filtering\n </label>\n <div style={{ display: 'flex', gap: '8px', position: 'relative' }}>\n <input\n type=\"text\"\n value={newKeyword}\n onChange={e => setNewKeyword(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type keyword and press Enter or Add...\"\n style={{\n flex: 1,\n minWidth: 0,\n padding: '10px 12px',\n borderRadius: '8px',\n border: '1px solid var(--ermis-border-color)',\n background: 'var(--ermis-bg-secondary)',\n color: 'var(--ermis-text-primary)',\n fontSize: '14px',\n outline: 'none'\n }}\n disabled={isSaving}\n />\n <button\n type=\"button\"\n onClick={handleAddNewKeyword}\n disabled={isSaving || !newKeyword.trim()}\n style={{\n padding: '0 12px',\n borderRadius: '8px',\n background: 'var(--ermis-color-primary-light)',\n color: 'var(--ermis-color-primary)',\n border: 'none',\n fontWeight: 600,\n fontSize: '13px',\n cursor: isSaving || !newKeyword.trim() ? 'not-allowed' : 'pointer',\n opacity: isSaving || !newKeyword.trim() ? 0.6 : 1,\n transition: 'opacity 0.2s',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center'\n }}\n >\n Add\n </button>\n </div>\n </div>\n\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', minHeight: '32px' }}>\n {keywords.map(kw => (\n <span\n key={kw}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n padding: '3px 8px',\n borderRadius: '16px',\n background: 'var(--ermis-color-danger-light)',\n color: 'var(--ermis-color-danger)',\n border: '1px solid rgba(239, 68, 68, 0.2)',\n fontSize: '12px',\n fontWeight: 600\n }}\n >\n {kw}\n <button\n onClick={() => handeRemoveKeyword(kw)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'transparent',\n border: 'none',\n cursor: 'pointer',\n padding: '2px',\n color: 'inherit',\n opacity: 0.8,\n }}\n disabled={isSaving}\n aria-label=\"Remove keyword\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </span>\n ))}\n {keywords.length === 0 && (\n <span style={{ fontSize: '14px', color: 'var(--ermis-text-secondary)', padding: '6px 0', fontStyle: 'italic' }}>\n No blacklisted keywords added.\n </span>\n )}\n </div>\n </section>\n\n </div>\n\n {/* Footer Area */}\n <div\n className=\"ermis-settings-panel__footer\"\n style={{\n flexShrink: 0,\n padding: '12px 16px',\n background: 'var(--ermis-bg-primary)',\n borderTop: '1px solid var(--ermis-border-color)',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px'\n }}\n >\n {error && (\n <div style={{ color: 'var(--ermis-color-danger)', fontSize: '13px', display: 'flex', alignItems: 'center', gap: '6px', fontWeight: 500 }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\" /><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" /><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" /></svg>\n {error}\n </div>\n )}\n <button\n onClick={handleSave}\n disabled={isSaving || !isDirty}\n style={{\n width: '100%',\n padding: '10px',\n borderRadius: '8px',\n background: 'var(--ermis-color-primary, #006eff)',\n color: '#ffffff',\n border: 'none',\n fontSize: '14px',\n fontWeight: 600,\n cursor: (isSaving || !isDirty) ? 'not-allowed' : 'pointer',\n opacity: (isSaving || !isDirty) ? 0.6 : 1,\n transition: 'all 0.2s ease',\n boxShadow: (isSaving || !isDirty) ? 'none' : '0 4px 12px rgba(0, 110, 255, 0.2)'\n }}\n >\n {isSaving ? (\n <span style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px' }}>\n <svg className=\"ermis-spinner\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\">\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\"></path>\n </svg>\n Saving...\n </span>\n ) : 'Save Updates'}\n </button>\n </div>\n\n </Panel>\n );\n});\n\nChannelSettingsPanel.displayName = 'ChannelSettingsPanel';\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { Modal } from './Modal';\nimport { UserPicker } from './UserPicker';\nimport { Avatar } from './Avatar';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { CreateChannelModalProps, UserPickerUser } from '../types';\n\n\nexport const CreateChannelModal: React.FC<CreateChannelModalProps> = ({\n isOpen,\n onClose,\n onSuccess,\n AvatarComponent = Avatar,\n UserItemComponent,\n title = 'New Message',\n directTabLabel = 'Direct',\n groupTabLabel = 'Group',\n groupNameLabel = 'Channel Name',\n groupNamePlaceholder = 'Enter channel name (required)',\n groupDescriptionLabel = 'Description',\n groupDescriptionPlaceholder = 'Optional description',\n groupPublicLabel = 'Public Channel',\n userSearchPlaceholder = 'Search users...',\n cancelButtonLabel = 'Cancel',\n createButtonLabel = 'Create',\n creatingButtonLabel = 'Creating...',\n}) => {\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n\n /* ---------- State ---------- */\n const [tab, setTab] = useState<'messaging' | 'team'>('messaging');\n const [step, setStep] = useState<1 | 2>(1); // Only for team channel\n\n // Group specific\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [isPublic, setIsPublic] = useState(false);\n\n // Users\n const [selectedUsers, setSelectedUsers] = useState<UserPickerUser[]>([]);\n\n // Progress/Error\n const [isCreating, setIsCreating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /* ---------- Exclude IDs for Direct ---------- */\n const existingDirectUserIds = useMemo(() => {\n if (!client || !currentUserId || tab !== 'messaging') return [];\n\n const ids = new Set<string>();\n Object.values(client.activeChannels).forEach((channel: any) => {\n if (channel.type === 'messaging' && channel.state?.members) {\n Object.keys(channel.state.members).forEach(uid => {\n if (uid !== currentUserId) ids.add(uid);\n });\n }\n });\n return Array.from(ids);\n }, [client, currentUserId, tab]);\n\n /* ---------- Handlers ---------- */\n const handleCreate = useCallback(async () => {\n if (!client || !currentUserId || isCreating) return;\n\n // Validations\n if (selectedUsers.length === 0) {\n setError('Please select at least one user.');\n return;\n }\n\n if (tab === 'team' && !name.trim()) {\n setError('Group name is required.');\n return;\n }\n\n setIsCreating(true);\n setError(null);\n\n try {\n let createdChannel;\n\n if (tab === 'messaging') {\n const targetUserId = selectedUsers[0].id;\n createdChannel = client.channel('messaging', {\n members: [currentUserId, targetUserId],\n } as any);\n await createdChannel.create();\n } else {\n // Group Channel\n const memberIds = selectedUsers.map(member => member.id);\n // Ensure current user is in the group members\n if (!memberIds.includes(currentUserId)) {\n memberIds.push(currentUserId);\n }\n\n const payload: any = {\n name: name.trim(),\n members: memberIds,\n public: isPublic,\n };\n\n if (description.trim()) {\n payload.description = description.trim();\n }\n\n createdChannel = client.channel('team', payload);\n await createdChannel.create();\n }\n\n // Cleanup and execute callback\n if (onSuccess) {\n onSuccess(createdChannel);\n } else {\n onClose();\n }\n\n } catch (err: any) {\n setError(err?.message || 'Failed to create channel');\n } finally {\n setIsCreating(false);\n }\n }, [client, currentUserId, isCreating, selectedUsers, tab, name, isPublic, description, onSuccess, onClose]);\n\n\n const isValid = useMemo(() => {\n if (tab === 'messaging' && selectedUsers.length === 0) return false;\n if (tab === 'team' && step === 1 && !name.trim()) return false;\n if (tab === 'team' && step === 2 && selectedUsers.length === 0) return false;\n return true;\n }, [selectedUsers, tab, name, step]);\n\n let footer;\n if (tab === 'messaging') {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={onClose} disabled={isCreating}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={handleCreate} disabled={isCreating || !isValid}>\n {isCreating ? creatingButtonLabel : createButtonLabel}\n </button>\n </div>\n );\n } else if (tab === 'team' && step === 1) {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={onClose} disabled={isCreating}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={() => { setError(null); setStep(2); }} disabled={isCreating || !isValid}>\n Next\n </button>\n </div>\n );\n } else if (tab === 'team' && step === 2) {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={() => { setError(null); setStep(1); }} disabled={isCreating}>Back</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={handleCreate} disabled={isCreating || !isValid}>\n {isCreating ? creatingButtonLabel : createButtonLabel}\n </button>\n </div>\n );\n }\n\n return (\n <Modal isOpen={isOpen} onClose={isCreating ? () => { } : onClose} title={title} maxWidth=\"480px\" footer={footer}>\n <div className=\"ermis-create-channel__body\">\n\n {/* Type Toggle */}\n <div className=\"ermis-create-channel__tabs\">\n <button\n className={`ermis-create-channel__tab ${tab === 'messaging' ? 'ermis-create-channel__tab--active' : ''}`}\n onClick={() => {\n setTab('messaging');\n setStep(1);\n setSelectedUsers([]);\n setError(null);\n }}\n disabled={isCreating}\n >\n {directTabLabel}\n </button>\n <button\n className={`ermis-create-channel__tab ${tab === 'team' ? 'ermis-create-channel__tab--active' : ''}`}\n onClick={() => {\n setTab('team');\n setStep(1);\n setSelectedUsers([]);\n setError(null);\n }}\n disabled={isCreating}\n >\n {groupTabLabel}\n </button>\n </div>\n\n {/* Group Specific Fields - Step 1 */}\n {tab === 'team' && step === 1 && (\n <>\n\n <div className=\"ermis-create-channel__field\">\n <label className=\"ermis-create-channel__label\">{groupNameLabel} <span style={{ color: 'var(--ermis-error)' }}>*</span></label>\n <input\n className=\"ermis-create-channel__input\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={groupNamePlaceholder}\n disabled={isCreating}\n maxLength={100}\n />\n </div>\n\n <div className=\"ermis-create-channel__field\">\n <label className=\"ermis-create-channel__label\">{groupDescriptionLabel}</label>\n <textarea\n className=\"ermis-create-channel__textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={groupDescriptionPlaceholder}\n disabled={isCreating}\n maxLength={500}\n rows={2}\n />\n </div>\n\n <div className=\"ermis-create-channel__field ermis-create-channel__field--toggle\">\n <label className=\"ermis-create-channel__label\">{groupPublicLabel}</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPublic}\n className={`ermis-create-channel__toggle ${isPublic ? 'ermis-create-channel__toggle--on' : ''}`}\n onClick={() => setIsPublic(v => !v)}\n disabled={isCreating}\n >\n <span className=\"ermis-create-channel__toggle-thumb\" />\n </button>\n </div>\n </>\n )}\n\n {/* User Selection - Step 2 (Group) or Step 1 (Messaging) */}\n {((tab === 'team' && step === 2) || tab === 'messaging') && (\n <div className=\"ermis-create-channel__users\">\n <div className=\"ermis-create-channel__users-title\">\n Members <span style={{ color: 'var(--ermis-error)' }}>*</span>\n </div>\n <div style={{ height: tab === 'team' ? '280px' : '400px', display: 'flex', flexDirection: 'column' }}>\n <UserPicker\n mode={tab === 'messaging' ? 'radio' : 'checkbox'}\n onSelectionChange={setSelectedUsers}\n excludeUserIds={tab === 'messaging' ? existingDirectUserIds : []}\n initialSelectedUsers={selectedUsers}\n AvatarComponent={AvatarComponent}\n UserItemComponent={UserItemComponent as any}\n searchPlaceholder={userSearchPlaceholder}\n />\n </div>\n </div>\n )}\n\n {error && (\n <div className=\"ermis-create-channel__error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n\n </div>\n </Modal>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAA4D;;;ACA5D,IAAAC,gBAAgE;AAChE,4BAAiF;;;ACDjF,mBAAkB;AAoCX,IAAM,mBAAmB,aAAAC,QAAM,cAA4C,MAAS;;;AD4OvF;AAzQG,IAAM,oBAAsD,CAAC;AAAA,EAClE;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,UAAU,WAAW,QAAI,wBAA+B,IAAI;AACnE,QAAM,CAAC,YAAY,aAAa,QAAI,wBAA0B,EAAE;AAChE,QAAM,CAAC,aAAa,cAAc,QAAI,wBAA6B,IAAI;AACvE,QAAM,CAAC,cAAc,eAAe,QAAI,wBAA6B,IAAI;AACzE,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAiB,OAAO;AACxD,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAmC,MAAS;AAChF,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAmC,MAAS;AACpF,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAkB,KAAK;AAC3D,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,KAAK;AAClD,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,IAAI;AACrD,QAAM,CAAC,cAAc,eAAe,QAAI,wBAA4B,CAAC,CAAC;AACtE,QAAM,CAAC,cAAc,eAAe,QAAI,wBAA4B,CAAC,CAAC;AACtE,QAAM,CAAC,uBAAuB,wBAAwB,QAAI,wBAAiB,EAAE;AAC7E,QAAM,CAAC,uBAAuB,wBAAwB,QAAI,wBAAiB,EAAE;AAC7E,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAAS,KAAK;AAC5D,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAwB,IAAI;AACpE,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,wBAAS,KAAK;AAC9D,QAAM,CAAC,oBAAoB,qBAAqB,QAAI,wBAAS,KAAK;AAGlE,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,CAAC;AAClD,QAAM,eAAW,sBAA8C,IAAI;AAEnE,QAAM,iBAAa,2BAAY,MAAM;AACnC,oBAAgB,CAAC;AACjB,aAAS,UAAU,YAAY,MAAM;AACnC,sBAAgB,CAAC,SAAS,OAAO,CAAC;AAAA,IACpC,GAAG,GAAI;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAY,2BAAY,MAAM;AAClC,QAAI,SAAS,SAAS;AACpB,oBAAc,SAAS,OAAO;AAC9B,eAAS,UAAU;AAAA,IACrB;AACA,oBAAgB,CAAC;AAAA,EACnB,GAAG,CAAC,CAAC;AAEL,+BAAU,MAAM;AACd,QAAI,eAAe,iCAAW,WAAW;AACvC,iBAAW;AAAA,IACb,OAAO;AACL,gBAAU;AAAA,IACZ;AACA,WAAO,MAAM,UAAU;AAAA,EACzB,GAAG,CAAC,YAAY,YAAY,SAAS,CAAC;AAEtC,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,UAAW;AAG3B,UAAM,OAAO,IAAI,oCAAc,QAAQ,WAAW,UAAU,QAAQ;AACpE,gBAAY,IAAI;AAGhB,SAAK,cAAc,CAAC,SAAwB;AAC1C,oBAAc,KAAK,SAAS,UAAU;AACtC,kBAAY,KAAK,QAAQ;AACzB,oBAAc,KAAK,UAAU;AAC7B,sBAAgB,KAAK,YAAY;AAEjC,UAAI,KAAK,SAAS,cAAc,KAAK,YAAY;AAC/C,yBAAiB,KAAK,UAAU;AAAA,MAClC;AAAA,IACF;AAEA,SAAK,UAAU,CAAC,UAAkB;AAChC,sBAAgB,KAAK;AAErB,oBAAc,KAAK;AAAA,IACrB;AACA,SAAK,iBAAiB,CAAC,OAAO,UAAU;AACtC,sBAAgB,KAAK;AACrB,sBAAgB,KAAK;AAAA,IACvB;AACA,SAAK,sBAAsB,CAAC,cAAuB,mBAAmB,SAAS;AAE/E,SAAK,WAAW,EAAE,KAAK,CAAC,EAAE,cAAc,GAAG,cAAc,EAAE,MAAM;AAC/D,sBAAgB,CAAC;AACjB,sBAAgB,CAAC;AAAA,IACnB,CAAC;AAED,SAAK,eAAe,CAAC,WAA0B;AAC7C,YAAM,eAAe;AACrB,oBAAc,YAAY;AAC1B,UAAI,iBAAiB,iCAAW,SAAS,CAAC,cAAc;AACtD,uBAAe,IAAI;AACnB,wBAAgB,IAAI;AACpB,sBAAc,KAAK;AACnB,sBAAc,EAAE;AAAA,MAClB;AAAA,IACF;AAEA,SAAK,gBAAgB,CAAC,WAAwB;AAC5C,qBAAe,MAAM;AACrB,YAAM,cAAc,OAAO,eAAe;AAC1C,oBAAc,YAAY,WAAW,KAAK,CAAC,YAAY,CAAC,EAAE,OAAO;AACjE,YAAM,cAAc,OAAO,eAAe;AAC1C,sBAAgB,YAAY,WAAW,KAAK,CAAC,YAAY,CAAC,EAAE,OAAO;AAAA,IACrE;AAEA,SAAK,iBAAiB,CAAC,WAAwB,gBAAgB,MAAM;AAGrE,SAAK,uBAAuB,CAAC,UAA8D;AACzF,UAAI,OAAO,OAAO,iBAAiB,WAAW;AAC5C,4BAAoB,CAAC,MAAM,YAAY;AAAA,MACzC;AACA,UAAI,OAAO,OAAO,iBAAiB,WAAW;AAC5C,8BAAsB,CAAC,MAAM,YAAY;AAAA,MAC3C;AAAA,IACF;AAIA,SAAK,gBAAgB,MAAM;AACzB,kBAAY,OAAO;AAAA,IAErB;AAEA,WAAO,MAAM;AACX,YAAM,UAAU,YAAY;AAC1B,YAAI;AACF,gBAAM,KAAK,QAAQ;AAAA,QACrB,SAAS,GAAG;AAAA,QAAE;AAAA,MAChB;AACA,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,CAAC,QAAQ,WAAW,UAAU,UAAU,gBAAgB,WAAW,CAAC;AAEvE,QAAM,iBAAa,2BAAY,OAAO,MAAyB,QAAgB;AAC7E,QAAI,CAAC,SAAU;AACf,gBAAY,IAAI;AAChB,kBAAc,KAAK;AACnB,kBAAc,iCAAW,OAAO;AAChC,UAAM,SAAS,WAAW,MAAM,GAAG;AAEnC,kBAAc,MAAM,GAAG;AAAA,EACzB,GAAG,CAAC,UAAU,WAAW,CAAC;AAE1B,QAAM,iBAAa,2BAAY,YAAY;AACzC,QAAI,SAAU,OAAM,SAAS,WAAW;AAExC,qBAAiB;AAAA,EACnB,GAAG,CAAC,UAAU,cAAc,CAAC;AAE7B,QAAM,iBAAa,2BAAY,YAAY;AACzC,QAAI,SAAU,OAAM,SAAS,WAAW;AACxC,kBAAc,EAAE;AAChB,kBAAc,KAAK;AAEnB,qBAAiB;AAAA,EACnB,GAAG,CAAC,UAAU,cAAc,CAAC;AAE7B,QAAM,cAAU,2BAAY,YAAY;AACtC,QAAI,SAAU,OAAM,SAAS,QAAQ;AAErC,UAAM,WAAW;AACjB,kBAAc,EAAE;AAChB,kBAAc,KAAK;AACnB,mBAAe,IAAI;AACnB,oBAAgB,IAAI;AACpB,gBAAY,QAAQ;AAAA,EACtB,GAAG,CAAC,UAAU,cAAc,SAAS,CAAC;AAEtC,QAAM,wBAAoB,2BAAY,YAAY;AAChD,QAAI,CAAC,SAAU;AACf,QAAI,iBAAiB;AACnB,YAAM,SAAS,gBAAgB;AAAA,IACjC,OAAO;AACL,YAAM,SAAS,iBAAiB;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,UAAU,eAAe,CAAC;AAE9B,QAAM,wBAAoB,2BAAY,OAAO,aAAqB;AAChE,QAAI,CAAC,SAAU;AACf,UAAM,UAAU,MAAM,SAAS,kBAAkB,QAAQ;AACzD,QAAI,QAAS,0BAAyB,QAAQ;AAAA,EAChD,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,wBAAoB,2BAAY,OAAO,aAAqB;AAChE,QAAI,CAAC,SAAU;AACf,UAAM,UAAU,MAAM,SAAS,kBAAkB,QAAQ;AACzD,QAAI,QAAS,0BAAyB,QAAQ;AAAA,EAChD,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,iBAAa,2BAAY,MAAM,gBAAgB,IAAI,GAAG,CAAC,CAAC;AAE9D,QAAM,kBAAc,2BAAY,YAAY;AAC1C,QAAI,CAAC,SAAU;AACf,UAAM,SAAS,YAAY;AAC3B,gBAAY,OAAO;AAAA,EACrB,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,gBAAY,2BAAY,YAAY;AACxC,QAAI,CAAC,YAAY,CAAC,YAAa;AAC/B,UAAM,gBAAgB,CAAC;AACvB,UAAM,SAAS,UAAU,CAAC,aAAa;AACvC,kBAAc,aAAa;AAAA,EAC7B,GAAG,CAAC,UAAU,aAAa,UAAU,CAAC;AAEtC,QAAM,kBAAc,2BAAY,YAAY;AAC1C,QAAI,CAAC,SAAU;AACf,QAAI,aAAa;AACf,UAAI,YAAY,eAAe,EAAE,SAAS,GAAG;AAC3C,cAAM,gBAAgB,CAAC;AACvB,cAAM,SAAS,aAAa,CAAC,aAAa;AAC1C,wBAAgB,aAAa;AAAA,MAC/B,OAAO;AAIL,cAAM,SAAS,mBAAmB,IAAI;AACtC,wBAAgB,KAAK;AAAA,MACvB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,UAAU,aAAa,YAAY,CAAC;AAExC,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SACE,4CAAC,iBAAiB,UAAjB,EAA0B,OACxB,UACH;AAEJ;AAEA,kBAAkB,cAAc;;;AEtRhC,IAAAC,gBAAgE;;;ACAhE,IAAAC,gBAA2B;AAGpB,IAAM,iBAAiB,MAAM;AAClC,QAAM,cAAU,0BAAW,gBAAgB;AAC3C,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO;AACT;;;ACTA,IAAAC,gBAAiC;AAiCS,IAAAC,sBAAA;AA9BnC,IAAM,QAA8B,CAAC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB,sBAAsB;AACxB,MAAM;AACJ,+BAAU,MAAM;AACd,UAAM,YAAY,CAAC,MAAqB;AACtC,UAAI,EAAE,QAAQ,YAAY,OAAQ,SAAQ;AAAA,IAC5C;AACA,aAAS,iBAAiB,WAAW,SAAS;AAC9C,WAAO,MAAM,SAAS,oBAAoB,WAAW,SAAS;AAAA,EAChE,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,MAAI,CAAC,OAAQ,QAAO;AAEpB,SACE,6CAAC,SAAI,WAAU,uBAAsB,SAAS,sBAAsB,UAAU,QAC5E;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,SAAS;AAAA,MAClB,SAAS,OAAK,EAAE,gBAAgB;AAAA,MAE9B;AAAA,kBAAS,CAAC,oBACV,8CAAC,SAAI,WAAU,sBACZ;AAAA,kBACC,OAAO,UAAU,WAAW,6CAAC,QAAI,iBAAM,IAAQ,QAC7C,6CAAC,SAAI;AAAA,UACR,CAAC,mBACA,6CAAC,YAAO,WAAU,qBAAoB,SAAS,SAAS,cAAW,SACjE,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,yDAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK;AAAA,YACpC,6CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,aACtC,GACF;AAAA,WAEJ;AAAA,QAGF,6CAAC,SAAI,WAAU,oBACZ,UACH;AAAA,QAEC,UACC,6CAAC,SAAI,WAAU,sBACZ,kBACH;AAAA;AAAA;AAAA,EAEJ,GACF;AAEJ;;;AC1DA,IAAAC,gBAA+B;AAkE3B,IAAAC,sBAAA;AA1DJ,SAAS,YAAY,MAAuB;AAC1C,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,WAAW,IAAI,EAAG,QAAO;AAClC,QAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK;AACrC,MAAI,MAAM,UAAU,GAAG;AACrB,YAAQ,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,MAAM,SAAS,CAAC,EAAE,CAAC,GAAG,YAAY;AAAA,EAChE;AACA,SAAO,MAAM,CAAC,EAAE,CAAC,EAAE,YAAY;AACjC;AAKO,IAAM,SAAgC,cAAAC,QAAM,KAAK,CAAC;AAAA,EACvD;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AACF,MAAM;AACJ,QAAM,CAAC,UAAU,WAAW,IAAI,cAAAA,QAAM,SAAS,KAAK;AACpD,QAAM,CAAC,UAAU,WAAW,IAAI,cAAAA,QAAM,SAAS,KAAK;AACpD,QAAM,SAAS,cAAAA,QAAM,OAAyB,IAAI;AAGlD,gBAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,OAAO;AACT,kBAAY,KAAK;AACjB,UAAI,OAAO,SAAS,UAAU;AAC5B,oBAAY,IAAI;AAAA,MAClB,OAAO;AACL,oBAAY,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,eAAW,uBAAQ,MAAM,YAAY,IAAI,GAAG,CAAC,IAAI,CAAC;AAExD,QAAM,mBAAe,uBAA6B,OAAO;AAAA,IACvD,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,UAAU;AAAA,IACV,cAAc;AAAA;AAAA,IACd,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,EAClB,IAAI,CAAC,IAAI,CAAC;AAEV,QAAM,mBAAe,uBAA6B,OAAO;AAAA,IACvD,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU,OAAO;AAAA,IACjB,YAAY;AAAA,EACd,IAAI,CAAC,IAAI,CAAC;AAEV,SACE,8CAAC,SAAI,WAAW,uBAAuB,YAAY,IAAI,SAAS,KAAK,EAAE,IAAI,OAAO,cAEhF;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,QACP,OAAO;AAAA,QAEN;AAAA;AAAA,IACH;AAAA,IAGC,SAAS,CAAC,YACT;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,WAAU;AAAA,QACV,KAAK;AAAA,QACL,KAAK,QAAQ;AAAA,QACb,SAAQ;AAAA,QACR,QAAQ,MAAM,YAAY,IAAI;AAAA,QAC9B,SAAS,MAAM,YAAY,IAAI;AAAA,QAC/B,OAAO;AAAA,UACL,GAAG;AAAA,UACH,UAAU;AAAA,UACV,KAAK;AAAA,UACL,MAAM;AAAA,UACN,SAAS,WAAW,IAAI;AAAA,UACxB,YAAY;AAAA,UACZ,WAAW;AAAA,QACb;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ,CAAC;AAED,OAAO,cAAc;;;AHjGrB,IAAAC,yBAA2B;AAkKrB,IAAAC,sBAAA;AA9JN,IAAM,iBAAiB,CAAC,iBAAiC;AACvD,QAAM,IAAI,KAAK,MAAM,eAAe,EAAE,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AAClE,QAAM,KAAK,eAAe,IAAI,SAAS,EAAE,SAAS,GAAG,GAAG;AACxD,SAAO,GAAG,CAAC,IAAI,CAAC;AAClB;AAEO,IAAM,cAA0C,cAAAC,QAAM,KAAK,CAAC;AAAA,EACjE;AAAA,EACA,oBAAoB,CAAC,SAAiB,YAAY,IAAI;AAAA,EACtD,oBAAoB,CAAC,SAAiB,YAAY,IAAI;AAAA,EACtD,mBAAmB,CAAC,SAAiB,WAAW,IAAI;AAAA,EACpD,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,uBAAuB;AAAA,EACvB,iBAAiB;AAAA,EACjB,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,kBAAkB;AAAA,EAClB,sBAAsB;AAAA,EACtB,mBAAmB;AAAA,EACnB,wBAAwB;AAAA,EACxB;AAAA,EACA,kBAAkB;AAAA,EAClB,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,wBAAwB;AAAA,EACxB,kBAAkB;AAAA,EAClB,yBAAyB;AAAA,EACzB,yBAAyB;AAAA,EACzB,gBAAgB;AAAA,EAChB,sBAAsB;AACxB,MAAM;AACJ,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,eAAe;AAEnB,QAAM,oBAAgB,sBAAyB,IAAI;AACnD,QAAM,qBAAiB,sBAAyB,IAAI;AACpD,QAAM,qBAAiB,sBAAyB,IAAI;AACpD,QAAM,sBAAkB,sBAAyB,IAAI;AACrD,QAAM,uBAAmB,sBAAuB,IAAI;AAGpD,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,KAAK;AAEtD,QAAM,uBAAmB,2BAAY,MAAM;AACzC,QAAI,CAAC,iBAAiB,QAAS;AAC/B,QAAI,CAAC,SAAS,mBAAmB;AAC/B,uBAAiB,QAAQ,oBAAoB,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC/D,OAAO;AACL,eAAS,iBAAiB,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,+BAAU,MAAM;AACd,UAAM,eAAe,MAAM,gBAAgB,CAAC,CAAC,SAAS,iBAAiB;AACvE,aAAS,iBAAiB,oBAAoB,YAAY;AAC1D,WAAO,MAAM,SAAS,oBAAoB,oBAAoB,YAAY;AAAA,EAC5E,GAAG,CAAC,CAAC;AAGL,+BAAU,MAAM;AACd,QAAI,eAAe,GAAG;AACpB,6BAAuB,YAAY;AAAA,IACrC;AAAA,EACF,GAAG,CAAC,cAAc,oBAAoB,CAAC;AAEvC,+BAAU,MAAM;AACd,QAAI,cAAc,WAAW,aAAa;AACxC,oBAAc,QAAQ,YAAY;AAAA,IACpC;AAAA,EACF,GAAG,CAAC,aAAa,UAAU,UAAU,CAAC;AAEtC,+BAAU,MAAM;AACd,QAAI,cAAc;AAChB,UAAI,aAAa,WAAW,eAAe,SAAS;AAClD,uBAAe,QAAQ,YAAY;AAAA,MACrC;AACA,UAAI,eAAe,SAAS;AAC1B,uBAAe,QAAQ,YAAY;AAAA,MACrC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,cAAc,UAAU,UAAU,CAAC;AAEvC,+BAAU,MAAM;AACd,QAAI,eAAe,kCAAW,WAAW,gBAAgB,SAAS;AAChE,YAAM,cAAc,gBAAgB,QAAQ,KAAK;AACjD,UAAI,gBAAgB,QAAW;AAC7B,oBAAY,MAAM,CAAC,MAAM,QAAQ,IAAI,6CAA6C,CAAC,CAAC;AAAA,MACtF;AAAA,IACF,WAAW,gBAAgB,SAAS;AAClC,sBAAgB,QAAQ,MAAM;AAC9B,sBAAgB,QAAQ,cAAc;AAAA,IACxC;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAEf,MAAI,CAAC,cAAc,CAAC,aAAc,QAAO;AAGzC,MAAI,yBAAyB,cAAc,eAAe,kCAAW,QAAS,QAAO;AAErF,QAAM,SAAS,eAAe,kCAAW,WAAW,eAAe,kCAAW,aAAa,CAAC,CAAC;AAC7F,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,QAAQ,eAAe,eAC3B,eAAe,kCAAW,UACrB,aAAa,kBAAkB,QAAQ,IAAI,kBAAkB,QAAQ,IACtE,iBAAiB,QAAQ;AAG/B,QAAM,WAAW,aAAa,aAAa;AAC3C,QAAM,gBAAgB,aAAa,WAAW,eAAe,kCAAW,YAAY,UAAU;AAG9F,QAAM,iBAAiB,kBAAkB,MACvC,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,uDAAC,UAAK,GAAE,iSAAgS,GAC1S;AAGF,QAAM,iBAAiB,kBAAkB,MACvC,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,iDAAC,aAAQ,QAAO,yBAAwB;AAAA,IACxC,6CAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,KACzD;AAGF,QAAM,oBAAoB,qBAAqB,MAC7C,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,uDAAC,UAAK,GAAE,+GAA8G,GACxH;AAGF,QAAM,eAAe,gBAAgB,MACnC,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,iDAAC,UAAK,GAAE,wDAAuD;AAAA,IAC/D,6CAAC,UAAK,GAAE,8BAA6B;AAAA,IACrC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACtC,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACvC;AAGF,QAAM,kBAAkB,mBAAmB,MACzC,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,iDAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,IACpC,6CAAC,UAAK,GAAE,0DAAyD;AAAA,IACjE,6CAAC,UAAK,GAAE,yDAAwD;AAAA,IAChE,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACtC,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACvC;AAGF,QAAM,uBAAuB,wBAAwB,MACnD,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,iDAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,IACvD,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACrC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACtC,6CAAC,UAAK,GAAE,mBAAkB;AAAA,IAC1B,6CAAC,UAAK,GAAE,YAAW;AAAA,KACrB;AAGF,QAAM,0BAA0B,2BAA2B,MACzD,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,iDAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,IACvD,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACrC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACtC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACxC;AAGF,QAAM,sBAAsB,uBAAuB,MACjD,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,iDAAC,UAAK,GAAE,0BAAyB;AAAA,IACjC,6CAAC,UAAK,GAAE,4BAA2B;AAAA,IACnC,6CAAC,UAAK,GAAE,2BAA0B;AAAA,IAClC,6CAAC,UAAK,GAAE,6BAA4B;AAAA,KACtC;AAGF,QAAM,0BAA0B,2BAA2B,MACzD,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,iDAAC,UAAK,GAAE,aAAY;AAAA,IACpB,6CAAC,UAAK,GAAE,eAAc;AAAA,IACtB,6CAAC,UAAK,GAAE,cAAa;AAAA,IACrB,6CAAC,UAAK,GAAE,aAAY;AAAA,KACtB;AAIF,QAAM,uBAAuB,uBAAuB;AAKpD,QAAM,iBAAiB,MAAM;AAE3B,QAAI,4BAA4B;AAC9B,aACE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IAEJ;AAEA,WACE,8CAAC,SAAI,WAAU,2BAEb;AAAA,oDAAC,SAAI,WAAU,+BACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAW,8BAA8B,aAAa,sCAAsC,EAAE;AAAA,YAC9F,gBAAc;AAAA,YAEb,uBAAa,6CAAC,mBAAgB,IAAK,6CAAC,gBAAa;AAAA;AAAA,QACpD;AAAA,QACC,aAAa,SAAS,KACrB;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,kBAAkB,EAAE,OAAO,KAAK;AAAA,YAEhD,uBAAa,IAAI,OAChB,6CAAC,YAAwB,OAAO,EAAE,UAAW,YAAE,SAAS,gBAA3C,EAAE,QAAsD,CACtE;AAAA;AAAA,QACH;AAAA,SAEJ;AAAA,MAGC,aAAa,UACZ,8CAAC,SAAI,WAAU,+BACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAW,8BAA8B,eAAe,sCAAsC,EAAE;AAAA,YAChG,gBAAc;AAAA,YAEb,yBAAe,6CAAC,qBAAkB,IAAK,6CAAC,kBAAe;AAAA;AAAA,QAC1D;AAAA,QACC,aAAa,SAAS,KACrB;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,kBAAkB,EAAE,OAAO,KAAK;AAAA,YAEhD,uBAAa,IAAI,OAChB,6CAAC,YAAwB,OAAO,EAAE,UAAW,YAAE,SAAS,YAA3C,EAAE,QAAkD,CAClE;AAAA;AAAA,QACH;AAAA,SAEJ,IAEA,6CAAC,SAAI,WAAU,+BACb;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UACV,gBAAc;AAAA,UAEd,uDAAC,wBAAqB;AAAA;AAAA,MACxB,GACF;AAAA,MAID,aAAa,WAAW,OAAO,UAAU,cAAc,oBAAoB,cAC1E,6CAAC,SAAI,WAAU,+BACb;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAW,8BAA8B,kBAAkB,uCAAuC,EAAE;AAAA,UACpG,gBAAc,kBAAkB,uBAAuB;AAAA,UAEtD,4BAAkB,6CAAC,wBAAqB,IAAK,6CAAC,2BAAwB;AAAA;AAAA,MACzE,GACF;AAAA,MAIF,6CAAC,SAAI,WAAU,+BACb;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UACV,gBAAc,eAAe,sBAAsB;AAAA,UAElD,yBAAe,6CAAC,2BAAwB,IAAK,6CAAC,uBAAoB;AAAA;AAAA,MACrE,GACF;AAAA,MAGA,6CAAC,SAAI,WAAU,qCAAoC;AAAA,MAGnD;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UACV,gBAAc;AAAA,UAEd,uDAAC,kBAAe;AAAA;AAAA,MAClB;AAAA,OACF;AAAA,EAEJ;AAKA,QAAM,gBAAgB,MAAM;AAE1B,QAAI,wBAAwB;AAC1B,aACE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IAEJ;AAEA,WACE,8CAAC,SAAI,WAAU,0BAEb;AAAA,mDAAC,SAAI,WAAU,iCACb,uDAAC,SAAI,WAAU,uCACb;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,UAAU;AAAA,UACjB,MAAM,UAAU;AAAA,UAChB,MAAM;AAAA;AAAA,MACR,GACF,GACF;AAAA,MAEA,6CAAC,QAAG,WAAU,+BACX,oBAAU,MACb;AAAA,MACA,6CAAC,OAAE,WAAU,iCACV,uBAAa,oBAAoB,cACpC;AAAA,MAGA,8CAAC,SAAI,WAAU,6BACZ;AAAA,qBAAa,UAAU,6CAAC,kBAAe,IAAK,6CAAC,kBAAe;AAAA,QAC5D,aAAa,UAAU,sBAAsB;AAAA,SAChD;AAAA,MAGA,6CAAC,SAAI,WAAU,kCACZ,uBACC,8EACE;AAAA,sDAAC,SAAI,WAAU,iCACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,WAAU;AAAA,cAEV,uDAAC,kBAAe;AAAA;AAAA,UAClB;AAAA,UACA,6CAAC,UAAK,WAAU,+BAA+B,2BAAgB;AAAA,WACjE;AAAA,QACA,8CAAC,SAAI,WAAU,iCACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,WAAU;AAAA,cAET,uBAAa,UAAU,6CAAC,kBAAe,IAAK,6CAAC,kBAAe;AAAA;AAAA,UAC/D;AAAA,UACA,6CAAC,UAAK,WAAU,+BAA+B,2BAAgB;AAAA,WACjE;AAAA,SACF,IAEA,8CAAC,SAAI,WAAU,iCACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAU;AAAA,YAEV,uDAAC,kBAAe;AAAA;AAAA,QAClB;AAAA,QACA,6CAAC,UAAK,WAAU,+BAA+B,wBAAa;AAAA,SAC9D,GAEJ;AAAA,OACF;AAAA,EAEJ;AAKA,QAAM,kBAAkB,MAAM;AAC5B,QAAI,aAAa,SAAS;AAExB,UAAI,+BAA+B;AACjC,eACE;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF;AAAA,MAEJ;AAEA,aACE,6CAAC,SAAI,WAAU,yBACb,wDAAC,SAAI,WAAU,kCACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,UAAQ;AAAA,YACR,aAAW;AAAA,YACX,WAAU;AAAA;AAAA,QACZ;AAAA,QACA,6CAAC,SAAI,WAAU,8BACb;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,UAAQ;AAAA,YACR,aAAW;AAAA,YACX,OAAK;AAAA,YACL,WAAU;AAAA;AAAA,QACZ,GACF;AAAA,QAEC,oBACC,6CAAC,SAAI,WAAU,qCACb,uDAAC,mBAAgB,GACnB;AAAA,QAGF,6CAAC,SAAI,WAAU,yCACZ,yBAAe,GAClB;AAAA,SACF,GACF;AAAA,IAEJ;AAIA,QAAI,+BAA+B;AACjC,aACE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IAEJ;AAEA,WACE,6CAAC,SAAI,WAAU,yBACb,wDAAC,SAAI,WAAU,kCACb;AAAA,oDAAC,SAAI,WAAU,uCACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,UAAU;AAAA,YACjB,MAAM,UAAU;AAAA,YAChB,MAAM;AAAA;AAAA,QACR;AAAA,QAEC,oBACC,6CAAC,SAAI,WAAU,8EACb,uDAAC,mBAAgB,GACnB;AAAA,SAEJ;AAAA,MACA,6CAAC,QAAG,WAAU,8BACX,oBAAU,MACb;AAAA,MAGA,8CAAC,SAAI,WAAU,gCACb;AAAA,qDAAC,UAAK,WAAU,oCAAmC;AAAA,QACnD,6CAAC,UAAM,0BAAe;AAAA,QACtB,6CAAC,UAAK,WAAU,wBACb,yBAAe,YAAY,GAC9B;AAAA,SACF;AAAA,MAGA,6CAAC,SAAI,WAAU,8BACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,6CAAC,UAAa,WAAU,mCAAb,CAA6C,CACzD,GACH;AAAA,MAEA,6CAAC,WAAM,KAAK,gBAAgB,UAAQ,MAAC,WAAU,gCAA+B;AAAA,MAG7E,eAAe;AAAA,OAClB,GACF;AAAA,EAEJ;AAKA,QAAM,cAAc,MAAM;AACxB,QAAI,CAAC,aAAc,QAAO;AAG1B,QAAI,sBAAsB;AACxB,aACE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA,WAAW;AAAA;AAAA,MACb;AAAA,IAEJ;AAEA,WACE,8CAAC,SAAI,WAAU,wBACb;AAAA,mDAAC,SAAI,WAAU,6BACb,wDAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,6BAA4B,aAAY,KAAI,OAAM,MAAK,QAAO,MACxG;AAAA,qDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAC/B,6CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,QACrC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK;AAAA,SAC3C,GACF;AAAA,MACA,6CAAC,OAAE,WAAU,6BAA6B,wBAAa;AAAA,MACvD;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS;AAAA,UAET;AAAA,yDAAC,kBAAe;AAAA,YAAE;AAAA,YAAE;AAAA;AAAA;AAAA,MACtB;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,6CAAC,SAAM,QAAgB,SAAS,SAAS,OAAc,iBAAe,MAAC,qBAAqB,OAAO,UAAU,eAC3G,wDAAC,SAAI,WAAW,iBAAiB,eAAe,8BAA8B,EAAE,GAAG,YAAY,IAAI,SAAS,KAAK,EAAE,IAAI,KAAK,kBAExH;AAAA,8BAAyB,0BACzB;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,KAAK,aAAa,wBAAwB;AAAA,QAC1C,MAAI;AAAA,QACJ,WAAU;AAAA;AAAA,IACZ;AAAA,IAID,gBAAgB,YAAY;AAAA,IAG5B,CAAC,gBAAgB,eAAe,kCAAW,WAAW,cAAc;AAAA,IAGpE,CAAC,gBAAgB,eAAe,kCAAW,aAAa,gBAAgB;AAAA,KAC3E,GACF;AAEJ,CAAC;AAED,YAAY,cAAc;;;AHxiBa,IAAAC,sBAAA;AAzEhC,IAAM,kBAAc,6BAAuC,IAAI;AAE/D,IAAM,eAA4C,CAAC;AAAA,EACxD;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,wBAAyB,IAAI;AAC7E,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAgB,YAAY;AACtD,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAkC,CAAC,CAAC;AACpE,QAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAuC,IAAI;AACrF,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,wBAAuC,IAAI;AACvF,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAyC,CAAC,CAAC;AAC7E,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,wBAAuC,IAAI;AAC7F,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAAwB,IAAI;AAE1E,QAAM,gBAAgB;AAEtB,QAAM,uBAAmB,2BAAY,CAAC,YAA4B;AAChE,wBAAoB,OAAO;AAC3B,qBAAiB,IAAI;AACrB,sBAAkB,IAAI;AACtB,QAAI,SAAS;AACX,kBAAY,CAAC,GAAG,QAAQ,MAAM,cAAc,CAAC;AAC7C,mBAAa,EAAE,GAAG,QAAQ,MAAM,KAAK,CAAC;AAAA,IACxC,OAAO;AACL,kBAAY,CAAC,CAAC;AACd,mBAAa,CAAC,CAAC;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,mBAAe,2BAAY,MAAM;AACrC,QAAI,eAAe;AACjB,kBAAY,CAAC,GAAG,cAAc,MAAM,cAAc,CAAC;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,QAA0B;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,aAAa,kBAAkB,6CAAC,mBAAgB,IACpD;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA;AAAA,EACF;AAGF,QAAM,UACJ,6CAAC,YAAY,UAAZ,EAAqB,OACpB,wDAAC,SAAI,WAAW,0BAA0B,KAAK,IAC5C;AAAA;AAAA,IACA,cAAc;AAAA,KACjB,GACF;AAGF,MAAI,YAAY;AACd,QAAI,CAAC,eAAe;AAClB,cAAQ,KAAK,mEAAmE;AAAA,IAClF;AACA,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW,iBAAiB;AAAA,QAC5B,UAAU;AAAA,QACV,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,SAAO;AACT;;;AOxHA,IAAAC,gBAA2B;AAIpB,IAAM,gBAAgB,MAAwB;AACnD,QAAM,UAAM,0BAAW,WAAW;AAClC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,SAAO;AACT;;;ACVA,IAAAC,gBAAiD;AAO1C,IAAM,aAAa,MAAwB;AAChD,QAAM,EAAE,cAAc,IAAI,cAAc;AACxC,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AAErD,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA;AAAA,EACF;AACF;;;ACjBA,IAAAC,iBAAkC;AAe3B,SAAS,sBACd,UACA,aACM;AACN,QAAM,EAAE,QAAQ,eAAe,iBAAiB,IAAI,cAAc;AAGlE,QAAM,uBAAmB,uBAAO,aAAa;AAC7C,mBAAiB,UAAU;AAE3B,gCAAU,MAAM;AAEd,UAAM,mBAAmB,CAAC,UAAiB;AACzC,YAAM,WAAW,MAAM;AACvB,UAAI,CAAC,SAAU;AAKf,YAAM,SAAS,iBAAiB;AAChC,UAAI,QAAQ,QAAQ,YAAY,MAAM,MAAM,OAAO,OAAO,QAAQ;AAChE,cAAM,mBAAmB,QAAQ,OAAO,OAAO,YAAY,MAAM;AACjE,cAAM,oBAAoB,OAAO,SAAS,eAAe,QAAQ,OAAO,OAAO,YAAY,OAAO;AAClG,cAAM,kBACJ,OAAO,OAAO,YAAY,iBAAiB,aAAc,OAAO,OAAO,YAAwC,SAAS;AAE1H,YAAI,CAAC,oBAAoB,CAAC,qBAAqB,CAAC,iBAAiB;AAC/D,iBAAO,SAAS,EAAE,MAAM,MAAM;AAAA,UAE9B,CAAC;AAAA,QACH;AAAA,MACF;AAEA,kBAAY,CAAC,SAAS;AACpB,cAAM,MAAM,KAAK,UAAU,CAACC,QAAOA,IAAG,QAAQ,QAAQ;AACtD,YAAI,OAAO,GAAG;AAEZ,iBAAO,QAAQ,IAAI,CAAC,GAAG,IAAI,IAAI;AAAA,QACjC;AAEA,cAAM,UAAU,KAAK,GAAG;AAGxB,YAAI,QAAQ,OAAO,YAAY,QAAQ;AACrC,iBAAO,CAAC,GAAG,IAAI;AAAA,QACjB;AAGA,cAAM,UAAU,CAAC,GAAG,IAAI;AACxB,cAAM,CAAC,EAAE,IAAI,QAAQ,OAAO,KAAK,CAAC;AAClC,gBAAQ,QAAQ,EAAE;AAClB,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAGA,UAAM,uBAAuB,CAAC,UAAiB;AAC7C,YAAM,WAAW,MAAM,OAAO,MAAM,SAAS;AAC7C,UAAI,CAAC,SAAU;AAEf,UAAI,iBAAiB,SAAS,QAAQ,UAAU;AAC9C,yBAAiB,IAAI;AAAA,MACvB;AAEA,kBAAY,CAAC,SAAS,KAAK,OAAO,CAAC,OAAO,GAAG,QAAQ,QAAQ,CAAC;AAAA,IAChE;AAGA,UAAM,sBAAsB,CAAC,UAAiB;AAC5C,YAAM,WAAW,MAAM,OAAO,MAAM,SAAS;AAE7C,YAAM,gBAAgB,WAClB,WACC,MAAkC,aACnC,GAAI,MAAkC,YAAY,IAAK,MAAkC,UAAU,KACnG;AAEJ,UAAI,CAAC,cAAe;AAEpB,YAAM,gBAAgB,MAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM,MAAM,MAAM,MAAM;AAGrF,UAAI,kBAAkB,OAAO,QAAQ;AACnC,YAAI,iBAAiB,SAAS,QAAQ,eAAe;AACnD,2BAAiB,IAAI;AAAA,QACvB;AACA,oBAAY,CAAC,SAAS,KAAK,OAAO,CAAC,OAAO,GAAG,QAAQ,aAAa,CAAC;AAAA,MACrE;AAAA,IAGF;AAGA,UAAM,uBAAuB,OAAO,OAAc,aAAsB,UAAU;AAChF,YAAM,OAAO,MAAM,SAAS,QAAS,MAAkC;AACvE,YAAM,KAAK,MAAM,SAAS,MAAO,MAAkC;AACnE,YAAM,MAAM,MAAM,SAAS,OAAO,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE;AAE5D,UAAI,CAAC,QAAQ,CAAC,GAAI;AAElB,UAAI;AAEF,cAAM,kBAAkB,OAAO,QAAQ,MAAgB,EAAY;AAKnE,YAAI,CAAC,cAAc,MAAM,SAAS,kBAAkB,MAAM,UAAU,gBAAgB,OAAO;AACzF,0BAAgB,MAAM,aAAa,EAAE,GAAG,gBAAgB,MAAM,YAAY,GAAG,MAAM,OAAO;AAAA,QAC5F;AAGA,YAAI,cAAc,CAAC,gBAAgB,aAAa;AAC9C,gBAAM,gBAAgB,MAAM,EAAE,MAAM,CAAC,QAAQ,QAAQ,MAAM,4BAA4B,GAAG,CAAC;AAAA,QAC7F;AAEA,oBAAY,CAAC,SAAS;AAEpB,cAAI,KAAK,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG,GAAG;AACnC,mBAAO;AAAA,UACT;AACA,iBAAO,CAAC,iBAAiB,GAAG,IAAI;AAAA,QAClC,CAAC;AAGD,YAAI,CAAC,gBAAgB,aAAa;AAChC,cAAI,WAAW;AACf,gBAAM,mBAAmB,YAAY,MAAM;AACzC;AACA,gBAAI,gBAAgB,eAAe,WAAW,IAAiB;AAC7D,4BAAc,gBAAgB;AAC9B,kBAAI,gBAAgB,aAAa;AAE/B,4BAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAEzB,sBAAM,YAAY,gBAAgB,UAAU;AAC5C,oBAAI,mBAAmB,aAAa,OAAO,UAAU,kBAAkB,YAAY;AACjF,kBAAC,UAAU,cAA2B;AAAA,oBACpC,MAAM;AAAA,oBACN,KAAK,gBAAgB;AAAA,oBACrB,SAAS,gBAAgB;AAAA,kBAC3B,CAAC;AAAA,gBACH;AAAA,cACF;AAAA,YACF;AAAA,UACF,GAAG,EAAE;AAAA,QACP;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,0CAA0C,GAAG;AAAA,MAC7D;AAAA,IACF;AAGA,UAAM,oBAAoB,OAAO,UAAiB;AAChD,YAAM,cAAc,MAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM;AAEjE,UAAI,gBAAgB,OAAO,QAAQ;AACjC,cAAM,qBAAqB,OAAO,KAAK;AAAA,MACzC;AAAA,IACF;AAGA,UAAM,sBAAsB,CAAC,UAAiB;AAC5C,YAAM,gBAAgB,MAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM,MAAM,MAAM,MAAM;AACrF,UAAI,kBAAkB,OAAO,QAAQ;AACnC,oBAAY,CAAC,SAAS;AAEpB,gBAAM,WACJ,MAAM,OACN,MAAM,SAAS,QACb,MAAkC,aAAa,GAAI,MAAkC,YAAY,IAAK,MAAkC,UAAU,KAAK;AAE3J,cAAI,YAAY,MAAM,QAAQ;AAC5B,kBAAM,gBAAgB,KAAK,KAAK,CAAC,MAAM,EAAE,QAAQ,QAAQ;AAEzD,gBAAI,iBAAiB,cAAc,OAAO;AACxC,4BAAc,MAAM,aAAa;AAAA,gBAC/B,GAAG,cAAc,MAAM;AAAA,gBACvB,GAAG,MAAM;AAAA,cACX;AAAA,YACF;AAAA,UACF;AAEA,iBAAO,CAAC,GAAG,IAAI;AAAA,QACjB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,OAAO,OAAO,GAAG,eAAe,gBAAgB;AACtD,UAAM,OAAO,OAAO,GAAG,mBAAmB,oBAAoB;AAC9D,UAAM,OAAO,OAAO,GAAG,kBAAkB,mBAAmB;AAC5D,UAAM,OAAO,OAAO,GAAG,mBAAmB,CAAC,UAAU,qBAAqB,OAAO,IAAI,CAAC;AACtF,UAAM,OAAO,OAAO,GAAG,gBAAgB,iBAAiB;AACxD,UAAM,OAAO,OAAO,GAAG,iCAAiC,iBAAiB;AACzE,UAAM,OAAO,OAAO,GAAG,gCAAgC,mBAAmB;AAC1E,UAAM,OAAO,OAAO,GAAG,gCAAgC,mBAAmB;AAE1E,WAAO,MAAM;AACX,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,gBAAgB,CAAC;AAC5C;;;AC/NA,IAAAC,iBAAoC;AAO7B,SAAS,qBAAqB,SAAkB,eAAwB;AAE7E,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,yBAAS,MAAM,QAAQ,QAAQ,OAAO,YAAY,MAAM,CAAC;AAC3G,QAAM,CAAC,oBAAoB,qBAAqB,QAAI,yBAAS,MAAM;AACjE,QAAI,QAAQ,SAAS,YAAa,QAAO;AACzC,WAAO,QAAQ,QAAQ,OAAO,YAAY,OAAO;AAAA,EACnD,CAAC;AAGD,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,CAAC;AAEhD,gCAAU,MAAM;AACd,yBAAqB,QAAQ,QAAQ,OAAO,YAAY,MAAM,CAAC;AAC/D;AAAA,MACE,QAAQ,SAAS,cAAc,QAAQ,QAAQ,OAAO,YAAY,OAAO,IAAI;AAAA,IAC/E;AAEA,UAAM,eAAe,CAAC,UAAe;AACnC,UAAI,MAAM,QAAQ,YAAY,eAAe;AAC3C,6BAAqB,IAAI;AAAA,MAC3B;AAAA,IACF;AACA,UAAM,iBAAiB,CAAC,UAAe;AACrC,UAAI,MAAM,QAAQ,YAAY,eAAe;AAC3C,6BAAqB,KAAK;AAAA,MAC5B;AAAA,IACF;AAEA,UAAM,eAAe,MAAM,eAAe,CAAC,MAAM,IAAI,CAAC;AAEtD,UAAM,OAAO,QAAQ,GAAG,iBAAiB,YAAY;AACrD,UAAM,OAAO,QAAQ,GAAG,mBAAmB,cAAc;AACzD,UAAM,OAAO,QAAQ,GAAG,eAAe,YAAY;AACnD,UAAM,OAAO,QAAQ,GAAG,gBAAgB,YAAY;AACpD,UAAM,OAAO,QAAQ,GAAG,mBAAmB,YAAY;AACvD,UAAM,OAAO,QAAQ,GAAG,mBAAmB,YAAY;AACvD,UAAM,OAAO,QAAQ,GAAG,mBAAmB,YAAY;AACvD,UAAM,OAAO,QAAQ,GAAG,gBAAgB,YAAY;AACpD,UAAM,OAAO,QAAQ,GAAG,kBAAkB,YAAY;AAGtD,UAAM,gBAAgB,CAAC,UAAe;AACpC,UAAI,MAAM,QAAQ,YAAY,eAAe;AAC3C,8BAAsB,IAAI;AAAA,MAC5B;AAAA,IACF;AACA,UAAM,kBAAkB,CAAC,UAAe;AACtC,UAAI,MAAM,QAAQ,YAAY,eAAe;AAC3C,8BAAsB,KAAK;AAAA,MAC7B;AAAA,IACF;AACA,UAAM,QAAQ,QAAQ,GAAG,kBAAkB,aAAa;AACxD,UAAM,QAAQ,QAAQ,GAAG,oBAAoB,eAAe;AAE5D,WAAO,MAAM;AACX,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,YAAM,YAAY;AAClB,YAAM,YAAY;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,SAAS,aAAa,CAAC;AAE3B,SAAO,EAAE,mBAAmB,oBAAoB,YAAY;AAC9D;;;AC7EA,IAAAC,iBAAoC;AAW7B,SAAS,eAAe,SAAqC,eAAwB;AAC1F,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAkB,MAAM;AACtD,WAAO,QAAQ,SAAS,OAAO,YAAY,MAAM;AAAA,EACnD,CAAC;AAED,gCAAU,MAAM;AACd,QAAI,CAAC,SAAS;AACZ,kBAAY,KAAK;AACjB;AAAA,IACF;AAGA,gBAAY,QAAQ,QAAQ,OAAO,YAAY,MAAM,CAAC;AAEtD,UAAM,eAAe,CAAC,UAAe;AACnC,UAAI,MAAM,QAAQ,YAAY,eAAe;AAC3C,oBAAY,IAAI;AAAA,MAClB;AAAA,IACF;AAEA,UAAM,iBAAiB,CAAC,UAAe;AACrC,UAAI,MAAM,QAAQ,YAAY,eAAe;AAC3C,oBAAY,KAAK;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,OAAO,QAAQ,GAAG,iBAAiB,YAAY;AACrD,UAAM,OAAO,QAAQ,GAAG,mBAAmB,cAAc;AAEzD,WAAO,MAAM;AACX,WAAK,YAAY;AACjB,WAAK,YAAY;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,SAAS,aAAa,CAAC;AAE3B,SAAO,EAAE,SAAS;AACpB;;;AC/CA,IAAAC,iBAAoC;AAiB7B,SAAS,gBAAgB,SAAqC,eAAwB;AAC3F,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAkB,MAAM;AACxD,QAAI,SAAS,SAAS,YAAa,QAAO;AAC1C,WAAO,QAAQ,SAAS,OAAO,YAAY,OAAO;AAAA,EACpD,CAAC;AAED,gCAAU,MAAM;AACd,QAAI,CAAC,WAAW,QAAQ,SAAS,aAAa;AAC5C,mBAAa,KAAK;AAClB;AAAA,IACF;AAGA,iBAAa,QAAQ,QAAQ,OAAO,YAAY,OAAO,CAAC;AAExD,UAAM,gBAAgB,CAAC,UAAe;AACpC,UAAI,MAAM,QAAQ,YAAY,eAAe;AAC3C,qBAAa,IAAI;AAAA,MACnB;AAAA,IACF;AAEA,UAAM,kBAAkB,CAAC,UAAe;AACtC,UAAI,MAAM,QAAQ,YAAY,eAAe;AAC3C,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF;AAEA,UAAM,OAAO,QAAQ,GAAG,kBAAkB,aAAa;AACvD,UAAM,OAAO,QAAQ,GAAG,oBAAoB,eAAe;AAE3D,WAAO,MAAM;AACX,WAAK,YAAY;AACjB,WAAK,YAAY;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,SAAS,aAAa,CAAC;AAE3B,SAAO,EAAE,UAAU;AACrB;;;ACtDA,IAAAC,iBAAoC;AAM7B,SAAS,gBAAgB,SAAqC,eAAwB;AAC3F,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAkB,MAAM;AACxD,UAAM,aAAa,SAAS,OAAO,cAAc,SAAS,OAAO,UAAU,iBAAiB,EAAE;AAC9F,WAAO,YAAY,iBAAiB,aAAc,YAAwC,SAAS;AAAA,EACrG,CAAC;AAED,gCAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,eAAe;AAC9B,mBAAa,KAAK;AAClB;AAAA,IACF;AAEA,UAAM,eAAe,MAAM;AACzB,YAAM,aAAa,QAAQ,OAAO,cAAc,QAAQ,OAAO,UAAU,aAAa;AACtF,aAAO,YAAY,iBAAiB,aAAc,YAAwC,SAAS;AAAA,IACrG;AAGA,iBAAa,aAAa,CAAC;AAE3B,UAAM,uBAAuB,CAAC,UAAmC;AAG/D,UAAI,MAAM,UAAU,QAAQ,SAAS,QAAQ,MAAM,YAAY;AAC7D,gBAAQ,MAAM,aAAa;AAAA,UACzB,GAAG,QAAQ,MAAM;AAAA,UACjB,GAAI,MAAM;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAEA,UAAM,qBAAqB,CAAC,UAAmC;AAC7D,YAAM,cAAc,MAAM;AAC1B,YAAM,YAAY,MAAM;AACxB,YAAM,cAAc,aAAa,WAAY,aAAa,MAAkC,MAAM,WAAW;AAC7G,UAAI,gBAAgB,cAAe;AAEnC,YAAM,WACJ,MAAM,OAAQ,MAAM,SAAqC,QAAQ,MAAM,aAAa,GAAG,MAAM,YAAY,IAAI,MAAM,UAAU,KAAK;AACpI,UAAI,aAAa,QAAQ,KAAK;AAC5B,6BAAqB,KAAK;AAC1B,qBAAa,aAAa,CAAC;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,OAAO,OAAO,GAAG,gCAAgC,kBAAkB;AACzE,UAAM,OAAO,OAAO,GAAG,gCAAgC,kBAAkB;AAEzE,WAAO,MAAM;AACX,WAAK,YAAY;AACjB,WAAK,YAAY;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,SAAS,aAAa,CAAC;AAE3B,SAAO,EAAE,UAAU;AACrB;;;AC9DA,IAAAC,iBAAiE;AACjE,oBAAsB;AAEtB,IAAAC,yBAAuD;;;ACGhD,SAAS,WAAW,MAAyC;AAClE,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,gBAAgB,OAAO,OAAO,IAAI,KAAK,IAAI;AACrD,SAAO,EAAE,mBAAmB,CAAC,GAAG,EAAE,MAAM,WAAW,QAAQ,UAAU,CAAC;AACxE;AAKO,SAAS,oBAAoB,MAAyC;AAC3E,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,gBAAgB,OAAO,OAAO,IAAI,KAAK,IAAI;AACrD,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,QAAQ,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,GAAG,IAAI,QAAQ,CAAC;AACvE,QAAM,SAAS,IAAI,KAAK,EAAE,YAAY,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ,CAAC;AAClE,QAAM,SAAS,MAAM,QAAQ,IAAI,OAAO,QAAQ;AAChD,QAAM,WAAW,KAAK,MAAM,SAAS,KAAQ;AAC7C,QAAM,OAAO,EAAE,mBAAmB,CAAC,GAAG,EAAE,MAAM,WAAW,QAAQ,UAAU,CAAC;AAE5E,MAAI,aAAa,EAAG,QAAO,GAAG,IAAI;AAClC,MAAI,aAAa,EAAG,QAAO,GAAG,IAAI;AAClC,QAAM,KAAK,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACnD,QAAM,KAAK,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAC9C,QAAM,OAAO,EAAE,YAAY;AAC3B,SAAO,GAAG,IAAI,KAAK,EAAE,IAAI,EAAE,IAAI,IAAI;AACrC;AAKO,SAAS,WAAW,MAAyC;AAClE,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,gBAAgB,OAAO,OAAO,IAAI,KAAK,IAAI;AACrD,SAAO,GAAG,EAAE,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC;AAC1D;AAKO,SAAS,gBAAgB,MAAyC;AACvE,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,gBAAgB,OAAO,OAAO,IAAI,KAAK,IAAI;AACrD,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,QAAQ,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,GAAG,IAAI,QAAQ,CAAC;AACvE,QAAM,SAAS,IAAI,KAAK,EAAE,YAAY,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ,CAAC;AAClE,QAAM,SAAS,MAAM,QAAQ,IAAI,OAAO,QAAQ;AAChD,QAAM,WAAW,KAAK,MAAM,SAAS,KAAQ;AAE7C,MAAI,aAAa,EAAG,QAAO;AAC3B,MAAI,aAAa,EAAG,QAAO;AAC3B,SAAO,EAAE,mBAAmB,QAAW;AAAA,IACrC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,EACP,CAAC;AACH;AAKO,SAAS,iBAAiB,SAAwC;AACvE,SAAO,QAAQ,MAAM,MAAM,QAAQ,WAAW;AAChD;AAMO,SAAS,0BACd,MACA,SACA,SACA,eACQ;AACR,QAAM,iBAA4B,QAAgB,mBAAmB,CAAC;AACtE,QAAM,eAAyB,QAAgB,iBAAiB;AAGhE,MAAI,eAAe,WAAW,KAAK,CAAC,cAAc;AAChD,WAAO;AAAA,EACT;AAEA,QAAM,eAAqD,CAAC;AAE5D,aAAW,UAAU,gBAAgB;AACnC,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,QAAQ,MAAM,KAAK;AAChC,iBAAa,KAAK;AAAA,MAChB,SAAS,IAAI,MAAM;AAAA,MACnB,OAAO,gBAAgB,cAAc,QAAQ,IAAI,IAAI,IAAI,IAAI;AAAA,IAC/D,CAAC;AAAA,EACH;AAEA,MAAI,cAAc;AAChB,iBAAa,KAAK;AAAA,MAChB,SAAS;AAAA,MACT,OAAO,gBAAgB,cAAc,WAAW,KAAK,IAAI;AAAA,IAC3D,CAAC;AAAA,EACH;AAEA,MAAI,aAAa,WAAW,EAAG,QAAO;AAGtC,QAAM,UAAU,aAAa,IAAI,CAAC,MAAM,EAAE,QAAQ,QAAQ,uBAAuB,MAAM,CAAC;AACxF,QAAM,QAAQ,IAAI,OAAO,IAAI,QAAQ,KAAK,GAAG,CAAC,KAAK,GAAG;AAGtD,QAAM,iBAAiB,IAAI,IAAI,aAAa,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAE5E,SAAO,KAAK,QAAQ,OAAO,CAAC,UAAU,eAAe,IAAI,KAAK,KAAK,KAAK;AAC1E;AAMO,SAAS,aAAa,cAA2C;AACtE,QAAM,MAA8B,CAAC;AACrC,QAAM,UAAU,cAAc;AAC9B,MAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,eAAW,CAAC,IAAI,MAAM,KAAK,OAAO,QAAa,OAAO,GAAG;AACvD,UAAI,EAAE,IAAI,QAAQ,MAAM,QAAQ,QAAQ,WAAW;AAAA,IACrD;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,eAAe,IAAiB;AAC9C,QAAM,MAAM,OAAO,aAAa;AAChC,MAAI,CAAC,IAAK;AACV,QAAM,QAAQ,SAAS,YAAY;AACnC,QAAM,mBAAmB,EAAE;AAC3B,QAAM,SAAS,KAAK;AACpB,MAAI,gBAAgB;AACpB,MAAI,SAAS,KAAK;AACpB;AAKO,SAAS,mBAAmB,MAAY;AAC7C,QAAM,MAAM,OAAO,aAAa;AAChC,MAAI,CAAC,IAAK;AACV,QAAM,QAAQ,SAAS,YAAY;AACnC,QAAM,cAAc,IAAI;AACxB,QAAM,SAAS,IAAI;AACnB,MAAI,gBAAgB;AACpB,MAAI,SAAS,KAAK;AACpB;AAcA,IAAM,gBAAgB,oBAAI,IAAY;AACtC,IAAM,iBAAiB;AAEhB,SAAS,aAAa,KAAmB;AAC9C,MAAI,CAAC,OAAO,cAAc,IAAI,GAAG,EAAG;AAEpC,MAAI,cAAc,QAAQ,gBAAgB;AACxC,UAAM,QAAQ,cAAc,OAAO,EAAE,KAAK,EAAE;AAC5C,QAAI,MAAO,eAAc,OAAO,KAAK;AAAA,EACvC;AAEA,QAAM,MAAM,IAAI,MAAM;AACtB,MAAI,MAAM;AACV,gBAAc,IAAI,GAAG;AACvB;AAEO,SAAS,iBAAiB,KAAsB;AACrD,SAAO,cAAc,IAAI,GAAG;AAC9B;AAKO,SAAS,eAAe,OAAuB;AACpD,MAAI,UAAU,EAAG,QAAO;AACxB,QAAM,IAAI;AACV,QAAM,QAAQ,CAAC,KAAK,MAAM,MAAM,IAAI;AACpC,QAAM,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AAClD,SAAO,GAAG,YAAY,QAAQ,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AACvE;AAMO,SAAS,mBAAmB,SAAyB;AAC1D,QAAM,OAAO,IAAI,KAAK,OAAO;AAC7B,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,SAAS,IAAI,QAAQ,IAAI,KAAK,QAAQ;AAC5C,QAAM,WAAW,KAAK,MAAM,UAAU,MAAO,KAAK,KAAK,GAAG;AAE1D,MAAI,aAAa,EAAG,QAAO;AAC3B,MAAI,aAAa,EAAG,QAAO;AAC3B,MAAI,WAAW,EAAG,QAAO,GAAG,QAAQ;AAEpC,SAAO,KAAK,mBAAmB,SAAS,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,KAAK,YAAY,MAAM,IAAI,YAAY,IAAI,YAAY,OAAU,CAAC;AACpJ;AAMO,SAAS,eAAe,UAA0B;AACvD,QAAM,QAAQ,SAAS,MAAM,GAAG;AAChC,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,MAAM,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AACzC,WAAO,QAAQ,GAAG;AAAA,EACpB;AACA,SAAO;AACT;AAKO,SAAS,cAAc,KAAqB;AACjD,MAAI;AACF,WAAO,IAAI,IAAI,GAAG,EAAE;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ADnHM,IAAAC,sBAAA;AA5GN,SAAS,sBACP,SACA,UACgC;AAChC,QAAM,UAAU,QAAQ,OAAO,gBAAgB,MAAM,EAAE,EAAE,CAAC;AAC1D,MAAI,CAAC,QAAS,QAAO,EAAE,MAAM,IAAI,MAAM,GAAG;AAE1C,QAAM,UAAU,QAAQ,QAAQ;AAChC,QAAM,UAAU,QAAQ,QAAQ;AAEhC,MAAI,YAAY,UAAU;AACxB,UAAM,UAAU,aAAa,QAAQ,KAAK;AAC1C,WAAO,EAAE,UAAM,2CAAmB,SAAS,OAAO,GAAG,MAAM,GAAG;AAAA,EAChE;AAEA,MAAI,YAAY,UAAU;AACxB,UAAM,aAAS,2CAAmB,SAAS,YAAY,EAAE;AACzD,WAAO,EAAE,MAAM,QAAQ,QAAQ,SAAS,MAAM,GAAG;AAAA,EACnD;AAGA,MAAI,YAAY,aAAc,QAAoC,aAAa;AAC7E,WAAO,EAAE,MAAM,WAAW,MAAM,QAAQ,MAAM,QAAQ,QAAQ,WAAW,GAAG;AAAA,EAC9E;AAGA,MAAI,cAAc;AAClB,MAAI,CAAC,eAAe,QAAQ,eAAe,QAAQ,YAAY,SAAS,GAAG;AACzE,UAAM,MAAM,QAAQ,YAAY,CAAC;AACjC,UAAM,OAAO,IAAI,QAAQ;AACzB,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,sBAAc;AACd;AAAA,MACF,KAAK;AACH,sBAAc;AACd;AAAA,MACF,KAAK;AACH,sBAAc;AACd;AAAA,MACF;AACE,sBAAc;AACd;AAAA,IACJ;AACA,QAAI,QAAQ,YAAY,SAAS,GAAG;AAClC,qBAAe,KAAK,QAAQ,YAAY,SAAS,CAAC;AAAA,IACpD;AAAA,EACF;AAGA,QAAM,gBAAgB;AACtB,QAAM,iBAAiB,cAAc;AACrC,QAAM,eAAe,cAAc;AAEnC,MAAI,gBAAgB,gBAAiB,kBAAkB,eAAe,SAAS,IAAK;AAClF,UAAM,UAAU,aAAa,QAAQ,KAAK;AAC1C,kBAAc,0BAA0B,aAAa,SAAgB,OAAO;AAAA,EAC9E;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,QAAQ,MAAM,QAAQ,QAAQ,WAAW;AAAA,EACjD;AACF;AAKO,IAAM,cAA0C,eAAAC,QAAM,KAAK,CAAC;AAAA,EACjE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AAGJ,QAAM,CAAC,EAAE,WAAW,QAAI,yBAAS,CAAC;AAClC,gCAAU,MAAM;AACd,UAAM,MAAM,QAAQ,GAAG,mBAAmB,MAAM,YAAY,CAAC,MAAM,IAAI,CAAC,CAAC;AACzE,WAAO,MAAM,IAAI,YAAY;AAAA,EAC/B,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,OAAO,QAAQ,MAAM,QAAQ,QAAQ;AAC3C,QAAM,QAAQ,QAAQ,MAAM;AAC5B,QAAM,aAAa,aAAa,CAAC;AAEjC,QAAM,kBAAc,4BAAY,MAAM;AACpC,aAAS,OAAO;AAAA,EAClB,GAAG,CAAC,SAAS,QAAQ,CAAC;AAEtB,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,WAAW,qCAAqC;AAAA,IAChD,aAAa,qCAAqC;AAAA,IAClD,YAAY,sCAAsC;AAAA,IAClD,YAAY,sCAAsC;AAAA,EACpD,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAE1B,SACE,8CAAC,SAAI,WAAW,WAAW,SAAS,aAClC;AAAA,iDAAC,mBAAgB,OAAc,MAAY,MAAM,IAAI;AAAA,IACrD,8CAAC,SAAI,WAAU,oCACb;AAAA,mDAAC,SAAI,WAAU,iCAAiC,gBAAK;AAAA,MACpD,mBACC,8CAAC,SAAI,WAAU,yCACZ;AAAA,2BACC,8CAAC,UAAK,WAAU,8CACb;AAAA;AAAA,UAAgB;AAAA,UAAE;AAAA,WACrB;AAAA,QAEF,6CAAC,UAAM,2BAAgB;AAAA,SACzB;AAAA,OAEJ;AAAA,IACC,cAAc,cAAc,KAC3B,6CAAC,UAAK,WAAU,oCACb,wBAAc,KAAK,QAAQ,aAC9B;AAAA,IAED,aACC,6CAAC,UAAK,WAAU,oCAAmC,OAAO,qBAAqB,WAC7E,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,mDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,MAC/B,6CAAC,UAAK,IAAG,QAAO,IAAG,QAAO,IAAG,SAAQ,IAAG,SAAQ;AAAA,OAClD,GACF;AAAA,IAED,aACC,6CAAC,UAAK,WAAU,qCAAqC,+BAAqB,WAAU;AAAA,KAExF;AAEJ,CAAC;AACD,YAAY,cAAc;AAE1B,IAAM,iBAAiB,eAAAA,QAAM,KAAK,CAAC,EAAE,KAAK,MACxC,6CAAC,SAAI,WAAU,+BAA+B,kBAAQ,uBAAsB,CAC7E;AACD,eAAe,cAAc;AAE7B,IAAM,eAAe,eAAAA,QAAM,KAAK,CAAC,EAAE,KAAK,MACtC,6CAAC,SAAI,WAAU,6BAA6B,kBAAQ,qBAAoB,CACzE;AACD,aAAa,cAAc;AAiB3B,IAAM,aAAwC,eAAAA,QAAM,KAAK,CAAC;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AAEJ,QAAM,EAAE,mBAAmB,oBAAoB,YAAY,IAAI,qBAAqB,SAAS,aAAa;AAC1G,QAAM,EAAE,UAAU,IAAI,gBAAgB,SAAS,aAAa;AAE5D,QAAM,eAAe,QAAQ;AAC7B,QAAM,iBAAkB,cAAc,eAA0B;AAChE,QAAM,cAAe,qBAAqB,sBAAsB,YAAa,IAAI;AACjF,QAAM,YAAY,cAAc;AAIhC,QAAM,EAAE,MAAM,oBAAoB,MAAM,mBAAmB,QAAI;AAAA,IAC7D,MAAM,sBAAsB,SAAS,aAAa;AAAA;AAAA;AAAA,IAGlD,CAAC,SAAS,QAAQ,OAAO,gBAAgB,WAAW;AAAA,EACtD;AAGA,QAAM,kBAAmB,qBAAqB,sBAAsB,YAAa,KAAK;AACtF,QAAM,kBAAmB,qBAAqB,sBAAsB,YAAa,KAAK;AAEtF,MAAI,eAAe;AACjB,WACE,6CAAC,SAAI,SAAS,MAAM,aAAa,OAAO,GACrC,wBAAc,SAAS,QAAQ,GAClC;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ,CAAC;AACD,WAAW,cAAc;AAElB,IAAM,cAA0C,eAAAA,QAAM,KAAK,CAAC;AAAA,EACjE,UAAU,EAAE,MAAM,CAAC,aAAa,QAAQ,SAAS,GAAG,yBAAyB,KAAK;AAAA,EAClF,OAAO,CAAC;AAAA,EACR,UAAU,EAAE,eAAe,GAAG;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,kBAAkB;AAAA,EAClB,uBAAuB;AAAA,EACvB;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,oBAAoB;AACtB,MAAM;AACJ,QAAM,EAAE,QAAQ,eAAe,iBAAiB,IAAI,cAAc;AAClE,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAoB,CAAC,CAAC;AACtD,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,IAAI;AAC3C,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,yBAAS,IAAI;AAG/D,QAAM,EAAE,iBAAiB,gBAAgB,QAAI,wBAAoE,MAAM;AACrH,UAAM,UAAqB,CAAC;AAC5B,UAAM,UAAqB,CAAC;AAE5B,aAAS,QAAQ,QAAM;AACrB,YAAM,KAAK,GAAG,OAAO;AACrB,YAAM,YAAY,IAAI,iBAAiB,aAAa,IAAI,SAAS;AACjE,UAAI,WAAW;AACb,gBAAQ,KAAK,EAAE;AAAA,MACjB,OAAO;AACL,gBAAQ,KAAK,EAAE;AAAA,MACjB;AAAA,IACF,CAAC;AAED,WAAO,EAAE,iBAAiB,SAAS,iBAAiB,QAAQ;AAAA,EAC9D,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,iBAAa,wBAAQ,MAAM,KAAK,UAAU,OAAO,GAAG,CAAC,OAAO,CAAC;AAEnE,QAAM,mBAAe,4BAAY,YAAY;AAC3C,QAAI;AACF,iBAAW,IAAI;AACf,YAAM,SAAS,MAAM,OAAO,cAAc,SAAS,MAAM,OAAqC;AAC9F,kBAAY,MAAM;AAAA,IACpB,SAAS,KAAK;AACZ,cAAQ,MAAM,4BAA4B,GAAG;AAAA,IAC/C,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,QAAQ,UAAU,CAAC;AAEvB,gCAAU,MAAM;AACd,iBAAa;AAAA,EACf,GAAG,CAAC,YAAY,CAAC;AAGjB,wBAAsB,UAAU,WAAW;AAE3C,QAAM,mBAAe;AAAA,IACnB,CAAC,YAAqB;AACpB,uBAAiB,OAAO;AACxB,wBAAkB,OAAO;AAGzB,YAAM,KAAK,QAAQ,OAAO;AAC1B,YAAM,UAAU,QAAQ;AACxB,YAAM,oBAAoB,QAAQ,IAAI,MAAM;AAC5C,YAAM,qBAAqB,QAAQ,SAAS,eAAe,QAAQ,IAAI,OAAO;AAC9E,YAAM,YAAY,IAAI,iBAAiB,aAAa,IAAI,SAAS;AAEjE,UAAI,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,aAAc,SAAS,cAAyB,GAAG;AACnG,gBAAQ,SAAS,EAAE,MAAM,MAAM;AAAA,QAAE,CAAC;AAElC,YAAI,QAAS,SAAQ,cAAc;AACnC,oBAAY,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;AAAA,MACjC;AAAA,IACF;AAAA,IACA,CAAC,kBAAkB,iBAAiB,WAAW;AAAA,EACjD;AAEA,MAAI,QAAS,QAAO,6CAAC,oBAAiB,MAAM,cAAc;AAC1D,MAAI,SAAS,WAAW,EAAG,QAAO,6CAAC,uBAAoB,MAAM,iBAAiB;AAE9E,SACE,6CAAC,SAAI,WAAW,qBAAqB,YAAY,IAAI,SAAS,KAAK,EAAE,IAEnE,wDAAC,uBAAM,OAAO,EAAE,QAAQ,OAAO,GAC5B;AAAA,oBAAgB,SAAS,KACxB;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS,MAAM,qBAAqB,UAAQ,CAAC,IAAI;AAAA,QAEjD;AAAA,uDAAC,UACE,iBAAO,wBAAwB,aAC5B,oBAAoB,gBAAgB,MAAM,IAC1C,uBAAuB,YAAY,gBAAgB,MAAM,KAC/D;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,sCAAsC,oBAAoB,iDAAiD,EAAE;AAAA,cACxH,OAAM;AAAA,cAAK,QAAO;AAAA,cAAK,SAAQ;AAAA,cAAY,MAAK;AAAA,cAAO,QAAO;AAAA,cAAe,aAAY;AAAA,cAAI,eAAc;AAAA,cAAQ,gBAAe;AAAA,cAElI,uDAAC,cAAS,QAAO,kBAAiB;AAAA;AAAA,UACpC;AAAA;AAAA;AAAA,IACF;AAAA,IAED,qBAAqB,gBAAgB,IAAI,CAAC,YAAqB;AAC9D,YAAM,WAAW,eAAe,QAAQ,QAAQ;AAChD,aACE;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,eAAe,OAAO;AAAA,UACtB;AAAA,UACA;AAAA;AAAA,QATK,QAAQ;AAAA,MAUf;AAAA,IAEJ,CAAC;AAAA,IACA,gBAAgB,SAAS,KAAK,gBAAgB,SAAS,KACtD,6CAAC,SAAI,WAAU,qFACb,uDAAC,UAAM,yBAAc,GACvB;AAAA,IAED,gBAAgB,IAAI,CAAC,YAAqB;AACzC,YAAM,WAAW,eAAe,QAAQ,QAAQ;AAEhD,aACE;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,eAAe,OAAO;AAAA,UACtB;AAAA,UACA;AAAA;AAAA,QATK,QAAQ;AAAA,MAUf;AAAA,IAEJ,CAAC;AAAA,KACH,GACF;AAEJ,CAAC;AAED,YAAY,cAAc;;;AEhZ1B,IAAAC,iBAAoD;;;ACApD,IAAAC,iBAAyE;AACzE,IAAAC,yBAA4C;AA0BxC,IAAAC,sBAAA;AAdJ,IAAM,4BAA+D,eAAAC,QAAM,KAAK,CAAC;AAAA,EAC/E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,OAAQ,QAAQ,MAAM,QAAQ,QAAQ;AAC5C,QAAM,WAAW,QAAQ,MAAM;AAE/B,QAAM,UAAU,UAAU,WAAW,UAAU;AAC/C,QAAM,QAAQ,UAAU,SAAY;AACpC,QAAM,YAAY,UAAU,SAAU,QAAQ,YAAY,EAAE,IAAI;AAEhE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,qCAAqC,WAAW,gDAAgD,EAAE;AAAA,MAC7G,SAAS,MAAM,SAAS,OAAO;AAAA,MAE9B;AAAA,oBACC,6CAAC,UAAK,WAAU,sCAAqC,OAAO,EAAE,UAAU,IAAI,OAAO,IAAI,WAAW,SAAS,GAAI,qBAAU,IAEzH,6CAAC,mBAAgB,OAAc,MAAY,MAAM,IAAI;AAAA,QAEvD,6CAAC,UAAK,WAAU,qCAAqC,gBAAK;AAAA,QAC1D,6CAAC,SAAI,WAAW,iCAAiC,WAAW,2CAA2C,EAAE,IACtG,sBACC,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,uDAAC,cAAS,QAAO,kBAAiB,GACpC,GAEJ;AAAA;AAAA;AAAA,EACF;AAEJ,CAAC;AACD,0BAA0B,cAAc;AAKjC,IAAM,sBAA0D,CAAC;AAAA,EACtE;AAAA,EACA;AAAA,EACA,uBAAuB;AAAA,EACvB;AACF,MAAM;AACJ,QAAM,EAAE,QAAQ,cAAc,IAAI,cAAc;AAChD,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,yBAAsB,oBAAI,IAAI,CAAC;AAC/E,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,EAAE;AACvC,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,KAAK;AAC5C,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAyD,IAAI;AAC3F,QAAM,kBAAc,uBAAuB,IAAI;AAG/C,QAAM,eAAW,wBAAQ,MAAM;AAC7B,WAAQ,OAAO,OAAO,OAAO,cAAc,EAAgB;AAAA,MACzD,CAAC,OAAO,GAAG,SAAS;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,OAAO,cAAc,CAAC;AAG1B,QAAM,uBAAmB,wBAAQ,MAAM;AACrC,QAAI,CAAC,OAAO,KAAK,EAAG,QAAO;AAC3B,UAAM,IAAI,OAAO,YAAY;AAC7B,WAAO,SAAS,OAAO,CAAC,OAAO;AAC7B,YAAM,QAAS,GAAG,MAAM,QAAQ,GAAG,KAAgB,YAAY;AAC/D,aAAO,KAAK,SAAS,CAAC;AAAA,IACxB,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,MAAM,CAAC;AAGrB,QAAM,oBAAgB,4BAAY,CAAC,YAAqB;AACtD,wBAAoB,CAAC,SAAS;AAC5B,YAAM,OAAO,IAAI,IAAI,IAAI;AACzB,UAAI,KAAK,IAAI,QAAQ,GAAG,GAAG;AACzB,aAAK,OAAO,QAAQ,GAAG;AAAA,MACzB,OAAO;AACL,aAAK,IAAI,QAAQ,GAAG;AAAA,MACtB;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAGL,QAAM,iBAAa,4BAAY,YAAY;AACzC,QAAI,CAAC,iBAAiB,iBAAiB,SAAS,KAAK,QAAS;AAC9D,eAAW,IAAI;AACf,UAAM,UAAoB,CAAC;AAC3B,UAAM,SAAmB,CAAC;AAE1B,eAAW,OAAO,kBAAkB;AAClC,YAAM,gBAAgB,SAAS,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG;AACxD,UAAI,CAAC,cAAe;AACpB,UAAI;AACF,cAAM,qBAAiB;AAAA,UACrB;AAAA,UACA,cAAc;AAAA,UACd,cAAc;AAAA,QAChB;AAEA,cAAM,cAAc,eAAe,gBAAgB;AAAA,UACjD,MAAM,cAAc;AAAA,UACpB,WAAW,cAAc;AAAA,QAC3B,CAAC;AACD,gBAAQ,KAAM,cAAc,MAAM,QAAQ,cAAc,GAAc;AAAA,MACxE,SAAS,KAAK;AACZ,gBAAQ,MAAM,wBAAwB,GAAG,IAAI,GAAG;AAChD,eAAO,KAAM,cAAc,MAAM,QAAQ,cAAc,GAAc;AAAA,MACvE;AAAA,IACF;AAEA,eAAW,EAAE,SAAS,OAAO,CAAC;AAC9B,eAAW,KAAK;AAGhB,QAAI,OAAO,WAAW,GAAG;AACvB,iBAAW,MAAM,UAAU,GAAG,IAAI;AAAA,IACpC;AAAA,EACF,GAAG,CAAC,eAAe,kBAAkB,UAAU,SAAS,SAAS,SAAS,CAAC;AAG3E,gCAAU,MAAM;AACd,UAAM,YAAY,CAAC,MAAqB;AACtC,UAAI,EAAE,QAAQ,SAAU,WAAU;AAAA,IACpC;AACA,aAAS,iBAAiB,WAAW,SAAS;AAC9C,WAAO,MAAM,SAAS,oBAAoB,WAAW,SAAS;AAAA,EAChE,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,0BAAsB,4BAAY,CAAC,MAAwB;AAC/D,QAAI,EAAE,WAAW,YAAY,QAAS,WAAU;AAAA,EAClD,GAAG,CAAC,SAAS,CAAC;AAGd,QAAM,cAAc,QAAQ,OACvB,QAAQ,KAAK,SAAS,MAAM,QAAQ,KAAK,MAAM,GAAG,GAAG,IAAI,WAAM,QAAQ,OACxE;AACJ,QAAM,kBAAkB,QAAQ,aAAa,UAAU;AAEvD,QAAM,SACJ,8EACE;AAAA,iDAAC,YAAO,WAAU,6DAA4D,SAAS,WAAW,oBAElG;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU,iBAAiB,SAAS,KAAK,WAAW,YAAY;AAAA,QAE/D,oBAAU,kBAAa,UAAU,iBAAiB,OAAO,IAAI,KAAK,iBAAiB,IAAI,MAAM,EAAE;AAAA;AAAA,IAClG;AAAA,KACF;AAGF,SACE,8CAAC,SAAM,QAAM,MAAC,SAAS,WAAW,OAAM,mBAAkB,QAExD;AAAA,kDAAC,SAAI,WAAU,gCACb;AAAA,mDAAC,SAAI,WAAU,uCACZ,kBAAQ,MAAM,QAAQ,QAAQ,WAAW,WAC5C;AAAA,MACC,eACC,6CAAC,SAAI,WAAU,qCAAqC,uBAAY;AAAA,MAEjE,kBAAkB,KACjB,8CAAC,SAAI,WAAU,4CAA2C;AAAA;AAAA,QACpD;AAAA,QAAgB;AAAA,QAAY,kBAAkB,IAAI,MAAM;AAAA,SAC9D;AAAA,OAEJ;AAAA,IAGA,6CAAC,SAAI,WAAU,uCACZ,iCACC,6CAAC,wBAAqB,OAAO,QAAQ,UAAU,WAAW,IAE1D;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,MAAK;AAAA,QACL,aAAY;AAAA,QACZ,OAAO;AAAA,QACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,QACzC,WAAS;AAAA;AAAA,IACX,GAEJ;AAAA,IAGA,6CAAC,SAAI,WAAU,qCACZ,2BAAiB,WAAW,IAC3B,6CAAC,SAAI,WAAU,8BAA6B,+BAAiB,IAE7D,iBAAiB,IAAI,CAAC,OACpB;AAAA,MAAC;AAAA;AAAA,QAEC,SAAS;AAAA,QACT,UAAU,iBAAiB,IAAI,GAAG,GAAG;AAAA,QACrC,UAAU;AAAA,QACV,iBAAiB;AAAA;AAAA,MAJZ,GAAG;AAAA,IAKV,CACD,GAEL;AAAA,IAGC,WACC,8CAAC,SAAI,WAAU,gCACZ;AAAA,cAAQ,QAAQ,SAAS,KACxB,8CAAC,SAAI,WAAU,wCAAuC;AAAA;AAAA,QACzC,QAAQ,QAAQ,KAAK,IAAI;AAAA,SACtC;AAAA,MAED,QAAQ,OAAO,SAAS,KACvB,8CAAC,SAAI,WAAU,uCAAsC;AAAA;AAAA,QACxC,QAAQ,OAAO,KAAK,IAAI;AAAA,SACrC;AAAA,OAEJ;AAAA,KAEJ;AAEJ;;;AD/NE,IAAAC,sBAAA;AADF,IAAMC,gBAAe,eAAAC,QAAM,KAAK,MAC9B,6CAAC,SAAI,WAAU,wBAAuB,gDAAkC,CACzE;AACDD,cAAa,cAAc;AAUpB,IAAM,UAAkC,eAAAC,QAAM,KAAK,CAAC;AAAA,EACzD;AAAA,EACA;AAAA,EACA,sBAAsBD;AAAA,EACtB;AAAA,EACA,+BAA+B;AACjC,MAAM;AACJ,QAAM,EAAE,eAAe,QAAQ,mBAAmB,qBAAqB,IAAI,cAAc;AACzF,QAAM,EAAE,SAAS,IAAI,eAAe,eAAe,OAAO,MAAM;AAChE,QAAM,EAAE,UAAU,IAAI,gBAAgB,eAAe,OAAO,MAAM;AAGlE,QAAM,CAAC,oBAAoB,qBAAqB,QAAI,yBAAS,CAAC;AAC9D,gCAAU,MAAM;AAEd,YAAQ,IAAI,sBAAsB,aAAa;AAE/C,QAAI,CAAC,cAAe;AACpB,UAAM,MAAM,cAAc,GAAG,mBAAmB,MAAM,sBAAsB,CAAC,MAAM,IAAI,CAAC,CAAC;AACzF,WAAO,MAAM,IAAI,YAAY;AAAA,EAC/B,GAAG,CAAC,aAAa,CAAC;AAGlB,QAAM,iBAAa,wBAAQ,MAAM;AAC/B,QAAI,CAAC,iBAAiB,CAAC,gBAAiB,QAAO;AAC/C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAO,cAAc,MAAM,QAAQ,cAAc,OAAO;AAAA,MACxD,OAAO,cAAc,MAAM;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,eAAe,iBAAiB,kBAAkB,CAAC;AAEvD,MAAI,CAAC,eAAe;AAClB,WAAO,6CAAC,uBAAoB;AAAA,EAC9B;AAEA,QAAM,cAAc,WAAW,2BAA2B;AAC1D,QAAM,eAAe,YAAY,4BAA4B;AAE7D,SACE,8CAAC,SAAI,WAAW,gBAAgB,WAAW,GAAG,YAAY,GAAG,YAAY,IAAI,SAAS,KAAK,EAAE,IAC1F;AAAA,uBAAmB,cAAc,6CAAC,mBAAiB,GAAG,YAAY;AAAA,IAClE;AAAA,IACA,qBACC;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAW,MAAM,qBAAqB,IAAI;AAAA;AAAA,IAC5C;AAAA,KAEJ;AAEJ,CAAC;AAED,QAAQ,cAAc;;;AE3EtB,IAAAE,iBAAgE;AAkE1D,IAAAC,sBAAA;AA7CC,IAAM,gBAA8C,eAAAC,QAAM,KAAK,CAAC;AAAA,EACrE;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB;AACF,MAAM;AACJ,QAAM,EAAE,eAAe,QAAQ,WAAW,IAAI,cAAc;AAC5D,QAAM,EAAE,UAAU,IAAI,gBAAgB,eAAe,OAAO,MAAM;AAClE,QAAM,kBAAc,2BAAW,gBAAgB;AAE/C,QAAM,iBAAiB;AAGvB,QAAM,CAAC,oBAAoB,qBAAqB,QAAI,yBAAS,CAAC;AAE9D,gCAAU,MAAM;AACd,QAAI,CAAC,cAAe;AACpB,UAAM,MAAM,cAAc,GAAG,mBAAmB,MAAM,sBAAsB,OAAK,IAAI,CAAC,CAAC;AACvF,WAAO,MAAM,IAAI,YAAY;AAAA,EAC/B,GAAG,CAAC,aAAa,CAAC;AAGlB,QAAM,kBAAc;AAAA,IAAQ,MAC1B,SAAS,eAAe,MAAM,QAAQ,eAAe,OAAO;AAAA,IAC5D,CAAC,OAAO,eAAe,MAAM,MAAM,eAAe,KAAK,kBAAkB;AAAA,EAC3E;AAGA,QAAM,mBAAe;AAAA,IAAQ,MAC3B,SAAU,eAAe,MAAM;AAAA,IAC/B,CAAC,OAAO,eAAe,MAAM,OAAO,kBAAkB;AAAA,EACxD;AAEA,MAAI,CAAC,cAAe,QAAO;AAE3B,SACE,8CAAC,SAAI,WAAW,uBAAuB,YAAY,IAAI,SAAS,KAAK,EAAE,IACrE;AAAA,iDAAC,mBAAgB,OAAO,cAAc,MAAM,aAAa,MAAM,IAAI;AAAA,IAEnE,8CAAC,SAAI,WAAU,8BACZ;AAAA,oBACC,YAAY,aAAa,IAEzB,6CAAC,SAAI,WAAU,8BAA8B,uBAAY;AAAA,MAE1D,YACC,6CAAC,SAAI,WAAU,kCAAkC,oBAAS;AAAA,OAE9D;AAAA,IAGA,8CAAC,SAAI,WAAU,iCACZ;AAAA,oBAAc,eAAe,eAAe,SAAS,eAAe,CAAC,aACpE,8EACG;AAAA,gCACC,sBAAsB,MAAM,YAAY,WAAW,SAAS,cAAc,OAAO,EAAE,GAAG,cAAc,IAEpG;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,UAAU;AAAA,YACV,SAAS,MAAM,YAAY,WAAW,SAAS,cAAc,OAAO,EAAE;AAAA,YACtE,OAAO;AAAA,YAEP,uDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,uDAAC,UAAK,GAAE,iSAAgS,GAC1S;AAAA;AAAA,QACF;AAAA,QAGD,wBACC,sBAAsB,MAAM,YAAY,WAAW,SAAS,cAAc,OAAO,EAAE,GAAG,cAAc,IAEpG;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,UAAU;AAAA,YACV,SAAS,MAAM,YAAY,WAAW,SAAS,cAAc,OAAO,EAAE;AAAA,YACtE,OAAO;AAAA,YAEP,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,2DAAC,aAAQ,QAAO,yBAAwB;AAAA,cACxC,6CAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,eACzD;AAAA;AAAA,QACF;AAAA,SAEJ;AAAA,MAGD,cAAc,eAAe,YAAY,cAAc,sBACtD,6CAAC,sBAAmB,UAAU,YAAY,UAAU;AAAA,MAErD,eAAe,YAAY,eAAe,cAAc;AAAA,OAC3D;AAAA,KACF;AAEJ,CAAC;AAED,cAAc,cAAc;;;AC7H5B,IAAAC,iBAAyE;AACzE,IAAAC,iBAAwC;;;ACDxC,IAAAC,iBAAyD;AAEzD,IAAAC,yBAA8B;AAI9B,IAAM,sBAAsB;AAGrB,IAAM,gBAAgB,CAAC,UAAiB,aAAqB;AAClE,QAAM,MAAM,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;AACpD,SAAO,SAAS,OAAO,CAAC,MAAW;AACjC,QAAI,CAAC,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE,EAAG,QAAO;AACnC,QAAI,IAAI,EAAE,EAAE;AACZ,WAAO;AAAA,EACT,CAAC;AACH;AA2BO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAClB,GAAkD;AAChD,QAAM,EAAE,eAAe,YAAY,IAAI,cAAc;AACrD,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,IAAI;AAC3C,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,KAAK;AAC9C,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAS,KAAK;AAGhD,gCAAU,MAAM;AACd,QAAI,WAAW;AACb,4BAAsB,MAAM,aAAa,KAAK,CAAC;AAAA,IACjD;AAAA,EACF,GAAG,CAAC,SAAS,CAAC;AAGd,QAAM,iBAAa,uBAAO,IAAI;AAC9B,aAAW,UAAU;AACrB,QAAM,kBAAc,uBAAO,KAAK;AAChC,cAAY,UAAU;AACtB,QAAM,oBAAgB,uBAAO,IAAI;AAGjC,QAAM,qBAAiB,uBAAO,KAAK;AACnC,QAAM,sBAAkB,uBAAO,KAAK;AAEpC,QAAM,eAAW,4BAAY,YAAY;AACvC,QAAI,CAAC,iBAAiB,eAAe,QAAS;AAE9C,UAAM,kBAAkB,YAAY;AACpC,UAAM,gBAAgB,gBAAgB,CAAC;AACvC,QAAI,CAAC,eAAe,GAAI;AAExB,mBAAe,UAAU;AACzB,QAAI;AACF,YAAM,WAAW,MAAM,cAAc,wBAAwB,cAAc,IAAI,aAAa;AAE5F,UAAI,SAAS,WAAW,GAAG;AACzB,mBAAW,KAAK;AAChB;AAAA,MACF;AAEA,YAAM,iBAAiB,SAAS,IAAI,CAAC,YAAa,sCAAc,GAAG,CAAC;AACpE,mBAAa,IAAI;AACjB,kBAAY,CAAC,SAAS;AACpB,cAAM,SAAS,cAAc,gBAAgB,IAAI;AACjD,YAAI,OAAO,WAAW,GAAG;AACvB,qBAAW,KAAK;AAAA,QAClB;AACA,eAAO,CAAC,GAAG,QAAQ,GAAG,IAAI;AAAA,MAC5B,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,iCAAiC,GAAG;AAAA,IACpD,UAAE;AACA,qBAAe,UAAU;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,eAAe,eAAe,WAAW,CAAC;AAE9C,QAAM,gBAAY,4BAAY,YAAY;AACxC,QAAI,CAAC,iBAAiB,gBAAgB,QAAS;AAE/C,UAAM,kBAAkB,YAAY;AACpC,UAAM,gBAAgB,gBAAgB,gBAAgB,SAAS,CAAC;AAChE,QAAI,CAAC,eAAe,GAAI;AAExB,oBAAgB,UAAU;AAC1B,QAAI;AACF,YAAM,WAAW,MAAM,cAAc,2BAA2B,cAAc,IAAI,aAAa;AAE/F,UAAI,SAAS,WAAW,GAAG;AACzB,oBAAY,KAAK;AACjB;AAAA,MACF;AAEA,YAAM,iBAAiB,SAAS,IAAI,CAAC,YAAa,sCAAc,GAAG,CAAC;AACpE,kBAAY,CAAC,SAAS;AACpB,cAAM,SAAS,cAAc,gBAAgB,IAAI;AACjD,YAAI,OAAO,WAAW,GAAG;AACvB,sBAAY,KAAK;AAAA,QACnB;AACA,eAAO,CAAC,GAAG,MAAM,GAAG,MAAM;AAAA,MAC5B,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,kCAAkC,GAAG;AAAA,IACrD,UAAE;AACA,sBAAgB,UAAU;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,eAAe,eAAe,WAAW,CAAC;AAE9C,QAAM,mBAAe;AAAA,IACnB,CAAC,WAAmB;AAClB,UAAI,WAAW,QAAS;AACxB,YAAM,SAAS,SAAS;AACxB,UAAI,CAAC,OAAQ;AACb,YAAM,EAAE,YAAY,aAAa,IAAI;AAErC,YAAM,WAAW,KAAK,KAAK,SAAS,YAAY,KAAK,aAAa;AAClE,oBAAc,UAAU;AAGxB,UAAI,cAAc,cAAc;AAC9B,sBAAc,UAAU;AACxB;AAAA,MACF;AAEA,UAAI,UAAU,uBAAuB,WAAW,SAAS;AACvD,iBAAS;AAAA,MACX;AAEA,UAAI,SAAS,gBAAgB,aAAa,uBAAuB,YAAY,SAAS;AACpF,kBAAU;AAAA,MACZ;AAAA,IACF;AAAA,IACA,CAAC,UAAU,SAAS;AAAA,EACtB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACjLA,IAAAC,iBAAyD;AAEzD,IAAAC,yBAA8B;AAuBvB,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwD;AACtD,QAAM,EAAE,eAAe,YAAY,IAAI,cAAc;AACrD,QAAM,CAAC,eAAe,gBAAgB,QAAI,yBAAwB,IAAI;AACtE,QAAM,wBAAoB,uBAA6C,IAAI;AAG3E,gCAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,kBAAkB,QAAS,cAAa,kBAAkB,OAAO;AAAA,IACvE;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAY,4BAAY,CAAC,cAAsB;AACnD,QAAI,kBAAkB,QAAS,cAAa,kBAAkB,OAAO;AACrE,qBAAiB,SAAS;AAC1B,sBAAkB,UAAU,WAAW,MAAM;AAC3C,uBAAiB,IAAI;AACrB,wBAAkB,UAAU;AAAA,IAC9B,GAAG,IAAI;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,sBAAkB;AAAA,IACtB,OAAO,cAAsB;AAE3B,UAAI,WAAW,QAAS;AAGxB,YAAM,MAAM,YAAY,QAAQ,UAAU,CAAC,MAAM,EAAE,OAAO,SAAS;AACnE,UAAI,QAAQ,IAAI;AACd,iBAAS,SAAS,cAAc,KAAK,EAAE,OAAO,UAAU,QAAQ,KAAK,CAAC;AACtE,kBAAU,SAAS;AACnB;AAAA,MACF;AAGA,UAAI,CAAC,cAAe;AAEpB,iBAAW,UAAU;AAErB,YAAM,UAAU,gBAAgB;AAChC,UAAI,SAAS;AACX,gBAAQ,MAAM,aAAa;AAC3B,gBAAQ,MAAM,UAAU;AAAA,MAC1B;AAEA,UAAI;AACF,cAAM,cAAc,MAAM,cAAc,sBAAsB,WAAW,EAAE;AAC3E,YAAI,CAAC,eAAe,YAAY,WAAW,GAAG;AAC5C,qBAAW,UAAU;AACrB,cAAI,QAAS,SAAQ,MAAM,UAAU;AACrC;AAAA,QACF;AAEA,cAAM,YAAY,YAAY,IAAI,CAAC,YAAa,sCAAc,GAAG,CAAC;AAClE,cAAM,SAAS,cAAc,SAAS;AAEtC,mBAAW,IAAI;AACf,oBAAY,IAAI;AAChB,oBAAY,MAAM;AAGlB,mBAAW,MAAM;AACf,gBAAM,SAAS,OAAO,UAAU,CAAC,MAAW,EAAE,OAAO,SAAS;AAC9D,cAAI,WAAW,IAAI;AACjB,uBAAW,UAAU;AACrB,gBAAI,QAAS,SAAQ,MAAM,UAAU;AACrC;AAAA,UACF;AAEA,mBAAS,SAAS,cAAc,QAAQ,EAAE,OAAO,SAAS,CAAC;AAE3D,qBAAW,MAAM;AACf,gBAAI,SAAS;AACX,sBAAQ,MAAM,aAAa;AAC3B,sBAAQ,MAAM,UAAU;AAAA,YAC1B;AACA,sBAAU,SAAS;AACnB,uBAAW,MAAM;AACf,yBAAW,UAAU;AAAA,YACvB,GAAG,GAAG;AAAA,UACR,GAAG,GAAG;AAAA,QACR,GAAG,GAAG;AAAA,MACR,SAAS,KAAK;AACZ,gBAAQ,MAAM,uCAAuC,GAAG;AACxD,mBAAW,UAAU;AACrB,YAAI,QAAS,SAAQ,MAAM,UAAU;AAAA,MACvC;AAAA,IACF;AAAA,IACA,CAAC,eAAe,WAAW,aAAa,YAAY,aAAa,eAAe;AAAA,EAClF;AAEA,QAAM,mBAAe,4BAAY,MAAM;AACrC,QAAI,CAAC,cAAe;AACpB,eAAW,UAAU;AAErB,UAAM,UAAU,gBAAgB;AAChC,QAAI,SAAS;AACX,cAAQ,MAAM,aAAa;AAC3B,cAAQ,MAAM,UAAU;AAAA,IAC1B;AAEA,UAAM,aAAa,CAAC,GAAG,cAAc,MAAM,cAAc;AACzD,gBAAY,UAAU;AACtB,gBAAY,KAAK;AACjB,eAAW,IAAI;AAEf,eAAW,MAAM;AACf,qBAAe,KAAK;AACpB,iBAAW,MAAM;AACf,YAAI,SAAS;AACX,kBAAQ,MAAM,aAAa;AAC3B,kBAAQ,MAAM,UAAU;AAAA,QAC1B;AACA,mBAAW,MAAM;AACf,qBAAW,UAAU;AAAA,QACvB,GAAG,GAAG;AAAA,MACR,GAAG,GAAG;AAAA,IACR,GAAG,GAAG;AAAA,EACR,GAAG,CAAC,eAAe,gBAAgB,iBAAiB,aAAa,YAAY,WAAW,CAAC;AAEzF,SAAO,EAAE,eAAe,iBAAiB,aAAa;AACxD;;;AC1JA,IAAAC,iBAAuC;AAiBvC,IAAM,gBAAgB,CAAC,IAAI,KAAK,KAAK,GAAI;AAQlC,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoC;AAClC,QAAM,EAAE,QAAQ,eAAe,cAAc,aAAa,IAAI,cAAc;AAE5E,QAAM,6BAAyB;AAAA,IAC7B,CAAC,WAAoB;AACnB,UAAI,QAAQ;AAGV,mBAAW,MAAM,eAAe,IAAI,GAAG,GAAG;AAAA,MAC5C,OAAO;AACL,sBAAc,QAAQ,CAAC,UAAU;AAC/B,qBAAW,MAAM,eAAe,KAAK,GAAG,KAAK;AAAA,QAC/C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,CAAC,cAAc;AAAA,EACjB;AAEA,gCAAU,MAAM;AACd,QAAI,CAAC,cAAe;AAGpB,sBAAkB;AAKlB,kBAAc,UAAU;AAGxB,eAAW,UAAU;AAErB,eAAW,MAAM;AACf,qBAAe,KAAK;AAGpB,iBAAW,MAAM;AACf,mBAAW,UAAU;AAAA,MACvB,GAAG,GAAG;AAAA,IACR,GAAG,CAAC;AAEJ,UAAM,mBAAmB,CAAC,UAAiB;AAEzC,YAAM,cAAc,cAAc;AAElC,mBAAa;AAEb,YAAM,eAAe,MAAM,SAAS,MAAM,OAAOC,QAAO,UAAU,MAAM,SAAS,YAAYA,QAAO;AAEpG,UAAI,gBAAgB,aAAa;AAC/B,+BAAuB,IAAI;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,sBAAsB,CAAC,WAAkB;AAC7C,mBAAa;AAAA,IACf;AAEA,UAAM,oBAAoB,CAAC,WAAkB;AAE3C,mBAAa,EAAE,GAAG,cAAc,MAAM,KAAK,CAAC;AAAA,IAC9C;AAEA,UAAM,kBAAkB,CAAC,UAAiB;AAExC,UAAI,MAAM,QAAQ,YAAYA,QAAO,QAAQ;AAE3C,sBACG,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,EAAE,CAAC,EACjC,KAAK,MAAM;AACV,uBAAa;AACb,iCAAuB,KAAK;AAC5B,gBAAM,YACJ,cAAc,OAAO,YAAY,iBAAiB,aACjD,cAAc,OAAO,YAAoB,SAAS;AACrD,cAAI,CAAC,WAAW;AACd,0BAAc,SAAS,EAAE,MAAM,MAAM;AAAA,YAAC,CAAC;AAAA,UACzC;AAAA,QACF,CAAC,EACA,MAAM,CAAC,MAAM,QAAQ,MAAM,yCAAyC,CAAC,CAAC;AAAA,MAC3E;AAAA,IACF;AAEA,UAAM,uBAAuB,CAAC,UAAiB;AAE7C,YAAM,WACJ,MAAM,OACN,MAAM,SAAS,QACb,MAAc,aAAa,GAAI,MAAc,YAAY,IAAK,MAAc,UAAU,KAAK;AAC/F,UAAI,aAAa,cAAc,KAAK;AAClC,sBACG,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,EAAE,CAAC,EACjC,KAAK,MAAM;AACV,uBAAa;AACb,iCAAuB,KAAK;AAC5B,wBAAc,SAAS,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC;AAAA,QACzC,CAAC,EACA,MAAM,CAAC,MAAM,QAAQ,MAAM,kDAAkD,CAAC,CAAC;AAAA,MACpF;AAAA,IACF;AAEA,UAAMA,UAAS,cAAc,UAAU;AACvC,UAAM,OAAO,cAAc,GAAG,eAAe,gBAAgB;AAC7D,UAAM,OAAO,cAAc,GAAG,mBAAmB,mBAAmB;AACpE,UAAM,OAAO,cAAc,GAAG,mBAAmB,mBAAmB;AACpE,UAAM,OAAO,cAAc,GAAG,kBAAkB,mBAAmB;AACnE,UAAM,OAAO,cAAc,GAAG,oBAAoB,mBAAmB;AACrE,UAAM,OAAO,cAAc,GAAG,gBAAgB,iBAAiB;AAC/D,UAAM,OAAO,cAAc,GAAG,0BAA0B,mBAAmB;AAC3E,UAAM,OAAO,cAAc,GAAG,gBAAgB,mBAAmB;AACjE,UAAM,OAAO,cAAc,GAAG,oBAAoB,mBAAmB;AACrE,UAAM,QAAQ,cAAc,GAAG,oBAAoB,eAAe;AAClE,UAAM,QAAQA,QAAO,GAAG,gCAAgC,oBAAoB;AAE5E,WAAO,MAAM;AACX,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,YAAM,YAAY;AAClB,YAAM,YAAY;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,eAAe,gBAAgB,wBAAwB,cAAc,iBAAiB,YAAY,CAAC;AACzG;;;AC9JA,IAAAC,iBAA6C;AAGtC,IAAM,oBAAoB,CAAC,YAAwC;AACxE,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,yBAAS,CAAC;AAE5D,gCAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,UAAM,gBAAgB,MAAM,qBAAqB,OAAK,IAAI,CAAC;AAE3D,UAAM,OAAO,QAAQ,GAAG,gBAAgB,aAAa;AACrD,UAAM,OAAO,QAAQ,GAAG,kBAAkB,aAAa;AACvD,UAAM,OAAO,QAAQ,GAAG,kBAAkB,aAAa;AACvD,UAAM,OAAO,QAAQ,GAAG,mBAAmB,aAAa;AACxD,UAAM,OAAO,QAAQ,GAAG,kBAAkB,aAAa;AACvD,UAAM,OAAO,QAAQ,GAAG,iBAAiB,aAAa;AACtD,UAAM,OAAO,QAAQ,GAAG,mBAAmB,aAAa;AACxD,UAAM,OAAO,QAAQ,GAAG,gCAAgC,aAAa;AAErE,WAAO,MAAM;AACX,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,WAAK,YAAY;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,mBAAe,wBAAQ,MAAM;AACjC,QAAI,CAAC,SAAS,OAAO,QAAS,QAAO,CAAC;AACtC,WAAO,OAAO,OAAO,QAAQ,MAAM,OAAO;AAAA,EAC5C,GAAG,CAAC,SAAS,OAAO,SAAS,iBAAiB,CAAC;AAE/C,SAAO,EAAE,SAAS,cAAc,kBAAkB;AACpD;AAEO,IAAM,oBAAoB,CAAC,YAAwC;AACxE,QAAM,CAAC,oBAAoB,qBAAqB,QAAI,yBAAS,CAAC;AAE9D,gCAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,UAAM,gBAAgB,MAAM,sBAAsB,OAAK,IAAI,CAAC;AAC5D,UAAM,MAAM,QAAQ,GAAG,mBAAmB,aAAa;AACvD,WAAO,MAAM,IAAI,YAAY;AAAA,EAC/B,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,kBAAc,wBAAQ,MAAM,SAAS,MAAM,QAAQ,SAAS,OAAO,mBAAmB,CAAC,SAAS,MAAM,MAAM,SAAS,KAAK,kBAAkB,CAAC;AACnJ,QAAM,mBAAe,wBAAQ,MAAM,SAAS,MAAM,OAA6B,CAAC,SAAS,MAAM,OAAO,kBAAkB,CAAC;AACzH,QAAM,yBAAqB,wBAAQ,MAAM,SAAS,MAAM,aAAmC,CAAC,SAAS,MAAM,aAAa,kBAAkB,CAAC;AAE3I,SAAO,EAAE,aAAa,cAAc,mBAAmB;AACzD;;;ACtDA,IAAAC,iBAAkB;;;ACAlB,IAAAC,iBAA+B;AAuC3B,IAAAC,uBAAA;AAhCJ,IAAM,qBAAqB;AAE3B,SAAS,aAAa,MAAc,WAA2B;AAC7D,MAAI,KAAK,UAAU,UAAW,QAAO;AACrC,SAAO,KAAK,MAAM,GAAG,SAAS,EAAE,QAAQ,IAAI;AAC9C;AAEO,IAAM,uBAA4D,eAAAC,QAAM,KAAK,CAAC;AAAA,EACnF;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,cAAc,IAAI,cAAc;AAExC,QAAM,cAAU,wBAAgC,MAAM;AACpD,WAAO,aAAa,eAAe,KAAK;AAAA,EAC1C,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,aAAa,cAAc,MAAM,QAAQ,cAAc,MAAM,MAAM;AAEzE,QAAM,UAAU,cAAc,QAAQ;AACtC,QAAM,oBAAgB,wBAAQ,MAAM,0BAA0B,SAAS,eAAsB,OAAO,GAAG,CAAC,SAAS,eAAe,OAAO,CAAC;AAExI,QAAM,cAAc,gBAChB,aAAa,eAAe,kBAAkB,IAC9C;AAEJ,QAAM,cAAc,MAAM;AACxB,YAAQ,cAAc,EAAE;AAAA,EAC1B;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,wBAAwB,eAAe,8BAA8B,EAAE;AAAA,MAClF,SAAS;AAAA,MACT,MAAK;AAAA,MACL,UAAU;AAAA,MACV,WAAW,CAAC,MAAM;AAChB,YAAI,EAAE,QAAQ,QAAS,aAAY;AAAA,MACrC;AAAA,MAEA;AAAA,sDAAC,UAAK,WAAU,gCAAgC,sBAAW;AAAA,QAC3D,8CAAC,UAAK,WAAU,8BAA8B,uBAAY;AAAA;AAAA;AAAA,EAC5D;AAEJ,CAAC;AAED,qBAAqB,cAAc;;;ACtDnC,IAAAC,iBAAmC;;;ACAnC,IAAAC,iBAAwB;;;ACAxB,IAAAC,iBAAiD;AAG1C,IAAM,yBAAyB,MAAM;AAC1C,QAAM,EAAE,eAAe,OAAO,IAAI,cAAc;AAChD,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAS,CAAC;AAG9C,gCAAU,MAAM;AACd,QAAI,CAAC,cAAe;AACpB,UAAM,eAAe,MAAM,cAAc,OAAK,IAAI,CAAC;AAEnD,kBAAc,GAAG,mBAAmB,YAAY;AAChD,WAAO,MAAM;AACX,oBAAc,IAAI,mBAAmB,YAAY;AAAA,IACnD;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,gBAAgB,QAAQ,UAAU;AACxC,QAAM,gBAAgB,eAAe,SAAS;AAC9C,QAAM,OAAQ,eAAe,OAAe,UAAU,aAAa,GAAG;AAEtE,QAAM,UAAU,SAAS,WAAW,eAAe,MAAM,kBAAkB;AAC3E,QAAM,cAAc,SAAS;AAC7B,QAAM,qBAAqB,WAAW;AAEtC,QAAM,eAAyB,gBAAiB,eAAe,MAAc,uBAAuB,CAAC,IAAI,CAAC;AAE1G,QAAM,oBAAgB,4BAAY,CAAC,QAAgB;AACjD,WAAO,CAAC,iBAAiB,sBAAsB,aAAa,SAAS,GAAG;AAAA,EAC1E,GAAG,CAAC,eAAe,oBAAoB,cAAc,UAAU,CAAC;AAEhE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ADlBO,IAAM,oBAAoB,CAAC,SAAgC,iBAA6C;AAC7G,QAAM,EAAE,eAAe,OAAO,IAAI,cAAc;AAChD,QAAM,EAAE,eAAe,QAAQ,SAAS,cAAc,IAAI,uBAAuB;AAGjF,QAAM,cAAc,QAAQ;AAC5B,QAAM,eAAe,QAAQ,UAAU,CAAC,CAAC,QAAQ;AAEjD,aAAO,wBAAQ,MAAM;AACnB,QAAI,CAAC,eAAe;AAClB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW;AAAA,QACX,gBAAgB;AAAA,QAChB,UAAU;AAAA,QACV,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,mBAAmB;AAAA,QACnB,WAAW;AAAA,QACX,aAAa;AAAA,QACb,aAAa;AAAA,MACf;AAAA,IACF;AAEA,UAAM,WAAW,gBAAgB;AACjC,UAAM,WAAW,gBAAgB;AACjC,UAAM,WAAW;AAEjB,UAAM,UAAU,CAAC,YAAY,CAAC,YAAY;AAK1C,UAAM,2BAA2B,UAAU;AAC3C,UAAM,gCAAgC,CAAC,UAAU;AAEjD,UAAM,YAAY,CAAC,aAAa,4BAA4B;AAC5D,UAAM,iBAAiB,CAAC;AACxB,UAAM,WAAW,CAAC,YAAY,CAAC;AAC/B,UAAM,WAAW,CAAC,YAAY,CAAC;AAC/B,UAAM,aAAa,CAAC,YAAY,CAAC;AACjC,UAAM,SAAS,CAAC,YAAY,CAAC;AAC7B,UAAM,UAAU,CAAC,YAAY,CAAC,YAAY,QAAQ,QAAQ,MAAM,KAAK,CAAC;AAEtE,UAAM,aAAa,cAAc,oBAAoB;AACrD,UAAM,eAAe,CAAC,UAAU,WAAY,gBAAgB,cAAc,oBAAoB;AAE9F,UAAM,oBAAoB,CAAC,UAAU,WAAW,CAAC,gBAAgB,cAAc,oBAAoB;AAEnG,UAAM,cAAc,cAAc,YAAY;AAC9C,UAAM,cAAc,cAAc,eAAe;AACjD,UAAM,YAAY,cAAc,aAAa;AAE7C,WAAO;AAAA,MACL;AAAA,MAAS;AAAA,MAAW;AAAA,MAAgB;AAAA,MAAU;AAAA,MAAU;AAAA,MAAY;AAAA,MAAQ;AAAA,MAAS;AAAA,MACrF;AAAA,MAAY;AAAA,MAAc;AAAA,MAAmB;AAAA,MAAW;AAAA,MAAa;AAAA,IACvE;AAAA,EACF,GAAG,CAAC,eAAe,QAAQ,SAAS,eAAe,aAAa,QAAQ,MAAM,cAAc,YAAY,CAAC;AAC3G;;;AEtFA,IAAAC,iBAAyC;AACzC,uBAA6B;AAiHzB,IAAAC,uBAAA;AA9GJ,IAAM,kBAAkB;AAGjB,IAAM,oBAAoB,MAAM;AACrC,WAAS,cAAc,IAAI,YAAY,eAAe,CAAC;AACzD;AAmBO,IAAM,WAAoC,CAAC;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,OAAO,YAAY,CAAC;AACtB,MAAM;AACJ,QAAM,mBAAe,uBAAuB,IAAI;AAChD,QAAM,iBAAa,uBAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAG7D,gCAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AAGb,aAAS,cAAc,IAAI,YAAY,iBAAiB,EAAE,QAAQ,WAAW,QAAQ,CAAC,CAAC;AAEvF,UAAM,oBAAoB,CAAC,MAAa;AACtC,YAAM,SAAU,EAAkB;AAClC,UAAI,CAAC,UAAU,WAAW,WAAW,SAAS;AAC5C,gBAAQ;AAAA,MACV;AAAA,IACF;AAEA,UAAM,qBAAqB,CAAC,MAAkB;AAG5C,UAAI,aAAa,WAAW,CAAC,aAAa,QAAQ,SAAS,EAAE,MAAc,GAAG;AAC5E,gBAAQ;AAAA,MACV;AAAA,IACF;AAEA,UAAM,gBAAgB,CAAC,MAAqB;AAC1C,UAAI,EAAE,QAAQ,SAAU,SAAQ;AAAA,IAClC;AAEA,UAAM,eAAe,MAAM,QAAQ;AAGnC,UAAM,MAAM,WAAW,MAAM;AAC3B,eAAS,iBAAiB,SAAS,kBAAkB;AAAA,IACvD,GAAG,EAAE;AAEL,aAAS,iBAAiB,iBAAiB,iBAAiB;AAC5D,aAAS,iBAAiB,WAAW,aAAa;AAClD,aAAS,iBAAiB,UAAU,cAAc,IAAI;AAEtD,WAAO,MAAM;AACX,mBAAa,GAAG;AAChB,eAAS,oBAAoB,iBAAiB,iBAAiB;AAC/D,eAAS,oBAAoB,SAAS,kBAAkB;AACxD,eAAS,oBAAoB,WAAW,aAAa;AACrD,eAAS,oBAAoB,UAAU,cAAc,IAAI;AAAA,IAC3D;AAAA,EACF,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,MAAI,CAAC,UAAU,CAAC,WAAY,QAAO;AAEnC,QAAM,aAAa,OAAO,cAAc,WAAW;AACnD,QAAM,aAAa,WAAW;AAC9B,QAAM,0BAA0B;AAEhC,MAAI,gBAAqC,CAAC;AAC1C,MAAI,aAAa,2BAA2B,aAAa,YAAY;AAEnE,oBAAgB,EAAE,QAAQ,OAAO,cAAc,WAAW,MAAM,EAAE;AAAA,EACpE,OAAO;AAEL,oBAAgB,EAAE,KAAK,WAAW,SAAS,EAAE;AAAA,EAC/C;AAEA,QAAM,QAA6B;AAAA,IACjC,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,GAAG;AAAA,IACH,GAAI,UAAU,UACV,EAAE,OAAO,OAAO,aAAa,WAAW,MAAM,IAC9C,EAAE,MAAM,WAAW,KAAK;AAAA,IAC5B,GAAG;AAAA,EACL;AAEA,QAAM,eAAe,SAAS,cAAc,aAAa,KAAK,SAAS;AAEvE,aAAO;AAAA,IACL,8CAAC,SAAI,KAAK,cAAc,WAAW,kBAAkB,SAAS,GAAG,KAAK,GAAG,OACtE,UACH;AAAA,IACA;AAAA,EACF;AACF;;;AH7BI,IAAAC,uBAAA;AAhFG,IAAM,oBAAsD,CAAC;AAAA,EAClE;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,yBAAyB;AAC3B,MAAM;AACJ,QAAM,EAAE,kBAAkB,mBAAmB,sBAAsB,cAAc,IAAI,cAAc;AACnG,QAAM,CAAC,YAAY,aAAa,IAAI,eAAAC,QAAM,SAAyB,IAAI;AACvE,QAAM,UAAU,kBAAkB,SAAS,YAAY;AAGvD,QAAM,UAAU,gBAAgB,CAAC,QAA+B,iBAAiB,GAAG;AACpF,QAAM,mBAAmB,cAAc,CAAC,QAA+B,qBAAqB,GAAG;AAC/F,QAAM,qBAAqB,gBAAgB,OAAO,KAA4B,aAAsB;AAClG,QAAI,CAAC,cAAe;AACpB,QAAI;AACF,UAAI,UAAU;AACZ,cAAM,cAAc,aAAa,IAAI,EAAG;AAAA,MAC1C,OAAO;AACL,cAAM,cAAc,WAAW,IAAI,EAAG;AAAA,MACxC;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,wBAAwB,GAAG;AAAA,IAC3C;AAAA,EACF;AACA,QAAM,gBAAgB,WAAW,CAAC,QAA+B,kBAAkB,GAAG;AAEtF,QAAM,6BAA6B,aAAa,OAAO,QAA+B;AACpF,QAAI,CAAC,cAAe;AACpB,QAAI;AACF,YAAM,cAAc,cAAc,IAAI,EAAG;AAAA,IAC3C,SAAS,KAAK;AACZ,cAAQ,MAAM,4BAA4B,GAAG;AAAA,IAC/C;AAAA,EACF;AAEA,QAAM,uBAAuB,kBAAkB,OAAO,QAA+B;AACnF,QAAI,CAAC,cAAe;AACpB,QAAI;AACF,YAAM,cAAc,mBAAmB,IAAI,EAAG;AAAA,IAChD,SAAS,KAAK;AACZ,cAAQ,MAAM,mCAAmC,GAAG;AAAA,IACtD;AAAA,EACF;AAEA,QAAM,SAAS,eAAe;AAC9B,QAAM,cAAU,4BAAY,MAAM,cAAc,IAAI,GAAG,CAAC,CAAC;AAEzD,QAAM,kBAAkB,CAAC,MAAwB;AAC/C,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAClB,UAAM,OAAQ,EAAE,cAA8B,sBAAsB;AACpE,kBAAc,IAAI;AAAA,EACpB;AAEA,QAAM,aAAa,YAAY;AAC7B,QAAI,QAAQ;AACV,aAAO,OAAO;AAAA,IAChB,WAAW,QAAQ,MAAM;AACvB,UAAI;AACF,cAAM,UAAU,UAAU,UAAU,QAAQ,IAAI;AAAA,MAClD,SAAS,KAAK;AACZ,gBAAQ,MAAM,wBAAwB,GAAG;AAAA,MAC3C;AAAA,IACF;AACA,YAAQ;AAAA,EACV;AAEA,SACE,gFACE;AAAA,mDAAC,SAAI,WAAW,+BAA+B,SAAS,wCAAwC,EAAE,IAC/F;AAAA,cAAQ,YACP;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,UAAU,OAAO;AAAA,UAChC,OAAM;AAAA,UACN,UAAU,CAAC,QAAQ;AAAA,UAEnB,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,gBACnD,wDAAC,UAAK,GAAE,gvBAA+uB,GACzvB;AAAA;AAAA,MACF;AAAA,MAED,QAAQ,cACP;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM,iBAAiB,OAAO;AAAA,UACvC,OAAM;AAAA,UACN,UAAU,CAAC,QAAQ;AAAA,UAEnB,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,0DAAC,cAAS,QAAO,mBAAkB;AAAA,YACnC,8CAAC,UAAK,GAAE,6BAA4B;AAAA,aACtC;AAAA;AAAA,MACF;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,uCAAuC,SAAS,gDAAgD,EAAE;AAAA,UAC7G,SAAS;AAAA,UACT,OAAM;AAAA,UAEN,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,0DAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,YAC9B,8CAAC,YAAO,IAAG,MAAK,IAAG,KAAI,GAAE,KAAI;AAAA,YAC7B,8CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,aAChC;AAAA;AAAA,MACF;AAAA,OACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,eAAe,UAAU;AAAA,QAEhC,yDAAC,SAAI,WAAU,wBACZ;AAAA,kBAAQ,UACP;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM;AAAE,mCAAmB,SAAS,QAAQ,QAAQ;AAAG,wBAAQ;AAAA,cAAG;AAAA,cAC3E,UAAU,CAAC,QAAQ;AAAA,cAElB,kBAAQ,WAAW,aAAa;AAAA;AAAA,UACnC;AAAA,UAED,QAAQ,WACP;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM;AAAE,8BAAc,OAAO;AAAG,wBAAQ;AAAA,cAAG;AAAA,cACpD,UAAU,CAAC,QAAQ;AAAA,cAElB;AAAA;AAAA,UACH;AAAA,UAED,QAAQ,WACP,8CAAC,YAAO,WAAU,wBAAuB,SAAS,YAC/C,qBACH;AAAA,WAGA,QAAQ,aAAa,QAAQ,mBAAmB,8CAAC,SAAI,WAAU,2BAA0B;AAAA,UAE1F,QAAQ,kBACP;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM;AAAE,qCAAqB,OAAO;AAAG,wBAAQ;AAAA,cAAG;AAAA,cAC3D,UAAU,CAAC,QAAQ;AAAA,cAElB;AAAA;AAAA,UACH;AAAA,UAED,QAAQ,aACP;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM;AAAE,2CAA2B,OAAO;AAAG,wBAAQ;AAAA,cAAG;AAAA,cACjE,UAAU,CAAC,QAAQ;AAAA,cAElB;AAAA;AAAA,UACH;AAAA,WAEJ;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;;;AIzLA,IAAAC,iBAAkB;AAwCR,IAAAC,uBAAA;AAnCV,IAAM,0BAAkD;AAAA,EACtD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AACR;AAEO,IAAM,mBAAoD,eAAAC,QAAM,KAAK,CAAC;AAAA,EAC3E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,OAAO,IAAI,cAAc;AACjC,QAAM,gBAAgB,QAAQ;AAE9B,MAAI,CAAC,kBAAkB,OAAO,KAAK,cAAc,EAAE,WAAW,EAAG,QAAO;AAExE,SACE,8CAAC,SAAI,WAAU,2BACZ,iBAAO,QAAQ,cAAc,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;AACrD,UAAM,QACJ,cAAc,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KACzC,iBAAiB,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,MAAM,OAAO,iBAAkB,EAAU,YAAY,cAAc;AAGxH,UAAM,YAAY,iBACd,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI,EAC9B,IAAI,CAAC,MAAW,EAAE,MAAM,QAAQ,EAAE,MAAM,MAAM,EAAE,WAAW,SAAS;AAEvE,UAAM,UAAU,aAAa,UAAU,SAAS,IAAI,UAAU,KAAK,IAAI,IAAI;AAC3E,UAAM,QAAQ,wBAAwB,IAAI,KAAK;AAE/C,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,iCACT,QAAQ,0CAA0C,EACpD;AAAA,QACA,gBAAc;AAAA,QACd,SAAS,MAAM,kBAAkB,IAAI;AAAA,QACrC,MAAK;AAAA,QAEL;AAAA,wDAAC,UAAK,WAAU,kCAAkC,iBAAM;AAAA,UACxD,8CAAC,UAAK,WAAU,kCAAkC,iBAAM;AAAA;AAAA;AAAA,MATnD;AAAA,IAUP;AAAA,EAEJ,CAAC,GACH;AAEJ,CAAC;AAED,iBAAiB,cAAc;;;AC1D/B,IAAAC,iBAAmC;AAoDzB,IAAAC,uBAAA;AAhDV,IAAM,kBAAkB,CAAC,QAAQ,QAAQ,QAAQ,OAAO,MAAM;AAC9D,IAAM,YAAoC;AAAA,EACxC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AACR;AAEO,IAAM,wBAGR,eAAAC,QAAM,KAAK,CAAC,EAAE,SAAS,aAAa,MAAM;AAC7C,QAAM,EAAE,eAAe,OAAO,IAAI,cAAc;AAChD,QAAM,gBAAgB,QAAQ;AAE9B,QAAM,2BAAuB;AAAA,IAC3B,OAAO,SAAiB;AACtB,UAAI,CAAC,cAAe;AACpB,YAAM,QACH,QAAgB,eAAe,KAAK,CAAC,MAAW,EAAE,SAAS,IAAI,KAC/D,QAAgB,kBAAkB;AAAA,QACjC,CAAC,MAAW,EAAE,SAAS,SAAS,EAAE,MAAM,OAAO,iBAAkB,EAAU,YAAY;AAAA,MACzF;AAEF,UAAI;AACF,YAAI,OAAO;AACT,gBAAM,cAAc,eAAe,QAAQ,IAAK,IAAI;AAAA,QACtD,OAAO;AACL,gBAAM,cAAc,aAAa,QAAQ,IAAK,IAAI;AAAA,QACpD;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,6BAA6B,GAAG;AAAA,MAChD;AAAA,IACF;AAAA,IACA,CAAC,eAAe,SAAS,aAAa;AAAA,EACxC;AAEA,SACE,8CAAC,SAAI,WAAW,iCAAiC,eAAe,uCAAuC,EAAE,IACtG,0BAAgB,IAAI,CAAC,SAAS;AAC7B,UAAM,QACH,QAAgB,eAAe,KAAK,CAAC,MAAW,EAAE,SAAS,IAAI,KAC/D,QAAgB,kBAAkB;AAAA,MACjC,CAAC,MAAW,EAAE,SAAS,SAAS,EAAE,MAAM,OAAO,iBAAkB,EAAU,YAAY;AAAA,IACzF;AAEF,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,sCACT,QAAQ,+CAA+C,EACzD;AAAA,QACA,OAAO;AAAA,QACP,SAAS,CAAC,MAAM;AACd,YAAE,eAAe;AACjB,YAAE,gBAAgB;AAClB,+BAAqB,IAAI;AAAA,QAC3B;AAAA,QAEC,oBAAU,IAAI;AAAA;AAAA,MAXV;AAAA,IAYP;AAAA,EAEJ,CAAC,GACH;AAEJ,CAAC;AAED,sBAAsB,cAAc;;;AP3C5B,IAAAC,uBAAA;AAbR,IAAM,mBAAiG,eAAAC,QAAM,KAAK,CAAC;AAAA,EACjH;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,MAAI,CAAC,aAAc,QAAO;AAE1B,QAAM,UAAU,WAAW,WAAW,WAAW;AACjD,MAAI,CAAC,iBAAiB,CAAC,QAAS,QAAO;AAEvC,MAAI,SAAS;AACX,WACE,8CAAC,UAAK,WAAU,+DAA8D,OAAM,kBAClF,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI;AAAA,oDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,MAC/B,8CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,MACrC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK;AAAA,OAC3C,GACF;AAAA,EAEJ;AAEA,MAAI,WAAW,WAAW;AACxB,WACE,8CAAC,UAAK,WAAU,gEAA+D,OAAM,cACnF,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,oDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,MAC/B,8CAAC,cAAS,QAAO,oBAAmB;AAAA,OACtC,GACF;AAAA,EAEJ;AAEA,SACE,8CAAC,UAAK,WAAU,6DAA4D,OAAM,QAChF,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI,wDAAC,cAAS,QAAO,kBAAiB,GACpC,GACF;AAEJ,CAAC;AACD,iBAAiB,cAAc;AAExB,IAAM,cAA0C,eAAAA,QAAM,KAAK,CAAC;AAAA,EACjE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gCAAgC;AAAA,EAChC,6BAA6B;AAAA,EAC7B,4BAA4B;AAAA,EAC5B,iBAAiB;AAAA,EACjB,cAAc;AAChB,MAAM;AACJ,QAAM,EAAE,eAAe,OAAO,IAAI,cAAc;AAChD,QAAM,EAAE,cAAc,IAAI,uBAAuB;AAEjD,QAAM,WAAW,cAAc,eAAe;AAE9C,QAAM,WAAW,QAAQ,MAAM,QAAQ,QAAQ;AAC/C,QAAM,aAAa,QAAQ,MAAM;AAEjC,QAAM,gBAAiB,QAAgB;AACvC,QAAM,cAAc,CAAC,CAAE,QAAgB;AACvC,QAAM,WAAY,QAAgB;AAClC,QAAM,WAAW,YAAY,SAAS,SAAS;AAC/C,QAAM,iBAAiB,QAAQ,eAAe,QAAQ,YAAY,SAAS;AAE3E,QAAM,uBAAuB,eAAAA,QAAM,YAAY,OAAO,SAAiB;AACrE,QAAI,CAAC,iBAAiB,CAAC,SAAU;AACjC,UAAM,gBAAgB,QAAQ;AAC9B,UAAM,QACH,QAAgB,eAAe,KAAK,CAAC,MAAW,EAAE,SAAS,IAAI,KAC/D,QAAgB,kBAAkB,KAAK,CAAC,MAAW,EAAE,SAAS,SAAS,EAAE,MAAM,OAAO,iBAAkB,EAAU,YAAY,cAAc;AAE/I,QAAI;AACF,UAAI,OAAO;AACT,cAAM,cAAc,eAAe,QAAQ,IAAK,IAAI;AAAA,MACtD,OAAO;AACL,cAAM,cAAc,aAAa,QAAQ,IAAK,IAAI;AAAA,MACpD;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,6BAA6B,GAAG;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,eAAe,SAAS,QAAQ,MAAM,CAAC;AAE3C,QAAM,cACJ,QAAQ,WAAW,YACf,2BACC,QAAQ,WAAW,WAAW,QAAQ,WAAW,mBAChD,yBACA;AAER,QAAM,eAAe,eAAAA,QAAM,QAAQ,MAAM;AACvC,QAAI,CAAC,QAAQ,WAAY,QAAO;AAChC,WAAO,KAAK,IAAI,IAAI,IAAI,KAAK,QAAQ,UAAU,EAAE,QAAQ,IAAI;AAAA,EAC/D,GAAG,CAAC,QAAQ,UAAU,CAAC;AAEvB,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,eAAe,kCAAkC;AAAA,IACjD,iBAAiB,0CAA0C;AAAA,IAC3D,gBAAgB,0CAA0C;AAAA,IAC1D,eAAe,kCAAkC;AAAA,IACjD;AAAA,EACF,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAE1B,QAAM,eAAe;AAAA,IACnB;AAAA,IACA,iBAAiB,sDAAsD;AAAA,EACzE,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAE1B,SACE,+CAAC,SAAI,WAAW,WAAW,mBAAiB,QAAQ,IAEjD;AAAA,KAAC,gBACA,8CAAC,SAAI,WAAU,mCACZ,2BACG,8CAAC,mBAAgB,OAAO,YAAY,MAAM,UAAU,MAAM,IAAI,IAC9D,8CAAC,SAAI,OAAO,EAAE,OAAO,GAAG,GAAG,GAEjC;AAAA,IAEF,+CAAC,SAAI,WAAW,cACb;AAAA,OAAC,gBAAgB,kBAChB,8CAAC,UAAK,WAAU,iCAAiC,oBAAS;AAAA,MAG3D,iBAAiB,gBAChB;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,SAAS;AAAA;AAAA,MACX;AAAA,MAEF,+CAAC,SAAI,WAAU,sCACb;AAAA,sDAAC,SAAI,OAAO,CAAC,WAAW,EAAE,SAAS,KAAK,eAAe,OAAO,IAAI,CAAC,GACjE,wDAAC,yBAAsB,SAAkB,cAA4B,GACvE;AAAA,QACA,+CAAC,iBAAc,SAAkB,cAC9B;AAAA,yBACC,8CAAC,UAAK,WAAU,2CAA2C,0BAAe;AAAA,UAE5E,8CAAC,mBAAgB,SAAkB,cAA4B;AAAA,UAC/D,+CAAC,UAAK,WAAU,iCACb;AAAA,wBACC;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBAGT;AAAA;AAAA,YACH;AAAA,YAED,WAAW,QAAQ,UAAU;AAAA,YAC9B,8CAAC,oBAAiB,QAAQ,QAAQ,QAAQ,cAA4B,eAA8B;AAAA,aACtG;AAAA,WACF;AAAA,QAGC,QAAQ,SAAS,YAChB;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA;AAAA,QACF;AAAA,QAID,6BACC,8CAAC,SAAI,OAAO,CAAC,WAAW,EAAE,SAAS,KAAK,eAAe,OAAO,IAAI,CAAC,GACjE;AAAA,UAAC;AAAA;AAAA,YACC,gBAAiB,QAAgB;AAAA,YACjC,cAAe,QAAgB;AAAA,YAC/B,iBAAkB,QAAgB;AAAA,YAClC,iBAAiB;AAAA;AAAA,QACnB,GACF;AAAA,SAEJ;AAAA,OACF;AAAA,KACF;AAEJ,CAAC;AACD,YAAY,cAAc;AAKnB,IAAM,oBAAsD,eAAAA,QAAM,KAAK,CAAC;AAAA,EAC7E;AAAA,EACA;AAAA,EACA;AACF,MACE,8CAAC,SAAI,WAAU,8BACb,wDAAC,kBAAe,SAAkB,cAA4B,GAChE,CACD;AACD,kBAAkB,cAAc;;;AQzNhC,IAAAC,iBAAyC;AAGzC,IAAAC,yBAAiE;AAmD7D,IAAAC,uBAAA;AAzCJ,SAAS,QAAQ,YAAiC;AAChD,SAAO,CAAC,EACN,WAAW,SAAS,WACnB,CAAC,WAAW,SAAS,WAAW,WAAW,WAAW,QAAQ,KAAK,WAAW;AAEnF;AAEA,SAAS,QAAQ,YAAiC;AAChD,SAAO,CAAC,EAAE,WAAW,SAAS,WAAY,CAAC,WAAW,QAAQ,WAAW,WAAW,WAAW,QAAQ;AACzG;AAEA,SAAS,iBAAiB,YAAiC;AACzD,SAAO,WAAW,SAAS;AAC7B;AAEA,SAAS,cAAc,YAAiC;AACtD,SAAO,WAAW,SAAS;AAC7B;AAKA,IAAM,kBAA6C,eAAAC,QAAM,KAAK,CAAC,EAAE,WAAW,MAAM;AAChF,QAAM,MAAM,WAAW,aAAa,WAAW,aAAa,WAAW;AACvE,QAAM,WAAW,WAAW;AAC5B,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,gBAAgB,iBAAiB,GAAG;AAC1C,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,aAAa;AAClD,QAAM,SAAS,eAAAA,QAAM,OAAyB,IAAI;AAGlD,8BAAQ,MAAM;AAAE,iBAAa,GAAG;AAAA,EAAG,GAAG,CAAC,GAAG,CAAC;AAE3C,iBAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,UAAU,OAAO,SAAS,UAAU;AACvC,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,QAAQ,GAAG,CAAC;AAEhB,SACE,+CAAC,SAAI,WAAU,+BAA8B,OAAO,EAAE,eAAe,MAAM,GAExE;AAAA,KAAC,WACA,YAAY,aAAa,MACvB;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,KAAK;AAAA,QACL,KAAI;AAAA,QACJ,eAAW;AAAA;AAAA,IACb,IAEA,8CAAC,SAAI,WAAU,4BAA2B;AAAA,IAG9C;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,WAAW,2CAA2C,SAAS,8BAA8B,EAAE;AAAA,QAC/F;AAAA,QACA,KAAK,WAAW,aAAa,WAAW,SAAS;AAAA,QACjD,SAAQ;AAAA,QACR,QAAQ,MAAM,UAAU,IAAI;AAAA;AAAA,IAC9B;AAAA,KACF;AAEJ,GAAG,CAAC,MAAM,SAAS;AACjB,QAAM,UAAU,KAAK,WAAW,aAAa,KAAK,WAAW,aAAa,KAAK,WAAW;AAC1F,QAAM,UAAU,KAAK,WAAW,aAAa,KAAK,WAAW,aAAa,KAAK,WAAW;AAC1F,SAAO,YAAY;AACrB,CAAC;AACA,gBAAwB,cAAc;AAEvC,IAAM,kBAA6C,eAAAA,QAAM,KAAK,CAAC,EAAE,WAAW,MAAM;AAChF,QAAM,MAAM,WAAW,aAAa,WAAW;AAC/C,QAAM,YAAY,WAAW,aAAa,WAAW;AACrD,QAAM,YAAY,WAAW;AAC7B,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,gBAAgB,YAAY,iBAAiB,SAAS,IAAI;AAChE,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,aAAa;AAClD,QAAM,SAAS,eAAAA,QAAM,OAAyB,IAAI;AAElD,8BAAQ,MAAM;AACZ,QAAI,UAAW,cAAa,SAAS;AAAA,EACvC,GAAG,CAAC,SAAS,CAAC;AAEd,iBAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,UAAU,OAAO,SAAS,UAAU;AACvC,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,CAAC;AAEtB,SACE,+CAAC,SAAI,WAAU,+BAA8B,OAAO,EAAE,eAAe,MAAM,GACxE;AAAA,KAAC,WACA,aAAa,cAAc,YACzB;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,KAAK;AAAA,QACL,KAAI;AAAA,QACJ,eAAW;AAAA;AAAA,IACb,IAEA,8CAAC,SAAI,WAAU,4BAA2B;AAAA,IAG7C,aAAa,CAAC,UACb;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,KAAK;AAAA,QACL,OAAO,EAAE,SAAS,OAAO;AAAA,QACzB,QAAQ,MAAM,UAAU,IAAI;AAAA,QAC5B,KAAI;AAAA;AAAA,IACN;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,2CAA2C,UAAU,CAAC,YAAY,8BAA8B,EAAE;AAAA,QAC7G;AAAA,QACA,QAAQ;AAAA,QACR,UAAQ;AAAA,QACR,SAAQ;AAAA,QACR,cAAc,MAAM;AACjB,cAAI,CAAC,UAAW,WAAU,IAAI;AAAA,QACjC;AAAA;AAAA,IACF;AAAA,KACF;AAEJ,GAAG,CAAC,MAAM,SAAS;AACjB,UAAQ,KAAK,WAAW,aAAa,KAAK,WAAW,UAClD,KAAK,WAAW,aAAa,KAAK,WAAW;AAClD,CAAC;AACA,gBAAwB,cAAc;AAEvC,IAAM,iBAA4C,eAAAA,QAAM,KAAK,CAAC,EAAE,WAAW,MAAM;AAC/E,QAAM,MAAM,WAAW,OAAO,WAAW;AACzC,QAAM,OAAO,WAAW,aAAa,WAAW,SAAS;AACzD,QAAM,OAAO,WAAW;AAExB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,MAAM;AAAA,MACN,UAAU;AAAA,MACV,QAAO;AAAA,MACP,KAAI;AAAA,MAEJ;AAAA,sDAAC,UAAK,WAAU,+BAA8B,0BAAE;AAAA,QAChD,+CAAC,UAAK,WAAU,+BACd;AAAA,wDAAC,UAAK,WAAU,+BAA+B,gBAAK;AAAA,UACnD,QACC,8CAAC,UAAK,WAAU,+BACb,iBAAO,SAAS,WAAW,IAAI,OAAO,MAAM,QAAQ,CAAC,CAAC,QAAQ,MACjE;AAAA,WAEJ;AAAA;AAAA;AAAA,EACF;AAEJ,GAAG,CAAC,MAAM,SAAS;AACjB,UAAQ,KAAK,WAAW,OAAO,KAAK,WAAW,gBAC5C,KAAK,WAAW,OAAO,KAAK,WAAW;AAC5C,CAAC;AACA,eAAuB,cAAc;AAEtC,IAAM,2BAAsD,eAAAA,QAAM,KAAK,CAAC,EAAE,WAAW,MAAM;AACzF,QAAM,MAAM,WAAW,aAAa,WAAW;AAC/C,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,cAAc,WAAW,YAAY;AAC3C,QAAM,OAAO,KAAK,MAAM,cAAc,EAAE;AACxC,QAAM,OAAO,KAAK,MAAM,cAAc,EAAE;AACxC,QAAM,gBAAgB,GAAG,IAAI,IAAI,KAAK,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC;AAEjE,SACE,+CAAC,SAAI,WAAU,4CACb;AAAA,kDAAC,UAAK,WAAU,gCAA+B,6BAAG;AAAA,IAClD,8CAAC,WAAM,KAAU,UAAQ,MAAC,SAAQ,YAAW,WAAU,kCAAiC;AAAA,IACxF,8CAAC,UAAK,WAAU,oCAAoC,yBAAc;AAAA,KACpE;AAEJ,GAAG,CAAC,MAAM,SAAS;AACjB,UAAQ,KAAK,WAAW,aAAa,KAAK,WAAW,UAClD,KAAK,WAAW,aAAa,KAAK,WAAW;AAClD,CAAC;AACA,yBAAiC,cAAc;AAEhD,IAAM,wBAAmD,eAAAA,QAAM,KAAK,CAAC,EAAE,WAAW,MAAM;AACtF,QAAM,MAAM,WAAW,YAAY,WAAW,iBAAiB,WAAW,cAAc,WAAW;AACnG,QAAM,QAAQ,WAAW;AACzB,QAAM,cAAc,WAAW;AAC/B,QAAM,QAAQ,WAAW;AAEzB,QAAM,gBAAgB,QAAQ,iBAAiB,KAAK,IAAI;AACxD,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,aAAa;AAClD,QAAM,SAAS,eAAAA,QAAM,OAAyB,IAAI;AAElD,8BAAQ,MAAM;AACZ,QAAI,MAAO,cAAa,KAAK;AAAA,EAC/B,GAAG,CAAC,KAAK,CAAC;AAEV,iBAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,UAAU,OAAO,SAAS,UAAU;AACvC,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,QAAQ,KAAK,CAAC;AAElB,MAAI,CAAC,MAAO,QAAO;AAEnB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,MAAM;AAAA,MACN,QAAO;AAAA,MACP,KAAI;AAAA,MAEH;AAAA,iBACC,+CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,OAAO,QAAQ,WAAW,SAAS,iBAAiB,kCAAkC,UAAU,SAAS,GAC1I;AAAA,WAAC,UAAU,8CAAC,SAAI,WAAU,4BAA2B;AAAA,UACtD;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,WAAW,+BAA+B,SAAS,8BAA8B,EAAE;AAAA,cACnF,KAAK;AAAA,cACL,KAAK,SAAS;AAAA,cACd,SAAQ;AAAA,cACR,QAAQ,MAAM,UAAU,IAAI;AAAA,cAC5B,OAAO,EAAE,SAAS,SAAS,IAAI,GAAG,YAAY,qBAAqB,SAAS,SAAS,OAAO,QAAQ,QAAQ,QAAQ,WAAW,SAAS,UAAU,YAAY,KAAK,GAAG,MAAM,EAAE;AAAA;AAAA,UAChL;AAAA,WACF;AAAA,QAEF,+CAAC,SAAI,WAAU,+BACZ;AAAA,mBAAS,8CAAC,UAAK,WAAU,gCAAgC,iBAAM;AAAA,UAC/D,eAAe,8CAAC,UAAK,WAAU,sCAAsC,uBAAY;AAAA,UACjF,OACC,8CAAC,UAAK,WAAU,8BACb,cAAI,IAAI,GAAG,EAAE,UAChB;AAAA,WAEJ;AAAA;AAAA;AAAA,EACF;AAEJ,GAAG,CAAC,MAAM,SAAS;AACjB,UAAQ,KAAK,WAAW,YAAY,KAAK,WAAW,iBAAiB,KAAK,WAAW,UAClF,KAAK,WAAW,YAAY,KAAK,WAAW,iBAAiB,KAAK,WAAW;AAClF,CAAC;AACA,sBAA8B,cAAc;AAEtC,IAAM,oBAA+C,CAAC,EAAE,WAAW,MAAM;AAC9E,MAAI,QAAQ,UAAU,EAAG,QAAO,8CAAC,mBAAgB,YAAwB;AACzE,MAAI,QAAQ,UAAU,EAAG,QAAO,8CAAC,mBAAgB,YAAwB;AACzE,MAAI,iBAAiB,UAAU,EAAG,QAAO,8CAAC,4BAAyB,YAAwB;AAC3F,MAAI,cAAc,UAAU,EAAG,QAAO,8CAAC,yBAAsB,YAAwB;AACrF,SAAO,8CAAC,kBAAe,YAAwB;AACjD;AAEO,IAAM,iBAA2D,eAAAA,QAAM,KAAK,CAAC,EAAE,YAAY,MAAM;AACtG,MAAI,CAAC,eAAe,YAAY,WAAW,EAAG,QAAO;AAGrD,QAAM,QAAQ,YAAY,OAAO,CAAC,MAAM,QAAQ,CAAC,KAAK,QAAQ,CAAC,CAAC;AAChE,QAAM,QAAQ,YAAY,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;AAC/G,QAAM,SAAS,YAAY,OAAO,gBAAgB;AAClD,QAAM,QAAQ,YAAY,OAAO,aAAa;AAE9C,QAAM,iBAAiB,MAAM,WAAW,IACpC,wDACA;AAEJ,SACE,+CAAC,SAAI,WAAU,yBAEZ;AAAA,UAAM,SAAS,KACd,8CAAC,SAAI,WAAW,gBACb,gBAAM,IAAI,CAAC,KAAK,MACf,QAAQ,GAAG,IACP,8CAAC,mBAA2C,YAAY,OAAlC,IAAI,MAAM,OAAO,CAAC,EAAqB,IAC7D,8CAAC,mBAA2C,YAAY,OAAlC,IAAI,MAAM,OAAO,CAAC,EAAqB,CAClE,GACH;AAAA,IAGD,MAAM,IAAI,CAAC,KAAK,MACf,8CAAC,kBAA2C,YAAY,OAAnC,IAAI,MAAM,QAAQ,CAAC,EAAqB,CAC9D;AAAA,IAEA,OAAO,IAAI,CAAC,KAAK,MAChB,8CAAC,4BAAsD,YAAY,OAApC,IAAI,MAAM,SAAS,CAAC,EAAqB,CACzE;AAAA,IAEA,MAAM,IAAI,CAAC,KAAK,MACf,8CAAC,yBAAkD,YAAY,OAAnC,IAAI,MAAM,QAAQ,CAAC,EAAqB,CACrE;AAAA,KACH;AAEJ,GAAG,CAAC,MAAM,SAAS;AAEjB,MAAI,KAAK,gBAAgB,KAAK,YAAa,QAAO;AAClD,MAAI,CAAC,KAAK,eAAe,CAAC,KAAK,YAAa,QAAO;AACnD,MAAI,KAAK,YAAY,WAAW,KAAK,YAAY,OAAQ,QAAO;AAChE,SAAO,KAAK,YAAY,MAAM,CAAC,GAAG,MAAM,EAAE,OAAO,KAAK,YAAa,CAAC,EAAE,EAAE;AAC1E,CAAC;AACA,eAAuB,cAAc;AAUtC,IAAM,YAAY;AAElB,SAAS,YAAY,MAAc,WAAsC;AACvE,QAAM,QAAQ,KAAK,MAAM,SAAS;AAClC,MAAI,MAAM,WAAW,EAAG,QAAO,CAAC,IAAI;AAEpC,SAAO,MAAM,IAAI,CAAC,MAAM,MAAM;AAC5B,QAAI,UAAU,KAAK,IAAI,GAAG;AAExB,gBAAU,YAAY;AACtB,YAAM,UAAU,KAAK,SAAS,GAAG,KAAK,CAAC,KAAK,WAAW,MAAM;AAC7D,YAAM,OAAO,UAAU,UAAU,IAAI,KAAM,KAAK,WAAW,MAAM,IAAI,OAAO,WAAW,IAAI;AAC3F,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UACV;AAAA,UACA,QAAO;AAAA,UACP,KAAI;AAAA,UAEH;AAAA;AAAA,QANI,GAAG,SAAS,SAAS,CAAC;AAAA,MAO7B;AAAA,IAEJ;AAEA,cAAU,YAAY;AACtB,WAAO;AAAA,EACT,CAAC;AACH;AAMA,SAAS,uBACP,MACA,SACA,SACiB;AACjB,QAAM,iBAA4B,QAAgB,mBAAmB,CAAC;AACtE,QAAM,eAAyB,QAAgB,iBAAiB;AAGhE,MAAI,eAAe,WAAW,KAAK,CAAC,cAAc;AAChD,WAAO,YAAY,MAAM,KAAK;AAAA,EAChC;AAGA,QAAM,eAAqD,CAAC;AAE5D,aAAW,UAAU,gBAAgB;AACnC,iBAAa,KAAK;AAAA,MAChB,SAAS,IAAI,MAAM;AAAA,MACnB,OAAO,IAAI,QAAQ,MAAM,KAAK,MAAM;AAAA,IACtC,CAAC;AAAA,EACH;AAEA,MAAI,cAAc;AAChB,iBAAa,KAAK,EAAE,SAAS,QAAQ,OAAO,OAAO,CAAC;AAAA,EACtD;AAGA,QAAM,UAAU,aAAa;AAAA,IAAI,CAAC,MAChC,EAAE,QAAQ,QAAQ,uBAAuB,MAAM;AAAA,EACjD;AACA,QAAM,QAAQ,IAAI,OAAO,IAAI,QAAQ,KAAK,GAAG,CAAC,KAAK,GAAG;AAEtD,QAAM,QAAQ,KAAK,MAAM,KAAK;AAG9B,QAAM,iBAAiB,IAAI,IAAI,aAAa,IAAI,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAE5E,SAAO,MAAM,QAAQ,CAAC,MAAM,MAAM;AAChC,UAAM,QAAQ,eAAe,IAAI,IAAI;AACrC,QAAI,OAAO;AAET,aACE,8CAAC,UAA0B,WAAU,iBAClC,mBADQ,WAAW,CAAC,EAEvB;AAAA,IAEJ;AAEA,WAAO,YAAY,MAAM,IAAI,CAAC,EAAE;AAAA,EAClC,CAAC;AACH;AAGO,IAAM,iBAAiD,eAAAA,QAAM,KAAK,CAAC,EAAE,QAAQ,MAAM;AACxF,QAAM,EAAE,cAAc,IAAI,cAAc;AAExC,QAAM,cAAU,wBAAgC,MAAM;AACpD,WAAO,aAAa,eAAe,KAAK;AAAA,EAC1C,GAAG,CAAC,eAAe,KAAK,CAAC;AAEzB,QAAM,cAAc,QAAQ,OACxB,uBAAuB,QAAQ,MAAM,SAAS,OAAO,IACrD;AAEJ,QAAM,0BAAsB,wBAAQ,MAAM;AACxC,QAAI,CAAC,QAAQ,eAAe,QAAQ,YAAY,WAAW,EAAG,QAAO,CAAC;AAEtE,UAAM,QAAQ,QAAQ,QAAQ,IAAI,KAAK;AACvC,UAAM,mBAAmB;AACzB,UAAM,YAAY,iBAAiB,KAAK,IAAI;AAE5C,WAAO,QAAQ,YAAY,OAAO,SAAO;AACvC,UAAI,cAAc,GAAG,EAAG,QAAO;AAC/B,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,aAAa,QAAQ,IAAI,CAAC;AAEtC,QAAM,iBAAiB,oBAAoB,SAAS;AAEpD,MAAI,gBAAgB;AAClB,WACE,+CAAC,SAAI,WAAU,2CACZ;AAAA,qBACC,8CAAC,UAAK,WAAU,iCAAiC,uBAAY;AAAA,MAE/D,8CAAC,kBAAe,aAAa,qBAAqB;AAAA,OACpD;AAAA,EAEJ;AAEA,SACE,+EACG,yBACC,8CAAC,UAAK,WAAU,iCAAiC,uBAAY,GAEjE;AAEJ,GAAG,CAAC,MAAM,SAAS;AACjB,SAAO,KAAK,QAAQ,OAAO,KAAK,QAAQ,MACtC,KAAK,QAAQ,eAAe,KAAK,QAAQ,cACzC,KAAK,QAAQ,SAAS,KAAK,QAAQ,QACnC,KAAK,iBAAiB,KAAK;AAC/B,CAAC;AACD,eAAe,cAAc;AAGtB,IAAM,gBAAgD,CAAC,EAAE,QAAQ,MAAM;AAC5E,QAAM,EAAE,cAAc,IAAI,cAAc;AAExC,QAAM,cAAU,wBAAgC,MAAM;AACpD,WAAO,aAAa,eAAe,KAAK;AAAA,EAC1C,GAAG,CAAC,eAAe,KAAK,CAAC;AAEzB,QAAM,iBAAa;AAAA,IACjB,MAAO,QAAQ,WAAO,2CAAmB,QAAQ,MAAM,OAAO,IAAI;AAAA,IAClE,CAAC,QAAQ,MAAM,OAAO;AAAA,EACxB;AAEA,SACE,8CAAC,UAAK,WAAU,mCACb,wBAAc,QAAQ,MACzB;AAEJ;AAGO,IAAM,gBAAgD,CAAC,EAAE,QAAQ,MAAM;AAC5E,QAAM,EAAE,OAAO,IAAI,cAAc;AAEjC,QAAM,UAAU,QAAQ,QAAQ;AAChC,QAAM,SAAS,cAAU,2CAAmB,SAAS,OAAO,UAAU,EAAE,IAAI;AAE5E,MAAI,CAAC,QAAQ;AACX,WACE,8CAAC,UAAK,WAAU,mCACb,mBACH;AAAA,EAEJ;AAEA,QAAM,YAAY,CAAC,CAAC,OAAO;AAC3B,QAAM,gBAAgB,YAAY,YAAY;AAC9C,QAAM,UAAU,OAAO,aAAa,gCAAS;AAE7C,SACE,+CAAC,SAAI,WAAU,wBACb;AAAA,kDAAC,SAAI,WAAW,0DAA0D,aAAa,IACpF,oBACC,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,wDAAC,UAAK,GAAE,iSAAgS,GAC1S,IAEA,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,oDAAC,aAAQ,QAAO,yBAAwB;AAAA,MACxC,8CAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,OACzD,GAEJ;AAAA,IACA,+CAAC,SAAI,WAAU,8BACb;AAAA,oDAAC,UAAK,WAAW,0DAA0D,aAAa,IACrF,iBAAO,MACV;AAAA,MACC,OAAO,YACN,8CAAC,UAAK,WAAU,kCAAkC,iBAAO,UAAS;AAAA,OAEtE;AAAA,KACF;AAEJ;AAGO,IAAM,cAA8C,CAAC,EAAE,QAAQ,MACpE,+CAAC,SAAI,WAAU,sBACb;AAAA,gDAAC,UAAK,WAAU,4BAA2B,uBAAE;AAAA,EAC7C,8CAAC,UAAK,WAAU,4BAA4B,kBAAQ,QAAQ,QAAO;AAAA,GACrE;AAIK,IAAM,iBAAiD,CAAC,EAAE,QAAQ,MAAM;AAC7E,QAAM,aAAc,QAAgB;AAEpC,QAAM,gBAAgB,aAAa,iBAAiB,UAAU,IAAI;AAClE,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,aAAa;AAClD,QAAM,SAAS,eAAAA,QAAM,OAAyB,IAAI;AAElD,8BAAQ,MAAM;AACZ,QAAI,WAAY,cAAa,UAAU;AAAA,EACzC,GAAG,CAAC,UAAU,CAAC;AAEf,iBAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,UAAU,OAAO,SAAS,UAAU;AACvC,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,QAAQ,UAAU,CAAC;AAEvB,MAAI,YAAY;AACd,WACE,+CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,OAAO,SAAS,QAAQ,SAAS,UAAU,SAAS,GACrF;AAAA,OAAC,UAAU,8CAAC,SAAI,WAAU,4BAA2B;AAAA,MACtD;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,WAAU;AAAA,UACV,KAAK;AAAA,UACL,KAAI;AAAA,UACJ,SAAQ;AAAA,UACR,QAAQ,MAAM,UAAU,IAAI;AAAA,UAC5B,OAAO,EAAE,SAAS,SAAS,IAAI,GAAG,YAAY,qBAAqB,UAAU,YAAY,KAAK,GAAG,MAAM,GAAG,OAAO,QAAQ,QAAQ,QAAQ,WAAW,UAAU;AAAA;AAAA,MAChK;AAAA,OACF;AAAA,EAEJ;AACA,SAAO,8CAAC,UAAK,WAAU,iCAAiC,kBAAQ,MAAK;AACvE;AAGO,IAAM,eAA+C,CAAC,EAAE,QAAQ,MACrE,8CAAC,UAAK,WAAU,uBAAuB,kBAAQ,QAAQ,kBAAiB;AAOnE,IAAM,0BAGT;AAAA,EACF,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AACT;;;AC/kBA,IAAAC,iBAAiE;AA4D3D,IAAAC,uBAAA;AAlDN,IAAM,2BAA6D,eAAAC,QAAM,KAAK,CAAC;AAAA,EAC7E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,cAAc,IAAI,cAAc;AACxC,QAAM,WAAW,QAAQ,MAAM,QAAQ,QAAQ,WAAW;AAC1D,QAAM,aAAa,QAAQ,MAAM;AACjC,QAAM,iBAAiB,QAAQ,eAAe,QAAQ,YAAY,SAAS;AAE3E,QAAM,cAAU,wBAAgC,MAAM;AACpD,WAAO,aAAa,eAAe,KAAK;AAAA,EAC1C,GAAG,CAAC,eAAe,KAAK,CAAC;AAEzB,MAAI,cAAc,QAAQ,QAAQ;AAClC,QAAM,YAAY,QAAQ,SAAS;AAEnC,MAAI,CAAC,eAAe,gBAAgB;AAClC,UAAM,cAAc,QAAQ,YAAa,CAAC;AAC1C,kBAAc,YAAY,SAAS,GAAG,YAAY,QAAQ,MAAM;AAAA,EAClE,WAAW,WAAW;AACpB,kBAAc;AAAA,EAChB;AAGA,MAAI,aAAa;AACf,kBAAc,0BAA0B,aAAa,SAAS,OAAO;AAAA,EACvE;AAGA,MAAI,aAAa;AACjB,MAAI,gBAAgB;AAClB,UAAM,OAAO,QAAQ,YAAa,CAAC,EAAE;AACrC,QAAI,SAAS,QAAS,cAAa;AAAA,aAC1B,SAAS,QAAS,cAAa;AAAA,aAC/B,SAAS,QAAS,cAAa;AAAA,QACnC,cAAa;AAAA,EACpB,WAAW,WAAW;AACpB,iBAAa;AAAA,EACf;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,+BAA+B,eAAe,qCAAqC,EAAE;AAAA,MAChG,SAAS,MAAM,iBAAiB,QAAQ,EAAE;AAAA,MAC1C,MAAK;AAAA,MACL,UAAU;AAAA,MAEV;AAAA,sDAAC,mBAAgB,OAAO,YAAY,MAAM,UAAU,MAAM,IAAI;AAAA,QAC9D,+CAAC,SAAI,WAAU,uCACb;AAAA,wDAAC,UAAK,WAAU,oCAAoC,oBAAS;AAAA,UAC7D,+CAAC,UAAK,WAAU,oCAAoC;AAAA;AAAA,YAAY,eAAe;AAAA,aAAa;AAAA,WAC9F;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,CAAC,MAAM;AAAE,gBAAE,gBAAgB;AAAG,wBAAU,QAAQ,EAAE;AAAA,YAAG;AAAA,YAC9D,OAAM;AAAA,YACN,cAAW;AAAA,YAEX,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,4DAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,cACpC,8CAAC,UAAK,GAAE,wDAAuD;AAAA,eACjE;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ,CAAC;AACD,yBAAyB,cAAc;AAKhC,IAAM,iBAAgD,eAAAA,QAAM,KAAK,CAAC;AAAA,EACvE;AAAA,EACA,kBAAkB;AAAA,EAClB,6BAA6B;AAAA,EAC7B;AAAA,EACA,eAAe;AACjB,MAAM;AACJ,QAAM,EAAE,eAAe,QAAQ,SAAS,IAAI,cAAc;AAC1D,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,KAAK;AAC9C,QAAM,gBAAgB,OAAO;AAG7B,gCAAU,MAAM;AACd,gBAAY,KAAK;AAAA,EACnB,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,qBAAiB,wBAAiC,MAAM;AAC5D,QAAI,CAAC,cAAe,QAAO,CAAC;AAC5B,UAAM,SAAU,cAAc,OAAe;AAC7C,WAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC;AAAA,EAC3C,GAAG,CAAC,eAAe,QAAQ,CAAC;AAE5B,QAAM,qBAAiB,4BAAY,MAAM;AACvC,gBAAY,CAAC,SAAS,CAAC,IAAI;AAAA,EAC7B,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAc,4BAAY,OAAO,cAAsB;AAC3D,QAAI,CAAC,cAAe;AACpB,QAAI;AACF,YAAM,cAAc,aAAa,SAAS;AAAA,IAC5C,SAAS,KAAK;AACZ,cAAQ,MAAM,2BAA2B,GAAG;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,MAAI,eAAe,WAAW,EAAG,QAAO;AAExC,QAAM,oBAAoB,WACtB,iBACA,eAAe,MAAM,GAAG,YAAY;AAExC,QAAM,UAAU,eAAe,SAAS;AAExC,SACE,+CAAC,SAAI,WAAW,wBAAwB,WAAW,qCAAqC,EAAE,GAAG,YAAY,IAAI,SAAS,KAAK,EAAE,IAE3H;AAAA,mDAAC,SAAI,WAAU,iCAAgC,SAAS,gBACtD;AAAA,oDAAC,SAAI,WAAU,+BAA8B,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,gBAC3F,wDAAC,UAAK,GAAE,wDAAuD,GACjE;AAAA,MACA,+CAAC,UAAK,WAAU,gCACb;AAAA,uBAAe;AAAA,QAAO;AAAA,QAAgB,eAAe,SAAS,IAAI,MAAM;AAAA,SAC3E;AAAA,MACC,WACC;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,CAAC,MAAM;AAAE,cAAE,gBAAgB;AAAG,2BAAe;AAAA,UAAG;AAAA,UAExD,qBAAW,aAAa;AAAA;AAAA,MAC3B;AAAA,OAEJ;AAAA,IAGA,8CAAC,SAAI,WAAU,+BACZ,4BAAkB,IAAI,CAAC,QACtB;AAAA,MAAC;AAAA;AAAA,QAEC,SAAS;AAAA,QACT,cAAc,IAAI,YAAY,iBAAiB,IAAI,MAAM,OAAO;AAAA,QAChE;AAAA,QACA,SAAS;AAAA,QACT;AAAA;AAAA,MALK,IAAI;AAAA,IAMX,CACD,GACH;AAAA,KACF;AAEJ,CAAC;AAED,eAAe,cAAc;;;ACpK7B,IAAAC,iBAAkB;AAkBR,IAAAC,uBAAA;AARV,IAAM,6BAAiE,eAAAC,QAAM,KAAK,CAAC;AAAA,EACjF;AAAA,EACA;AACF,MACE,8CAAC,SAAI,WAAU,wCACb,wDAAC,SAAI,WAAU,gCACZ,kBAAQ,IAAI,CAAC,WACZ,+CAAC,SAAoB,WAAU,qCAC7B;AAAA;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,OAAO;AAAA,MACd,MAAM,OAAO,QAAQ,OAAO;AAAA,MAC5B,MAAM;AAAA;AAAA,EACR;AAAA,EACA,+CAAC,SAAI,WAAU,qCACb;AAAA,kDAAC,UAAK,WAAU,qCAAqC,iBAAO,QAAQ,OAAO,IAAG;AAAA,IAC9E,8CAAC,UAAK,WAAU,qCAAqC,8BAAoB,OAAO,SAAS,GAAE;AAAA,KAC7F;AAAA,KATQ,OAAO,EAUjB,CACD,GACH,GACF,CACD;AACD,2BAA2B,cAAc;AAKlC,IAAM,eAA4C,eAAAA,QAAM,KAAK,CAAC;AAAA,EACnE;AAAA,EACA,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,cAAc;AAChB,MAAM;AAGJ,MAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AACpC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,QAAQ,MAAM,GAAG,UAAU;AAC3C,QAAM,WAAW,QAAQ,SAAS;AAElC,SACE,8CAAC,SAAI,WAAU,uBACb,yDAAC,SAAI,WAAU,gCACZ;AAAA,YAAQ,IAAI,CAAC,WACZ;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,OAAO;AAAA,QACd,MAAM,OAAO,QAAQ,OAAO;AAAA,QAC5B,MAAM;AAAA,QACN,WAAU;AAAA;AAAA,MAJL,OAAO;AAAA,IAKd,CACD;AAAA,IACA,WAAW,KACV,+CAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,MAAE;AAAA,OAAS;AAAA,IAE5D,eACC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA;AAAA,IACF;AAAA,KAEJ,GACF;AAEJ,CAAC;AAED,aAAa,cAAc;;;AC/E3B,IAAAC,iBAAkB;;;ACAlB,IAAAC,iBAA4C;AAgBrC,SAAS,qBAAqB;AACnC,QAAM,EAAE,eAAe,OAAO,IAAI,cAAc;AAChD,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAuB,CAAC,CAAC;AAC/D,QAAM,gBAAgB,OAAO;AAI7B,QAAM,mBAAe,uBAA6D,oBAAI,IAAI,CAAC;AAE3F,gCAAU,MAAM;AACd,QAAI,CAAC,eAAe;AAClB,qBAAe,CAAC,CAAC;AACjB,mBAAa,QAAQ,MAAM;AAC3B;AAAA,IACF;AAGA,iBAAa,QAAQ,MAAM;AAC3B,mBAAe,CAAC,CAAC;AAEjB,UAAM,YAAY,MAAM;AACtB,YAAM,QAAQ,MAAM,KAAK,aAAa,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AACzE,qBAAe,KAAK;AAAA,IACtB;AAEA,UAAM,oBAAoB,CAAC,UAAiB;AAC1C,YAAM,SAAS,MAAM,MAAM;AAC3B,UAAI,CAAC,UAAU,WAAW,cAAe;AAEzC,mBAAa,QAAQ,IAAI,QAAQ;AAAA,QAC/B,MAAM,EAAE,IAAI,QAAQ,MAAM,MAAM,MAAM,KAAK;AAAA,QAC3C,WAAW,KAAK,IAAI;AAAA,MACtB,CAAC;AACD,gBAAU;AAAA,IACZ;AAEA,UAAM,mBAAmB,CAAC,UAAiB;AACzC,YAAM,SAAS,MAAM,MAAM;AAC3B,UAAI,CAAC,OAAQ;AAEb,mBAAa,QAAQ,OAAO,MAAM;AAClC,gBAAU;AAAA,IACZ;AAEA,UAAM,OAAO,cAAc,GAAG,gBAAgB,iBAAiB;AAC/D,UAAM,OAAO,cAAc,GAAG,eAAe,gBAAgB;AAG7D,UAAM,kBAAkB,YAAY,MAAM;AACxC,YAAM,MAAM,KAAK,IAAI;AACrB,UAAI,UAAU;AACd,iBAAW,CAAC,KAAK,KAAK,KAAK,aAAa,QAAQ,QAAQ,GAAG;AACzD,YAAI,MAAM,MAAM,YAAY,KAAM;AAChC,uBAAa,QAAQ,OAAO,GAAG;AAC/B,oBAAU;AAAA,QACZ;AAAA,MACF;AACA,UAAI,QAAS,WAAU;AAAA,IACzB,GAAG,GAAI;AAEP,WAAO,MAAM;AACX,WAAK,YAAY;AACjB,WAAK,YAAY;AACjB,oBAAc,eAAe;AAC7B,mBAAa,QAAQ,MAAM;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,eAAe,aAAa,CAAC;AAEjC,SAAO,EAAE,YAAY;AACvB;;;AD7DQ,IAAAC,uBAAA;AAZD,IAAM,kBAAkD,eAAAC,QAAM,KAAK,CAAC,EAAE,WAAW,MAAM;AAC5F,QAAM,EAAE,YAAY,IAAI,mBAAmB;AAE3C,QAAM,WAAW,YAAY,SAAS;AAEtC,QAAM,OAAO,WACR,aAAa,WAAW,WAAW,IAAI,iBAAiB,WAAW,IACpE;AAEJ,SACE,8CAAC,SAAI,WAAW,yBAAyB,WAAW,oCAAoC,EAAE,IACvF,sBACC,gFACE;AAAA,mDAAC,SAAI,WAAU,gCACb;AAAA,oDAAC,UAAK,WAAU,+BAA8B;AAAA,MAC9C,8CAAC,UAAK,WAAU,+BAA8B;AAAA,MAC9C,8CAAC,UAAK,WAAU,+BAA8B;AAAA,OAChD;AAAA,IACA,8CAAC,UAAK,WAAU,gCAAgC,gBAAK;AAAA,KACvD,GAEJ;AAEJ,CAAC;AAED,gBAAgB,cAAc;AAQ9B,SAAS,iBAAiB,OAA6B;AACrD,QAAM,QAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE;AAE7C,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,GAAG,MAAM,CAAC,CAAC;AAAA,EACpB;AACA,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,GAAG,MAAM,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC;AAAA,EACpC;AACA,QAAM,YAAY,MAAM,SAAS;AACjC,SAAO,GAAG,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,QAAQ,SAAS,SAAS,YAAY,IAAI,MAAM,EAAE;AACnF;;;AhB3BE,IAAAC,uBAAA;AADF,IAAM,uBAAoD,eAAAC,QAAM,KAAK,CAAC,EAAE,MAAM,MAC5E,+CAAC,SAAI,WAAU,sCACb;AAAA,gDAAC,SAAI,WAAU,2CAA0C;AAAA,EACzD,8CAAC,UAAK,WAAU,4CAA4C,iBAAM;AAAA,EAClE,8CAAC,SAAI,WAAU,2CAA0C;AAAA,GAC3D,CACD;AACA,qBAA6B,cAAc;AAE5C,IAAM,sBAAsB,eAAAA,QAAM,KAAK,CAAC,EAAE,SAAS,QAAQ,wBAAmB,MAC5E,8CAAC,YAAO,WAAU,mCAAkC,SACjD,iBACH,CACD;AACD,oBAAoB,cAAc;AAElC,IAAMC,gBAAe,eAAAD,QAAM,KAAK,CAAC,EAAE,QAAQ,mBAAmB,WAAW,2CAA2C,MAClH,+CAAC,SAAI,WAAU,6BACb;AAAA,gDAAC,SAAI,WAAU,kCACb,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI,wDAAC,UAAK,GAAE,iEAAgE,GAC1E,GACF;AAAA,EACA,8CAAC,UAAK,WAAU,mCAAmC,iBAAM;AAAA,EACzD,8CAAC,UAAK,WAAU,sCAAsC,oBAAS;AAAA,GACjE,CACD;AACDC,cAAa,cAAc;AAE3B,IAAM,gBAA8C,eAAAD,QAAM,KAAK,CAAC;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAW,wBAAwB,eAAe,8BAA8B,6BAA6B;AAAA,IAE5G;AAAA,eAAS,UACR,8CAAC,SAAI,WAAW,wCAAwC,eAAe,8CAA8C,6CAA6C,IAChK,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,gBACnD,wDAAC,UAAK,GAAE,wDAAuD,GACjE,GACF;AAAA,MAED;AAAA;AAAA;AACH,CACD;AACA,cAAsB,cAAc;AAK9B,IAAM,qBAAiD,eAAAA,QAAM,KAAK,CAAC;AAAA,EACxE;AAAA,EACA;AAAA,EACA,sBAAsBC;AAAA,EACtB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,6BAA6B;AAAA,EAC7B,qBAAqB;AAAA,EACrB,gCAAgC;AAAA,EAChC;AAAA,EACA,qBAAqB;AAAA,EACrB,0BAA0B;AAAA,EAC1B,mBAAmB;AAAA,EACnB,wBAAwB;AAAA,EACxB;AAAA,EACA,yBAAyB;AAAA,EACzB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA,EAC3B;AAAA,EACA,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,sBAAsB;AAAA,EACtB,yBAAyB;AAAA,EACzB,sBAAsB;AAAA,EACtB,yBAAyB;AAAA,EACzB,qBAAqB;AAAA,EACrB,qBAAqB;AACvB,MAAM;AACJ,QAAM,EAAE,QAAQ,UAAU,WAAW,eAAe,iBAAiB,mBAAmB,IAAI,cAAc;AAC1G,QAAM,EAAE,SAAS,IAAI,eAAe,eAAe,OAAO,MAAM;AAChE,QAAM,EAAE,UAAU,IAAI,gBAAgB,eAAe,OAAO,MAAM;AAClE,QAAM,EAAE,UAAU,IAAI,gBAAgB,eAAe,OAAO,MAAM;AAElE,QAAM,EAAE,aAAa,aAAa,IAAI,kBAAkB,aAAa;AAErE,QAAM,eAAW,uBAAoB,IAAI;AACzC,QAAM,kBAAc,uBAAO,QAAQ;AACnC,cAAY,UAAU;AACtB,QAAM,gBAAgB,OAAO;AAG7B,QAAM,mBAAe,uBAAuB,IAAI;AAChD,QAAM,sBAAkB,4BAAY,MAA0B;AAC5D,WAAO,aAAa,SAAS,cAAc,4BAA4B,KAAK;AAAA,EAC9E,GAAG,CAAC,CAAC;AAEL,QAAM,yBAAqB,4BAAY,YAAY;AACjD,QAAI,CAAC,cAAe;AACpB,QAAI;AACF,YAAM,eAAe,cAAc,SAAS,UAAU,QAAQ,cAAc,MAAM,MAAM;AACxF,YAAM,SAAS,eAAe,SAAS;AACvC,YAAM,cAAc,aAAa,MAAM;AAAA,IACzC,SAAS,GAAQ;AACf,cAAQ,MAAM,0BAA0B,CAAC;AAAA,IAC3C;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,yBAAqB,4BAAY,MAAM;AAC3C,QAAI,CAAC,cAAe;AACpB,kBAAc,aAAa,EAAE,MAAM,CAAC,MAAW,QAAQ,MAAM,0BAA0B,CAAC,CAAC;AAAA,EAC3F,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,qBAAiB,4BAAY,CAAC,SAAS,OAAO,WAAW,MAAM;AACnE,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AAEb,UAAM,QAAQ,YAAY,QAAQ;AAClC,QAAI,UAAU,EAAG;AAIjB,SAAK,CAAC,OAAO,gBAAgB,OAAO,iBAAiB,MAAM,WAAW,IAAI;AACxE,4BAAsB,MAAM,eAAe,QAAQ,WAAW,CAAC,CAAC;AAChE;AAAA,IACF;AAEA,WAAO,cAAc,QAAQ,GAAG,EAAE,OAAO,OAAO,OAAO,CAAC;AAAA,EAC1D,GAAG,CAAC,CAAC;AAGL,QAAM,iBAAa,uBAAO,KAAK;AAG/B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IAAS;AAAA,IACT;AAAA,IAAU;AAAA,IACV;AAAA,IAAgB;AAAA,IAChB;AAAA,IACA;AAAA,EACF,IAAI,gBAAgB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,EAAE,eAAe,iBAAiB,aAAa,IAAI,mBAAmB;AAAA,IAC1E;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,gCAAU,MAAM;AACd,QAAI,iBAAiB;AACnB,sBAAgB,eAAe;AAC/B,yBAAmB,IAAI;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,iBAAiB,iBAAiB,kBAAkB,CAAC;AAEzD,qBAAmB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA,qBAAiB,4BAAY,MAAM;AACjC,iBAAW,IAAI;AACf,kBAAY,KAAK;AACjB,qBAAe,UAAU;AACzB,sBAAgB,UAAU;AAAA,IAC5B,GAAG,CAAC,YAAY,WAAW,CAAC;AAAA,EAC9B,CAAC;AAED,QAAM,gBAAY;AAAA,IAChB,OAAO,EAAE,GAAG,yBAAyB,GAAG,gBAAgB;AAAA,IACxD,CAAC,eAAe;AAAA,EAClB;AAGA,QAAM,gBAAY,wBAAQ,MAAM;AAC9B,UAAM,MAAwG,CAAC;AAC/G,QAAI,CAAC,UAAW,QAAO;AACvB,eAAW,UAAU,OAAO,KAAK,SAAS,GAAG;AAC3C,UAAI,WAAW,cAAe;AAC9B,YAAM,QAAQ,UAAU,MAAM;AAC9B,UAAI,MAAM,sBAAsB;AAC9B,YAAI,CAAC,IAAI,MAAM,oBAAoB,GAAG;AACpC,cAAI,MAAM,oBAAoB,IAAI,CAAC;AAAA,QACrC;AACA,YAAI,MAAM,oBAAoB,EAAE,KAAK;AAAA,UACnC,IAAI;AAAA,UACJ,MAAM,MAAM,MAAM;AAAA,UAClB,QAAQ,MAAM,MAAM;AAAA,UACpB,WAAW,MAAM;AAAA,QACnB,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT,GAAG,CAAC,WAAW,aAAa,CAAC;AAG7B,QAAM,sBAAkB,wBAAQ,MAAM;AACpC,WAAO,SAAS,IAAI,CAAC,SAAS,UAAU;AACtC,YAAM,eACJ,QAAQ,YAAY,iBAAiB,QAAQ,MAAM,OAAO;AAC5D,YAAM,cAAe,QAAQ,QAAQ;AAGrC,YAAM,UAAU,QAAQ,IAAI,SAAS,QAAQ,CAAC,IAAI;AAClD,YAAM,oBACJ,CAAC,WAAW,WAAW,QAAQ,UAAU,MAAM,WAAW,QAAQ,UAAU;AAC9E,YAAM,gBAAgB,oBACpB,8CAAC,0BAAuB,OAAO,gBAAgB,QAAQ,UAAU,GAAG,IAClE;AAEJ,UAAI,eAAe;AACjB,eACE,+CAAC,SACE;AAAA;AAAA,UACD,8CAAC,SAAK,wBAAc,SAAS,YAAY,GAAE;AAAA,aAFnC,QAAQ,MAAM,OAAO,KAAK,EAGpC;AAAA,MAEJ;AAEA,UAAI,gBAAgB,UAAU;AAC5B,eACE,+CAAC,SACE;AAAA;AAAA,UACD;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA,gBAAgB,UAAU;AAAA;AAAA,UAC5B;AAAA,aANQ,QAAQ,MAAM,OAAO,KAAK,EAOpC;AAAA,MAEJ;AAGA,YAAM,WAAY,SAAS,QAAQ;AACnC,YAAM,iBACJ,qBACA,CAAC,WACD,aAAa,YACb,aAAa,YACb,iBAAiB,OAAO,MAAM,iBAAiB,OAAO;AAExD,YAAM,UAAU,QAAQ,SAAS,SAAS,IAAI,SAAS,QAAQ,CAAC,IAAI;AACpE,YAAM,WAAY,SAAS,QAAQ;AACnC,YAAM,wBAAwB,UAC1B,WAAW,QAAQ,UAAU,MAAM,WAAW,QAAQ,UAAU,IAChE;AAEJ,YAAM,gBACJ,CAAC,WACD,yBACA,aAAa,YACb,aAAa,YACb,iBAAiB,OAAO,MAAM,iBAAiB,OAAO;AAExD,YAAM,kBAAkB,UAAU,WAAW,KAAK,UAAU;AAE5D,aACE,+CAAC,SACE;AAAA;AAAA,QACD;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,eAAe,kBAAkB,QAAQ;AAAA,YACzC;AAAA,YACA;AAAA,YACA;AAAA,YACA,cAAc;AAAA,YACd;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF;AAAA,QAEC,oBACC;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,UAAU,QAAQ,EAAG,KAAK,CAAC;AAAA,YACpC,YAAY;AAAA,YACZ;AAAA,YACA,kBAAkB;AAAA,YAClB;AAAA,YACA;AAAA,YACA,QAAQ,QAAQ;AAAA;AAAA,QAClB;AAAA,WA1BM,QAAQ,MAAM,OAAO,KAAK,EA4BpC;AAAA,IAEJ,CAAC;AAAA,EACH,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,eAAe,YAAY,iCAAiC;AAElE,SACE,+CAAC,SAAI,KAAK,cAAc,WAAW,qBAAqB,WAAW,gCAAgC,EAAE,GAAG,YAAY,GAAG,YAAY,IAAI,SAAS,KAAK,EAAE,IACpJ;AAAA,KAAC,YAAY,CAAC,aAAa,sBAAsB,8CAAC,2BAAwB,gBAAgB,iBAAiB,iBAAkC;AAAA,IAE7I,SAAS,WAAW,KAAK,CAAC,YAAY,CAAC,cACtC,wBAAwBA,gBACpB,8CAACA,eAAA,EAAa,OAAO,YAAY,UAAU,eAAe,IAC1D,8CAAC,uBAAoB;AAAA,IAI3B;AAAA,MAAC;AAAA;AAAA,QAEC,KAAK;AAAA,QACL,OAAO;AAAA,QACP,UAAU;AAAA,QACV,WAAU;AAAA,QAET,uBAAa,CAAC,YAAY,CAAC,YAC1B,8CAAC,SAAI,WAAU,uCACb,yDAAC,SAAI,WAAU,oCACb;AAAA,wDAAC,UAAO,OAAO,cAAc,MAAM,aAAa,MAAM,IAAI,WAAU,sCAAqC;AAAA,UACzG,8CAAC,UAAK,WAAU,6CAA6C,+BAAoB;AAAA,UACjF,8CAAC,SAAI,WAAU,4CAA4C,uBAAY;AAAA,UACvE,8CAAC,UAAK,WAAU,gDAAgD,kCAAuB;AAAA,UACvF,+CAAC,SAAI,WAAU,uCACb;AAAA,0DAAC,YAAO,WAAU,kCAAiC,SAAS,oBAAqB,8BAAmB;AAAA,YACpG,8CAAC,YAAO,WAAU,kCAAiC,SAAS,oBAAqB,8BAAmB;AAAA,aACtG;AAAA,WACF,GACF,KACG,YAAY,cAAc,CAAC,YAC9B,+CAAC,SAAI,WAAU,sCACb;AAAA,wDAAC,SAAI,WAAU,2CACb,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI;AAAA,0DAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,YAC/B,8CAAC,UAAK,IAAG,QAAO,IAAG,QAAO,IAAG,SAAQ,IAAG,SAAQ;AAAA,aAClD,GACF;AAAA,UACA,8CAAC,UAAK,WAAU,4CAA4C,sBAAY,sBAAsB,oBAAmB;AAAA,UACjH,8CAAC,UAAK,WAAU,+CAA+C,sBAAY,yBAAyB,uBAAsB;AAAA,UACzH,aAAa,iBACZ;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM;AAAE,8BAAc,YAAY,EAAE,MAAM,CAAC,MAAW,QAAQ,MAAM,yBAAyB,CAAC,CAAC;AAAA,cAAG;AAAA,cAC5G;AAAA;AAAA,UAED;AAAA,WAEJ,IACE;AAAA;AAAA,MAtCC,eAAe,OAAO;AAAA,IAuC7B;AAAA,IAGC,CAAC,YAAY,CAAC,aAAa,CAAC,aAAa,uBAAuB,8CAAC,4BAAyB;AAAA,IAG1F,CAAC,YAAY,CAAC,aAAa,CAAC,aAAa,aACxC,uBAAuB,sBACnB,8CAAC,uBAAoB,SAAS,cAAc,OAAO,mBAAmB,IACtE,8CAAC,sBAAmB,SAAS,cAAc;AAAA,KAEnD;AAEJ,CAAC;AAED,mBAAmB,cAAc;;;AkBxajC,IAAAC,iBAAyE;;;ACAzE,IAAAC,iBAAyE;AAWlE,IAAM,qBAAqB;AAK3B,SAAS,eAAe,QAAgB,aAA6B;AAC1E,QAAM,WAAW,YAAY,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM;AAC9F,SAAO,gBAAgB,kBAAkB,sBAAsB,MAAM,8BAA8B,QAAQ;AAC7G;AAMA,SAAS,sBACP,YACA,QACA,aACA;AACA,QAAM,MAAM,OAAO,aAAa;AAChC,MAAI,CAAC,OAAO,IAAI,eAAe,EAAG;AAElC,QAAM,QAAQ,IAAI,WAAW,CAAC;AAE9B,QAAM,EAAE,gBAAgB,YAAY,IAAI;AACxC,MAAI,eAAe,aAAa,KAAK,WAAW;AAC9C,UAAM,aAAa,eAAe,aAAa,MAAM,GAAG,WAAW,KAAK;AACxE,UAAM,UAAU,WAAW,YAAY,GAAG;AAC1C,QAAI,YAAY,IAAI;AAClB,YAAM,SAAS,gBAAgB,OAAO;AACtC,YAAM,eAAe;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,OAAK,YAAY;AACjB,OAAK,aAAa,mBAAmB,MAAM;AAC3C,OAAK,kBAAkB;AACvB,OAAK,cAAc,IAAI,WAAW;AAElC,QAAM,WAAW,IAAI;AAErB,QAAM,QAAQ,SAAS,eAAe,MAAQ;AAC9C,OAAK,MAAM,KAAK;AAChB,qBAAmB,KAAK;AAExB,aAAW,cAAc,IAAI,MAAM,SAAS,EAAE,SAAS,KAAK,CAAC,CAAC;AAChE;AAKA,SAAS,oBAAoB,YAAyC;AACpE,MAAI,OAAO;AACX,MAAI,eAAe;AACnB,QAAM,iBAA2B,CAAC;AAElC,WAAS,KAAK,MAAY;AACxB,QAAI,KAAK,aAAa,KAAK,WAAW;AACpC,cAAQ,KAAK,eAAe;AAC5B;AAAA,IACF;AAEA,QAAI,gBAAgB,aAAa;AAC/B,YAAM,YAAY,KAAK,aAAa,iBAAiB;AACrD,UAAI,aAAa,KAAK,UAAU,SAAS,kBAAkB,GAAG;AAC5D,YAAI,cAAc,WAAW;AAC3B,yBAAe;AACf,kBAAQ;AAAA,QACV,OAAO;AACL,cAAI,CAAC,eAAe,SAAS,SAAS,GAAG;AACvC,2BAAe,KAAK,SAAS;AAAA,UAC/B;AACA,kBAAQ,IAAI,SAAS;AAAA,QACvB;AACA;AAAA,MACF;AAEA,UAAI,KAAK,YAAY,MAAM;AACzB,gBAAQ;AACR;AAAA,MACF;AAEA,UAAI,KAAK,YAAY,SAAS,KAAK,SAAS,KAAK,CAAC,KAAK,SAAS,IAAI,GAAG;AACrE,gBAAQ;AAAA,MACV;AAAA,IACF;AAEA,SAAK,WAAW,QAAQ,IAAI;AAAA,EAC9B;AAEA,OAAK,UAAU;AACf,SAAO,KAAK,QAAQ,WAAW,GAAG,EAAE,KAAK;AAEzC,SAAO,EAAE,MAAM,eAAe,cAAc,iBAAiB,eAAe;AAC9E;AAKA,SAAS,oBAAoB,YAAsC;AACjE,QAAM,MAAM,oBAAI,IAAY;AAC5B,QAAM,QAAQ,WAAW,iBAAiB,IAAI,kBAAkB,EAAE;AAClE,QAAM,QAAQ,CAAC,SAAS;AACtB,UAAM,KAAK,KAAK,aAAa,iBAAiB;AAC9C,QAAI,GAAI,KAAI,IAAI,EAAE;AAAA,EACpB,CAAC;AACD,SAAO;AACT;AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,yBAAS,KAAK;AAC5D,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAS,EAAE;AACrC,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAAS,CAAC;AACtD,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,yBAAsB,oBAAI,IAAI,CAAC;AAE/E,QAAM,oBAAgB,iCAAiB,KAAK;AAG5C,QAAM,cAAyB;AAAA,IAC7B,OAAO,EAAE,IAAI,WAAW,MAAM,MAAM;AAAA,IACpC,CAAC;AAAA,EACH;AAGA,QAAM,sBAAkB,wBAAQ,MAAM;AACpC,UAAM,IAAI,cAAc,YAAY;AAGpC,UAAM,SAA0B,CAAC;AACjC,QAAI,CAAC,iBAAiB,IAAI,SAAS,GAAG;AACpC,UAAI,CAAC,KAAK,MAAM,SAAS,CAAC,GAAG;AAC3B,eAAO,KAAK,OAAO;AAAA,MACrB;AAAA,IACF;AAEA,eAAW,KAAK,SAAS;AACvB,UAAI,EAAE,OAAO,cAAe;AAC5B,UAAI,iBAAiB,IAAI,EAAE,EAAE,EAAG;AAChC,UAAI,KAAK,CAAC,EAAE,KAAK,YAAY,EAAE,SAAS,CAAC,EAAG;AAC5C,aAAO,KAAK,CAAC;AAAA,IACf;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,eAAe,kBAAkB,eAAe,OAAO,CAAC;AAGrE,QAAM,oBAAgB,4BAAY,MAA6C;AAC7E,UAAM,MAAM,OAAO,aAAa;AAChC,QAAI,CAAC,OAAO,IAAI,eAAe,KAAK,CAAC,IAAI,aAAa;AACpD,aAAO,EAAE,WAAW,OAAO,OAAO,GAAG;AAAA,IACvC;AAEA,UAAM,EAAE,YAAY,aAAa,IAAI;AACrC,QAAI,CAAC,cAAc,WAAW,aAAa,KAAK,WAAW;AACzD,aAAO,EAAE,WAAW,OAAO,OAAO,GAAG;AAAA,IACvC;AAEA,UAAM,aAAa,WAAW,aAAa,MAAM,GAAG,YAAY,KAAK;AAGrE,UAAM,QAAQ,WAAW,MAAM,uBAAuB;AACtD,QAAI,CAAC,OAAO;AACV,aAAO,EAAE,WAAW,OAAO,OAAO,GAAG;AAAA,IACvC;AAEA,WAAO,EAAE,WAAW,MAAM,OAAO,MAAM,CAAC,EAAE;AAAA,EAC5C,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAc,4BAAY,MAAM;AACpC,UAAM,KAAK,YAAY;AACvB,QAAI,CAAC,GAAI;AAGT,wBAAoB,oBAAoB,EAAE,CAAC;AAG3C,UAAM,SAAS,cAAc;AAC7B,QAAI,OAAO,WAAW;AACpB,yBAAmB,IAAI;AACvB,eAAS,OAAO,KAAK;AACrB,wBAAkB,CAAC;AAAA,IACrB,OAAO;AACL,yBAAmB,KAAK;AACxB,eAAS,EAAE;AAAA,IACb;AAAA,EACF,GAAG,CAAC,aAAa,aAAa,CAAC;AAE/B,QAAM,oBAAgB;AAAA,IACpB,CAAC,WAA0B;AACzB,YAAM,KAAK,YAAY;AACvB,UAAI,CAAC,GAAI;AAET,4BAAsB,IAAI,OAAO,IAAI,OAAO,IAAI;AAGhD,0BAAoB,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,IAAI,OAAO,EAAE,CAAC;AAC1D,yBAAmB,KAAK;AACxB,eAAS,EAAE;AAGX,SAAG,MAAM;AAAA,IACX;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,oBAAgB;AAAA,IACpB,CAAC,MAAoC;AACnC,UAAI,CAAC,mBAAmB,gBAAgB,WAAW,EAAG,QAAO;AAE7D,cAAQ,EAAE,KAAK;AAAA,QACb,KAAK;AACH,YAAE,eAAe;AACjB;AAAA,YAAkB,CAAC,SACjB,OAAO,gBAAgB,SAAS,IAAI,OAAO,IAAI;AAAA,UACjD;AACA,iBAAO;AAAA,QAET,KAAK;AACH,YAAE,eAAe;AACjB;AAAA,YAAkB,CAAC,SACjB,OAAO,IAAI,OAAO,IAAI,gBAAgB,SAAS;AAAA,UACjD;AACA,iBAAO;AAAA,QAET,KAAK;AACH,YAAE,eAAe;AACjB,cAAI,gBAAgB,cAAc,GAAG;AACnC,0BAAc,gBAAgB,cAAc,CAAC;AAAA,UAC/C;AACA,iBAAO;AAAA,QAET,KAAK;AACH,YAAE,eAAe;AACjB,6BAAmB,KAAK;AACxB,iBAAO;AAAA,QAET;AACE,iBAAO;AAAA,MACX;AAAA,IACF;AAAA,IACA,CAAC,iBAAiB,iBAAiB,gBAAgB,aAAa;AAAA,EAClE;AAEA,QAAM,mBAAe,4BAAY,MAAsB;AACrD,UAAM,KAAK,YAAY;AACvB,QAAI,CAAC,GAAI,QAAO,EAAE,MAAM,IAAI,eAAe,OAAO,iBAAiB,CAAC,EAAE;AACtE,WAAO,oBAAoB,EAAE;AAAA,EAC/B,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,YAAQ,4BAAY,MAAM;AAC9B,uBAAmB,KAAK;AACxB,aAAS,EAAE;AACX,sBAAkB,CAAC;AACnB,wBAAoB,oBAAI,IAAI,CAAC;AAC7B,UAAM,KAAK,YAAY;AACvB,QAAI,IAAI;AACN,SAAG,YAAY;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC9RA,IAAAC,iBAA8C;AAC9C,IAAAC,yBAA2D;AAI3D,IAAI,iBAAiB;AACrB,SAAS,aAAqB;AAC5B,SAAO,QAAQ,KAAK,IAAI,CAAC,IAAI,EAAE,cAAc;AAC/C;AAQO,SAAS,cAAc,EAAE,eAAe,aAAa,cAAc,GAAyB;AACjG,QAAM,mBAAe,uBAAyB,IAAI;AAClD,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAA4B,CAAC,CAAC;AASxD,QAAM,uBAAmB,4BAAY,OAAO,SAA0B;AACpE,QAAI,CAAC,cAAe;AAEpB,QAAI;AACF,YAAM,OAAO,KAAK;AAClB,YAAM,qBAAiB,0CAAkB,KAAK,IAAI;AAClD,YAAM,eAAe,mBAAmB,KAAK,OACzC,IAAI,KAAK,CAAC,IAAI,GAAG,gBAAgB,EAAE,MAAM,KAAK,MAAM,cAAc,KAAK,aAAa,CAAC,IACrF;AAEJ,YAAM,WAAW,MAAM,cAAc,SAAS,cAAc,aAAa,MAAM,aAAa,IAAI;AAChG,YAAM,cAAc,SAAS;AAE7B,UAAI,WAAW;AACf,cAAI,oCAAY,IAAI,GAAG;AACrB,YAAI;AACF,gBAAM,YAAY,MAAM,cAAc,kBAAkB,IAAI;AAC5D,cAAI,WAAW;AACb,kBAAM,YAAY,IAAI,KAAK,CAAC,SAAS,GAAG,SAAS,cAAc,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7F,kBAAM,YAAY,MAAM,cAAc,SAAS,WAAW,UAAU,MAAM,YAAY;AACtF,uBAAW,UAAU;AAAA,UACvB;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AAEA;AAAA,QAAS,CAAC,SACR,KAAK;AAAA,UAAI,CAAC,MACR,EAAE,OAAO,KAAK,KACV,EAAE,GAAG,GAAG,QAAQ,QAAiB,aAAa,UAAU,gBAAgB,aAAa,IACrF;AAAA,QACN;AAAA,MACF;AAAA,IACF,SAAS,KAAU;AACjB;AAAA,QAAS,CAAC,SACR,KAAK;AAAA,UAAI,CAAC,MACR,EAAE,OAAO,KAAK,KACV,EAAE,GAAG,GAAG,QAAQ,SAAkB,OAAO,KAAK,WAAW,gBAAgB,IACzE;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,0BAAsB,4BAAY,CAAC,kBAAmC;AAC1E,QAAI,CAAC,iBAAiB,cAAc,WAAW,EAAG;AAElD,UAAM,WAA8B,MAAM,KAAK,aAAa,EAAE,IAAI,CAAC,SAAS;AAC1E,YAAM,gBACH,KAAK,KAAK,WAAW,QAAQ,KAAK,KAAC,mCAAW,IAAI,KACnD,KAAK,KAAK,WAAW,QAAQ;AAC/B,aAAO;AAAA,QACL,IAAI,WAAW;AAAA,QACf;AAAA,QACA,YAAY,gBAAgB,IAAI,gBAAgB,IAAI,IAAI;AAAA,QACxD,QAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAED,aAAS,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,QAAQ,CAAC;AACzC,kBAAc,IAAI;AAElB,aAAS,QAAQ,CAAC,SAAS,iBAAiB,IAAI,CAAC;AAAA,EACnD,GAAG,CAAC,kBAAkB,aAAa,CAAC;AAEpC,QAAM,uBAAmB,4BAAY,CAAC,OAAe;AACnD,aAAS,CAAC,SAAS;AACjB,YAAM,OAAO,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACzC,UAAI,MAAM,WAAY,KAAI,gBAAgB,KAAK,UAAU;AACzD,YAAM,YAAY,KAAK,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAChD,YAAM,KAAK,YAAY;AACvB,YAAM,cAAc,IAAI,aAAa,KAAK,KAAK;AAC/C,UAAI,UAAU,WAAW,KAAK,YAAY,WAAW,GAAG;AACtD,sBAAc,KAAK;AAAA,MACrB;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,aAAa,aAAa,CAAC;AAE/B,QAAM,wBAAoB,4BAAY,MAAM;AAC1C,iBAAa,SAAS,MAAM;AAAA,EAC9B,GAAG,CAAC,CAAC;AAGL,QAAM,mBAAe,4BAAY,MAAM;AACrC,UAAM,QAAQ,CAAC,MAAM;AACnB,UAAI,EAAE,WAAY,KAAI,gBAAgB,EAAE,UAAU;AAAA,IACpD,CAAC;AAAA,EACH,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC/HA,IAAAC,iBAA8C;AAQvC,SAAS,eAAe,EAAE,aAAa,cAAc,GAA0B;AACpF,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,yBAAS,KAAK;AAC5D,QAAM,oBAAgB,uBAAqB,IAAI;AAE/C,QAAM,wBAAoB,4BAAY,CAAC,UAAkB;AACvD,UAAM,KAAK,YAAY;AACvB,QAAI,CAAC,GAAI;AAGT,OAAG,MAAM;AACT,UAAM,MAAM,OAAO,aAAa;AAChC,QAAI,OAAO,cAAc,SAAS;AAChC,UAAI,gBAAgB;AACpB,UAAI,SAAS,cAAc,OAAO;AAClC,oBAAc,UAAU;AAAA,IAC1B,OAAO;AACL,qBAAe,EAAE;AAAA,IACnB;AAEA,aAAS,YAAY,cAAc,OAAO,QAAQ,GAAG;AACrD,kBAAc,IAAI;AAClB,uBAAmB,KAAK;AAAA,EAC1B,GAAG,CAAC,aAAa,aAAa,CAAC;AAE/B,QAAM,uBAAmB,4BAAY,MAAM;AACzC,uBAAmB,KAAK;AACxB,kBAAc,UAAU;AAAA,EAC1B,GAAG,CAAC,CAAC;AAEL,QAAM,wBAAoB,4BAAY,MAAM;AAE1C,UAAM,MAAM,OAAO,aAAa;AAChC,QAAI,OAAO,IAAI,aAAa,GAAG;AAC7B,oBAAc,UAAU,IAAI,WAAW,CAAC,EAAE,WAAW;AAAA,IACvD;AACA,uBAAmB,CAAC,SAAS,CAAC,IAAI;AAAA,EACpC,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACpDA,IAAAC,iBAA8C;AAC9C,IAAAC,yBAAuC;AA2BhC,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,KAAK;AAC5C,QAAM,sBAAkB,uBAAO,KAAK;AAEpC,QAAM,iBAAa,4BAAY,YAAY;AACzC,QAAI,CAAC,iBAAiB,CAAC,cAAc,WAAW,gBAAgB,QAAS;AAGzE,UAAM,iBAAiB,MAAM,KAAK,CAAC,MAAM,EAAE,WAAW,WAAW;AACjE,QAAI,eAAgB;AAEpB,oBAAgB,UAAU;AAE1B,UAAM,UAAU,aAAa;AAC7B,UAAM,OAAO,QAAQ,KAAK,KAAK;AAC/B,UAAM,gBAAgB,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAE7D,QAAI,CAAC,QAAQ,cAAc,WAAW,EAAG;AAGzC,QAAI,cAAc;AAChB,YAAM,UAAU,MAAM,aAAa,MAAM,aAAa;AACtD,UAAI,CAAC,SAAS;AACZ,wBAAgB,UAAU;AAC1B;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,iBAAW,IAAI;AAGf,YAAM,cAAc,cAAc,IAAI,CAAC,MAAM;AAC3C,YAAI,EAAE,oBAAoB;AACxB,iBAAO,EAAE;AAAA,QACX;AACA,cAAM,UAAU,EAAE,kBAAkB,EAAE;AACtC,mBAAO,+CAAuB,SAAS,EAAE,aAAc,EAAE,QAAQ;AAAA,MACnE,CAAC;AAGD,YAAM,UAA+B,EAAE,KAAK;AAG5C,UAAI,CAAC,kBAAkB,YAAY,SAAS,GAAG;AAC7C,gBAAQ,cAAc;AAAA,MACxB;AAEA,UAAI,eAAe;AACjB,gBAAQ,gBAAgB,QAAQ;AAChC,gBAAQ,kBAAkB,QAAQ;AAAA,MACpC;AACA,UAAI;AAEJ,UAAI,gBAAgB,IAAI;AACtB,sBAAc,cAAc,YAAY,eAAe,IAAI,OAAc;AAAA,MAC3E,OAAO;AACL,YAAI,eAAe,IAAI;AACrB,kBAAQ,oBAAoB,cAAc;AAAA,QAC5C;AACA,sBAAc,cAAc,YAAY,OAAc;AAAA,MACxD;AAIA,mBAAa;AAIb,YAAM,QAAQ,CAAC,MAAM;AACnB,YAAI,EAAE,WAAY,KAAI,gBAAgB,EAAE,UAAU;AAAA,MACpD,CAAC;AAED,YAAM,aAAa,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO;AAC3D,eAAS,UAAU;AACnB,oBAAc,WAAW,SAAS,CAAC;AAEnC,YAAM;AACN,2BAAqB;AACrB,4BAAsB;AACtB,eAAS,QAAQ,IAAI;AAErB,qBAAe,WAAW;AAK1B,kBAAY,MAAM,CAAC,QAAe;AAChC,gBAAQ,MAAM,oCAAoC,GAAG;AAErD,qBAAa;AAAA,MACf,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,mCAAmC,GAAG;AAAA,IACtD,UAAE;AACA,sBAAgB,UAAU;AAC1B,iBAAW,KAAK;AAChB,4BAAsB,MAAM;AAC1B,oBAAY,SAAS,MAAM;AAAA,MAC7B,CAAC;AAAA,IACH;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,EAAE,SAAS,WAAW;AAC/B;;;ACnKA,IAAAC,iBAAkB;AAUhB,IAAAC,uBAAA;AAJK,IAAM,oBAA0E,eAAAC,QAAM,KAAK,CAAC;AAAA,EACjG;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAU;AAAA,IACV;AAAA,IACA;AAAA,IACD;AAAA;AAED,CACD;AACD,kBAAkB,cAAc;AAEzB,IAAM,sBAA4E,eAAAA,QAAM,KAAK,CAAC;AAAA,EACnG;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAU;AAAA,IACV;AAAA,IACA,MAAK;AAAA,IACL,cAAW;AAAA,IACX;AAAA,IACD;AAAA;AAED,CACD;AACD,oBAAoB,cAAc;AAE3B,IAAM,qBAAyE,eAAAA,QAAM,KAAK,CAAC;AAAA,EAChG;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA;AAAA,IACC,WAAW,iCAAiC,SAAS,4CAA4C,EAAE;AAAA,IACnG;AAAA,IACA,MAAK;AAAA,IACL,cAAW;AAAA,IACZ;AAAA;AAED,CACD;AACD,mBAAmB,cAAc;;;ACjDjC,IAAAC,iBAAyC;AACzC,IAAAC,iBAAmC;AA+BzB,IAAAC,uBAAA;AAxBV,IAAM,cAAc;AAEb,IAAM,qBAAwD,eAAAC,QAAM,KAAK,CAAC;AAAA,EAC/E;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,cAAU,uBAAoB,IAAI;AAGxC,gCAAU,MAAM;AAEd,YAAQ,SAAS,cAAc,cAAc;AAAA,EAC/C,GAAG,CAAC,cAAc,CAAC;AAEnB,MAAI,QAAQ,WAAW,EAAG,QAAO;AAGjC,QAAM,aAAa,KAAK,IAAI,QAAQ,SAAS,aAAa,GAAG;AAE7D,SACE,8CAAC,SAAI,WAAU,6BAA4B,OAAO,EAAE,UAAU,SAAS,GACrE,wDAAC,wBAAM,KAAK,SAAS,OAAO,EAAE,QAAQ,WAAW,GAC9C,kBAAQ,IAAI,CAAC,QAAQ,UACpB;AAAA,IAAC;AAAA;AAAA,MAEC,WAAW,kCACT,UAAU,iBAAiB,kDAAkD,EAC/E;AAAA,MACA,aAAa,CAAC,MAAM;AAElB,UAAE,eAAe;AACjB,iBAAS,MAAM;AAAA,MACjB;AAAA,MAEC;AAAA,eAAO,OAAO,YACb,8CAAC,SAAI,WAAU,uCAAsC,eAAC,IAEtD,8CAAC,UAAO,OAAO,OAAO,QAAQ,MAAM,OAAO,MAAM,MAAM,IAAI;AAAA,QAE7D,8CAAC,UAAK,WAAU,mCACb,iBAAO,OAAO,YAAY,QAAQ,OAAO,MAC5C;AAAA;AAAA;AAAA,IAjBK,OAAO;AAAA,EAkBd,CACD,GACH,GACF;AAEJ,CAAC;AAED,mBAAmB,cAAc;;;AC1DjC,IAAAC,iBAAkB;AAClB,IAAAC,0BAA2B;AAoDf,IAAAC,uBAAA;AA7CZ,SAASC,gBAAe,OAAuB;AAC7C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC9C;AAKA,SAAS,YAAY,UAA0B;AAC7C,MAAI,SAAS,WAAW,QAAQ,EAAG,QAAO;AAC1C,MAAI,SAAS,WAAW,QAAQ,EAAG,QAAO;AAC1C,MAAI,SAAS,SAAS,KAAK,EAAG,QAAO;AACrC,MAAI,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,KAAK,EAAG,QAAO;AAC7F,SAAO;AACT;AAMO,IAAM,eAA4C,eAAAC,QAAM,KAAK,CAAC,EAAE,OAAO,SAAS,MAAM;AAC3F,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SACE,8CAAC,SAAI,WAAU,uBACZ,gBAAM,IAAI,CAAC,SAAS;AACnB,UAAM,WAAW,KAAK,MAAM,QAAQ,KAAK,oBAAoB,aAAa;AAC1E,UAAM,WAAW,KAAK,MAAM,QAAQ,KAAK,oBAAoB,SAAS;AACtE,UAAM,WAAW,KAAK,MAAM,QAAQ,KAAK,oBAAoB,aAAa;AAE1E,UAAM,SAAS,KAAK,WAAO,oCAAW,KAAK,IAAI,IAAK,aAAa,gBAAgB,aAAa;AAC9F,UAAMC,WAAU,SAAS,WAAW,QAAQ,KAAK,CAAC;AAClD,UAAMC,WAAU,SAAS,WAAW,QAAQ;AAC5C,UAAM,cAAc,KAAK,WAAW;AACpC,UAAM,WAAW,KAAK,WAAW;AAEjC,UAAM,aAAa,KAAK,cAAc,KAAK,oBAAoB,aAAa,KAAK,oBAAoB;AAErG,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,4BAA4B,WAAW,sCAAsC,EAAE;AAAA,QAG1F;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM,SAAS,KAAK,EAAE;AAAA,cAC/B,cAAW;AAAA,cACX,MAAK;AAAA,cACN;AAAA;AAAA,UAED;AAAA,UAGCD,YAAW,aACV;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,KAAK;AAAA,cACL,KAAK;AAAA;AAAA,UACP,IACEC,YAAW,aACb;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,KAAK;AAAA,cACL,OAAK;AAAA;AAAA,UACP,IAEA,8CAAC,SAAI,WAAU,kCACb,wDAAC,UAAM,sBAAY,QAAQ,GAAE,GAC/B;AAAA,UAIF,+CAAC,SAAI,WAAU,6BACb;AAAA,0DAAC,UAAK,WAAU,6BAA6B,oBAAS;AAAA,YACtD,8CAAC,UAAK,WAAU,6BAA6B,UAAAH,gBAAe,OAAO,QAAQ,CAAC,GAAE;AAAA,aAChF;AAAA,UAGC,eACC,8CAAC,SAAI,WAAU,kCACb,wDAAC,UAAK,WAAU,gCAA+B,GACjD;AAAA,UAID,YACC,8CAAC,SAAI,WAAU,oCAAmC,OAAO,KAAK,OAAO,oBAErE;AAAA;AAAA;AAAA,MAjDG,KAAK;AAAA,IAmDZ;AAAA,EAEJ,CAAC,GACH;AAEJ,CAAC;AAED,aAAa,cAAc;;;AC3G3B,IAAAI,iBAA+B;AA8DzB,IAAAC,uBAAA;AAzDN,IAAMC,sBAAqB;AAE3B,SAASC,cAAa,MAAc,WAA2B;AAC7D,MAAI,KAAK,UAAU,UAAW,QAAO;AACrC,SAAO,KAAK,MAAM,GAAG,SAAS,EAAE,QAAQ,IAAI;AAC9C;AAGA,SAAS,qBAAqB,aAA4B;AACxD,MAAI,CAAC,eAAe,YAAY,WAAW,EAAG,QAAO;AAErD,QAAM,QAAgC,CAAC;AACvC,aAAW,OAAO,aAAa;AAC7B,UAAM,OAAO,IAAI,QAAQ;AACzB,UAAM,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK;AAAA,EACrC;AAEA,QAAM,SAAmB,CAAC;AAC1B,QAAM,aAAqC;AAAA,IACzC,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,gBAAgB;AAAA,EAClB;AAEA,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AACjD,UAAM,QAAQ,WAAW,IAAI,KAAK,aAAM,IAAI;AAC5C,WAAO,KAAK,QAAQ,IAAI,GAAG,KAAK,KAAK,KAAK,MAAM,KAAK;AAAA,EACvD;AAEA,SAAO,OAAO,KAAK,IAAI;AACzB;AACO,IAAM,eAA4C,eAAAC,QAAM,KAAK,CAAC;AAAA,EACnE;AAAA,EACA;AAAA,EACA,kBAAkB;AACpB,MAAM;AACJ,QAAM,EAAE,cAAc,IAAI,cAAc;AAExC,QAAM,cAAU,wBAAgC,MAAM;AACpD,WAAO,aAAa,eAAe,KAAK;AAAA,EAC1C,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,WAAW,QAAQ,MAAM,QAAQ,QAAQ,WAAW;AAE1D,QAAM,UAAU,QAAQ,QAAQ;AAChC,QAAM,oBAAgB,wBAAQ,MAAM,0BAA0B,SAAS,SAAS,OAAO,GAAG,CAAC,SAAS,SAAS,OAAO,CAAC;AACrH,QAAM,UAAU,CAAC,CAAC,cAAc,KAAK;AACrC,QAAM,iBAAiB,QAAQ,eAAe,QAAQ,YAAY,SAAS;AAC3E,QAAM,YAAY,QAAQ,SAAS;AACnC,QAAM,oBAAoB,iBAAiB,qBAAqB,QAAQ,WAAY,IAAI;AAGxF,MAAI,iBAAkC;AACtC,MAAI,WAAW;AACb,qBACE,8CAAC,UAAK,WAAU,2CAA0C,+BAE1D;AAAA,EAEJ,OAAO;AACL,qBACE,+CAAC,UAAK,WAAU,2CACb;AAAA,iBAAWD,cAAa,eAAeD,mBAAkB;AAAA,MACzD,WAAW,kBAAkB;AAAA,MAC7B,kBAAkB;AAAA,OACrB;AAAA,EAEJ;AAEA,SACE,+CAAC,SAAI,WAAU,sCACb;AAAA,mDAAC,SAAI,WAAU,2CACb;AAAA,oDAAC,UAAK,WAAU,4CAA4C,2BAAgB;AAAA,MAC5E,8CAAC,UAAK,WAAU,2CAA2C,oBAAS;AAAA,MACnE;AAAA,OACH;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QACT,OAAM;AAAA,QAEN,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,wDAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK;AAAA,UACpC,8CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,WACtC;AAAA;AAAA,IACF;AAAA,KACF;AAEJ,CAAC;AAED,aAAa,cAAc;;;ACjG3B,IAAAG,iBAA+B;AAkEzB,IAAAC,uBAAA;AA7DN,IAAMC,sBAAqB;AAE3B,SAASC,cAAa,MAAc,WAA2B;AAC7D,MAAI,KAAK,UAAU,UAAW,QAAO;AACrC,SAAO,KAAK,MAAM,GAAG,SAAS,EAAE,QAAQ,IAAI;AAC9C;AAGA,SAASC,sBAAqB,aAA4B;AACxD,MAAI,CAAC,eAAe,YAAY,WAAW,EAAG,QAAO;AAErD,QAAM,QAAgC,CAAC;AACvC,aAAW,OAAO,aAAa;AAC7B,UAAM,OAAO,IAAI,QAAQ;AACzB,UAAM,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK;AAAA,EACrC;AAEA,QAAM,SAAmB,CAAC;AAC1B,QAAM,aAAqC;AAAA,IACzC,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,gBAAgB;AAAA,EAClB;AAEA,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AACjD,UAAM,QAAQ,WAAW,IAAI,KAAK,aAAM,IAAI;AAC5C,WAAO,KAAK,QAAQ,IAAI,GAAG,KAAK,KAAK,KAAK,MAAM,KAAK;AAAA,EACvD;AAEA,SAAO,OAAO,KAAK,IAAI;AACzB;AACO,IAAM,cAGR,eAAAC,QAAM,KAAK,CAAC;AAAA,EACf;AAAA,EACA;AAAA,EACA,sBAAsB;AACxB,MAAW;AACT,UAAQ,IAAI,eAAe,OAAO;AAClC,QAAM,EAAE,cAAc,IAAI,cAAc;AAExC,QAAM,cAAU,wBAAgC,MAAM;AACpD,WAAO,aAAa,eAAe,KAAK;AAAA,EAC1C,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,WAAW,QAAQ,MAAM,QAAQ,QAAQ,WAAW;AAE1D,QAAM,UAAU,QAAQ,QAAQ;AAChC,QAAM,oBAAgB,wBAAQ,MAAM,0BAA0B,SAAS,SAAS,OAAO,GAAG,CAAC,SAAS,SAAS,OAAO,CAAC;AACrH,QAAM,UAAU,CAAC,CAAC,cAAc,KAAK;AACrC,QAAM,iBAAiB,QAAQ,eAAe,QAAQ,YAAY,SAAS;AAC3E,QAAM,YAAY,QAAQ,SAAS;AACnC,QAAM,oBAAoB,iBAAiBD,sBAAqB,QAAQ,WAAY,IAAI;AAGxF,MAAI,iBAAkC;AACtC,MAAI,WAAW;AACb,qBACE,8CAAC,UAAK,WAAU,2CAA0C,+BAE1D;AAAA,EAEJ,OAAO;AACL,qBACE,+CAAC,UAAK,WAAU,2CACb;AAAA,iBAAWD,cAAa,eAAeD,mBAAkB;AAAA,MACzD,WAAW,kBAAkB;AAAA,MAC7B,kBAAkB;AAAA,OACrB;AAAA,EAEJ;AAEA,SACE,+CAAC,SAAI,WAAU,sCACb;AAAA,mDAAC,SAAI,WAAU,2CACb;AAAA,oDAAC,UAAK,WAAU,4CAA4C,+BAAoB;AAAA,MAChF,8CAAC,UAAK,WAAU,2CAA2C,oBAAS;AAAA,MACnE;AAAA,OACH;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QACT,OAAM;AAAA,QAEN,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,wDAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK;AAAA,UACpC,8CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,WACtC;AAAA;AAAA,IACF;AAAA,KACF;AAEJ,CAAC;AAED,YAAY,cAAc;;;AT1DtB,IAAAI,uBAAA;AAtBG,IAAM,eAA4C,eAAAC,QAAM,KAAK,CAAC;AAAA,EACnE,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,eAAe;AAAA,EACf,wBAAwB;AAAA,EACxB,8BAA8B;AAAA,EAC9B,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EACxB,uBAAuB;AAAA,EACvB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,sBAAsB,CAAC,UAAkB,8CAA8C,KAAK;AAAA,EAC5F,oBAAoB;AAAA,EACpB,gBAAgB,CAAC,aACf,gFAAE;AAAA;AAAA,IAAqD,+CAAC,YAAQ;AAAA;AAAA,MAAS;AAAA,OAAC;AAAA,IAAS;AAAA,KAAC;AAExF,MAAM;AACJ,QAAM,EAAE,QAAQ,eAAe,cAAc,eAAe,kBAAkB,gBAAgB,kBAAkB,IAAI,cAAc;AAClI,QAAM,EAAE,SAAS,IAAI,eAAe,eAAe,OAAO,MAAM;AAChE,QAAM,EAAE,UAAU,IAAI,gBAAgB,eAAe,OAAO,MAAM;AAClE,QAAM,EAAE,UAAU,IAAI,gBAAgB,eAAe,OAAO,MAAM;AAClE,QAAM,cAAc,eAAAA,QAAM,OAAuB,IAAI;AACrD,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAS,KAAK;AAElD,QAAM,EAAE,MAAM,eAAe,cAAc,IAAI,uBAAuB;AAGtE,QAAM,CAAC,uBAAuB,wBAAwB,QAAI,yBAAS,OAAO,eAAe,MAAM,uBAAuB,KAAK,CAAC;AAE5H,gCAAU,MAAM;AACd,QAAI,CAAC,cAAe;AACpB,6BAAyB,OAAO,cAAc,MAAM,uBAAuB,KAAK,CAAC;AACjF,UAAM,eAAe,CAAC,UAAmC;AACvD,YAAM,cAAe,OAAO,WAAuC,cAAc;AACjF,+BAAyB,OAAO,aAAa,uBAAuB,KAAK,CAAC;AAAA,IAC5E;AACA,kBAAc,GAAG,mBAAmB,YAAY;AAChD,WAAO,MAAM;AACX,oBAAc,IAAI,mBAAmB,YAAY;AAAA,IACnD;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,oBAAoB,iBAAiB,SAAS,YAAY,wBAAwB;AAExF,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAwB,IAAI;AAClE,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,CAAC;AAC1C,QAAM,uBAAmB,uBAAe,CAAC;AAGzC,gCAAU,MAAM;AACd,QAAI,CAAC,mBAAmB;AACtB,qBAAe,IAAI;AACnB,kBAAY,CAAC;AACb;AAAA,IACF;AAEA,QAAI,gBAAgB,iBAAiB,WAAW;AAChD,UAAM,WAAW,eAAe,OAAO,YAAY,CAAC;AAGpD,aAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,UAAI,SAAS,CAAC,EAAE,MAAM,OAAO,OAAO,QAAQ;AAC1C,cAAM,UAAU,IAAI,KAAK,SAAS,CAAC,EAAE,UAAU,EAAE,QAAQ;AACzD,YAAI,WAAW,CAAC,MAAM,OAAO,KAAK,UAAU,eAAe;AACzD,0BAAgB;AAAA,QAClB;AACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,eAAe;AACjB,YAAM,QAAQ,gBAAgB;AAC9B,UAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,uBAAe,KAAK;AAAA,MACtB,OAAO;AACL,uBAAe,IAAI;AACnB,oBAAY,CAAC;AAAA,MACf;AAAA,IACF,OAAO;AACL,qBAAe,IAAI;AACnB,kBAAY,CAAC;AAAA,IACf;AAAA,EACF,GAAG,CAAC,mBAAmB,eAAe,uBAAuB,OAAO,MAAM,CAAC;AAG3E,gCAAU,MAAM;AACd,QAAI,CAAC,eAAe,eAAe,KAAK,IAAI,GAAG;AAC7C,kBAAY,CAAC;AACb;AAAA,IACF;AACA,UAAM,WAAW,MAAM;AACrB,YAAM,YAAY,cAAc,KAAK,IAAI;AACzC,UAAI,aAAa,GAAG;AAClB,oBAAY,CAAC;AAAA,MACf,OAAO;AACL,oBAAY,KAAK,KAAK,YAAY,GAAI,CAAC;AAAA,MACzC;AAAA,IACF;AACA,aAAS;AACT,UAAM,QAAQ,YAAY,UAAU,GAAI;AACxC,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,oBAAoB,qBAAqB,WAAW,KAAK,CAAC;AAEhE,QAAM,iBAAiB,cAAc,cAAc;AACnD,QAAM,eAAe,cAAc,YAAY;AAE/C,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAwB,IAAI;AAGpE,gCAAU,MAAM;AACd,QAAI,cAAc,SAAS,OAAO,KAAK,cAAc;AACnD,sBAAgB,IAAI;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,cAAc,YAAY,CAAC;AAE/B,QAAM,wBAAoB,4BAAY,OAAO,MAAc,gBAAmC;AAE5F,QAAI,CAAC,gBAAgB,MAAM;AAEzB,YAAM,WAAW;AACjB,UAAI,SAAS,KAAK,IAAI,GAAG;AACvB,wBAAgB,kBAAkB;AAClC,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,QAAS,eAAe,MAAM,gBAA6B,CAAC;AAClE,QAAI,MAAM,SAAS,KAAK,MAAM;AAC5B,YAAM,YAAY,KAAK,YAAY;AACnC,YAAM,QAAQ,MAAM,KAAK,OAAK,UAAU,SAAS,EAAE,YAAY,CAAC,CAAC;AACjE,UAAI,OAAO;AACT,wBAAgB,oBAAoB,KAAK,CAAC;AAE1C,eAAO;AAAA,MACT;AAAA,IACF;AACA,oBAAgB,IAAI;AACpB,QAAI,cAAc;AAChB,aAAO,MAAM,aAAa,MAAM,WAAW;AAAA,IAC7C;AACA,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,cAAc,YAAY,CAAC;AAE9C,QAAM,wBAAoB,4BAAY,CAAC,SAAiB;AACtD,QAAI,mBAAmB;AACrB,uBAAiB,UAAU,KAAK,IAAI;AACpC,qBAAe,KAAK,IAAI,IAAI,qBAAqB;AAAA,IACnD;AACA,aAAS,IAAI;AAAA,EACf,GAAG,CAAC,mBAAmB,uBAAuB,MAAM,CAAC;AAGrD,gCAAU,MAAM;AACd,QAAI,iBAAiB,YAAY,SAAS;AACxC,kBAAY,QAAQ,MAAM;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,eAAe,eAAe,cAAc,CAAC;AAIjD,QAAM;AAAA,IACJ;AAAA,IAAO;AAAA,IAAU;AAAA,IACjB;AAAA,IAAqB;AAAA,IAAkB;AAAA,IAAmB;AAAA,EAC5D,IAAI,cAAc,EAAE,eAAe,aAAa,cAAc,CAAC;AAG/D,gCAAU,MAAM;AACd,QAAI,kBAAkB,YAAY,SAAS;AAEzC,YAAM,UAAU,eAAe,QAAQ;AAGvC,YAAM,UAAU,aAAa,eAAe,KAAK;AAEjD,YAAM,WAAW,QACd,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,OAAO,MAAM;AAExB,kBAAY,QAAQ,YAAY;AAAA,QAC9B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAGA,qBAAe,YAAY,OAAO;AAIlC,eAAS,CAAC,CAAC;AACX,oBAAc,CAAC,CAAC,eAAe,IAAI;AAAA,IACrC;AAAA,EACF,GAAG,CAAC,gBAAgB,QAAQ,CAAC;AAG7B,gCAAU,MAAM;AACd,WAAO,MAAM,aAAa;AAAA,EAC5B,GAAG,CAAC,CAAC;AAEL,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,eAAe,EAAE,aAAa,cAAc,CAAC;AAGjD,QAAM,cAAU,wBAAyB,MAAM;AAC7C,QAAI,CAAC,cAAe,QAAO,CAAC;AAC5B,UAAM,OAAwB,CAAC;AAC/B,UAAM,eAAe,eAAe,OAAO;AAC3C,QAAI,gBAAgB,OAAO,iBAAiB,UAAU;AACpD,iBAAW,CAAC,IAAI,SAAS,KAAK,OAAO,QAAQ,YAAY,GAAG;AAC1D,cAAM,SAAS;AACf,aAAK,KAAK;AAAA,UACR;AAAA,UACA,MAAM,QAAQ,MAAM,QAAQ,QAAQ,WAAW;AAAA,UAC/C,QAAQ,QAAQ,MAAM;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,aAAa,CAAC;AAEjC,QAAM;AAAA,IACJ;AAAA,IAAiB;AAAA,IAAiB;AAAA,IAClC,aAAa;AAAA,IACb,eAAe;AAAA,IACf;AAAA,IAAe;AAAA,IAAc;AAAA,EAC/B,IAAI,YAAY;AAAA,IACd;AAAA,IACA,eAAe,OAAO;AAAA,IACtB;AAAA,EACF,CAAC;AAED,QAAM,iBAAa,4BAAY,MAAM;AACnC,sBAAkB,IAAI;AACtB,iBAAa;AACb,aAAS,CAAC,CAAC;AACX,kBAAc,KAAK;AACnB,UAAM;AACN,QAAI,YAAY,SAAS;AACvB,kBAAY,QAAQ,YAAY;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,mBAAmB,cAAc,UAAU,eAAe,KAAK,CAAC;AAEpE,QAAM,EAAE,SAAS,WAAW,IAAI,eAAe;AAAA,IAC7C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,cAAc;AAAA,IACd;AAAA,IACA,oBAAoB,MAAM,iBAAiB,IAAI;AAAA,IAC/C;AAAA,IACA,qBAAqB,MAAM,kBAAkB,IAAI;AAAA,EACnD,CAAC;AAED,gCAAU,MAAM;AACd,UAAM;AACN,qBAAiB;AACjB,aAAS,CAAC,SAAS;AACjB,WAAK,QAAQ,CAAC,MAAM;AAClB,YAAI,EAAE,WAAY,KAAI,gBAAgB,EAAE,UAAU;AAAA,MACpD,CAAC;AACD,aAAO,CAAC;AAAA,IACV,CAAC;AACD,kBAAc,KAAK;AAGnB,WAAO,MAAM;AACX,qBAAe,WAAW;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,eAAe,OAAO,kBAAkB,QAAQ,CAAC;AAGrD,QAAM,kBAAc,4BAAY,MAAM;AACpC,UAAM,KAAK,YAAY;AACvB,UAAM,UAAU,IAAI,aAAa,KAAK,KAAK;AAC3C,kBAAc,QAAQ,SAAS,KAAK,MAAM,SAAS,CAAC;AACpD,oBAAgB,IAAI;AACpB,QAAI,iBAAiB,CAAC,iBAAiB;AACrC,yBAAmB;AAAA,IACrB;AAEA,mBAAe,UAAU;AAAA,EAC3B,GAAG,CAAC,eAAe,iBAAiB,oBAAoB,MAAM,QAAQ,aAAa,CAAC;AAEpF,QAAM,oBAAgB;AAAA,IACpB,CAAC,MAA2B;AAE1B,UAAI,EAAE,YAAY,YAAa;AAE/B,UAAI,EAAE,QAAQ,UAAU;AACtB,YAAI,gBAAgB;AAClB,qBAAW;AACX;AAAA,QACF;AACA,YAAI,eAAe;AACjB,2BAAiB,IAAI;AACrB;AAAA,QACF;AAAA,MACF;AACA,UAAI,iBAAiB,CAAC,iBAAiB;AACrC,cAAM,WAAW,qBAAqB,CAAC;AACvC,YAAI,SAAU;AAAA,MAChB;AACA,UAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,UAAU;AACpC,UAAE,eAAe;AACjB,YAAI,CAAC,mBAAmB;AACtB,qBAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,eAAe,iBAAiB,sBAAsB,YAAY,gBAAgB,eAAe,mBAAmB,kBAAkB,KAAK;AAAA,EAC9I;AAEA,QAAM,kBAAc,4BAAY,CAAC,MAA4B;AAC3D,MAAE,eAAe;AACjB,UAAM,YAAY,EAAE,cAAc,QAAQ,YAAY;AACtD,aAAS,YAAY,cAAc,OAAO,SAAS;AAAA,EACrD,GAAG,CAAC,CAAC;AAEL,MAAI,CAAC,cAAe,QAAO;AAG3B,MAAI,UAAW,QAAO;AAGtB,MAAI,UAAU;AACZ,WACE,8CAAC,SAAI,WAAW,kDAAkD,YAAY,IAAI,SAAS,KAAK,EAAE,IAChG,yDAAC,SAAI,WAAU,sCACb;AAAA,qDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAC/B,8CAAC,UAAK,IAAG,QAAO,IAAG,QAAO,IAAG,SAAQ,IAAG,SAAQ;AAAA,SAClD;AAAA,MACA,8CAAC,UAAM,uBAAY;AAAA,OACrB,GACF;AAAA,EAEJ;AAGA,MAAI,WAAW;AACb,WACE,8CAAC,SAAI,WAAW,mDAAmD,YAAY,IAAI,SAAS,KAAK,EAAE,IACjG,yDAAC,SAAI,WAAU,uCACb;AAAA,qDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAC/B,8CAAC,UAAK,IAAG,QAAO,IAAG,QAAO,IAAG,SAAQ,IAAG,SAAQ;AAAA,SAClD;AAAA,MACA,8CAAC,UAAM,wBAAa;AAAA,OACtB,GACF;AAAA,EAEJ;AAEA,QAAM,mBAAmB,MAAM,KAAK,CAAC,MAAM,EAAE,WAAW,WAAW;AAEnE,SACE,+CAAC,SAAI,WAAW,sBAAsB,YAAY,IAAI,SAAS,KAAK,EAAE,IAEnE;AAAA,qBAAiB,CAAC,kBACjB;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAW,MAAM,iBAAiB,IAAI;AAAA;AAAA,IACxC;AAAA,IAID,kBACC;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAW;AAAA;AAAA,IACb;AAAA,IAID,cAAc;AAAA,IAGd,CAAC,sBAAsB,8CAAC,yBAAsB,OAAc,UAAU,kBAAkB;AAAA,IAGxF,gBACC,+CAAC,SAAI,WAAU,uCACb;AAAA,qDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAAS,8CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,QAAO,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK;AAAA,SAAO;AAAA,MACpR;AAAA,OACH;AAAA,IAID,CAAC,kBAAkB,CAAC,kBACnB,+CAAC,SAAI,WAAU,0CACb;AAAA,qDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ;AAAA,sDAAC,UAAK,GAAE,KAAI,GAAE,MAAK,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,QAAO,8CAAC,UAAK,GAAE,4BAA2B;AAAA,SAAO;AAAA,MACzP;AAAA,OACH;AAAA,IAID,kBAAkB,qBAAqB,CAAC,gBACvC,+CAAC,SAAI,WAAU,yCACb;AAAA,qDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAAS,8CAAC,cAAS,QAAO,oBAAmB;AAAA,SAAW;AAAA,MACvO,OAAO,kBAAkB,aAAa,cAAc,QAAQ,IAAI;AAAA,OACnE;AAAA,IAIF,+CAAC,SAAI,WAAW,2BAA4B,CAAC,kBAAkB,qBAAqB,eAAgB,8CAA8C,EAAE,IAClJ;AAAA,qDAAC,SAAI,WAAU,yCACZ;AAAA,0BAAkB,iBAAiB,CAAC,mBAAmB,mBACtD;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT;AAAA,YACA,UAAU;AAAA;AAAA,QACZ;AAAA,QAID,CAAC,sBACA,8CAAC,gBAAa,UAAU,WAAW,CAAC,CAAC,kBAAkB,qBAAqB,CAAC,gBAAgB,SAAS,mBAAmB;AAAA,QAI1H,CAAC,sBACA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,MAAK;AAAA,YACL,UAAQ;AAAA,YACR,WAAU;AAAA,YACV,UAAU,CAAC,MAAM;AACf,kCAAoB,EAAE,OAAO,KAAK;AAClC,gBAAE,OAAO,QAAQ;AAAA,YACnB;AAAA,YACA,UAAU,CAAC,CAAC,kBAAkB,qBAAqB,CAAC;AAAA;AAAA,QACtD;AAAA,QAGF;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,WAAU;AAAA,YACV,iBAAiB,CAAC,WAAW,CAAC,qBAAqB;AAAA,YACnD,MAAK;AAAA,YACL,oBAAkB;AAAA,YAClB,oBAAkB;AAAA,YAClB,SAAS;AAAA,YACT,WAAW;AAAA,YACX,SAAS;AAAA,YACT,gCAA8B;AAAA;AAAA,QAChC;AAAA,QAGC,wBACC,8CAAC,wBAAqB,QAAQ,iBAAiB,SAAS,oBAAoB,MAAM;AAAA,QAAE,IAAI,mBAAmB;AAAA,SAE/G;AAAA,MACA,8CAAC,cAAW,UAAU,CAAC,cAAc,WAAW,oBAAoB,mBAAmB,SAAS,YAAY;AAAA,OAC9G;AAAA,IAGC,wBAAwB,mBACvB,8CAAC,SAAI,WAAU,qCACb,wDAAC,wBAAqB,UAAU,mBAAmB,SAAS,kBAAkB,GAChF;AAAA,KAEJ;AAEJ,CAAC;AAED,aAAa,cAAc;;;AUhgB3B,IAAAC,iBAAiE;;;ACAjE,IAAAC,iBAAmF;AACnF,IAAAC,iBAAsB;;;ACOhB,IAAAC,uBAAA;AALC,SAASC,aAAY,aAAqB,UAAmC;AAClF,QAAM,MAAM,SAAS,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,KAAK;AAExD,MAAI,YAAY,SAAS,KAAK,KAAK,QAAQ,OAAO;AAChD,WACE,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,oDAAC,UAAK,GAAE,8DAA6D;AAAA,MACrE,8CAAC,cAAS,QAAO,kBAAiB;AAAA,MAClC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,MACrC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,MACrC,8CAAC,cAAS,QAAO,gBAAe;AAAA,OAClC;AAAA,EAEJ;AAEA,MAAI,YAAY,SAAS,KAAK,KAAK,YAAY,SAAS,KAAK,KAAK,YAAY,SAAS,SAAS,KAAK,CAAC,OAAO,OAAO,MAAM,OAAO,IAAI,EAAE,SAAS,GAAG,GAAG;AACpJ,WACE,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,oDAAC,UAAK,GAAE,mBAAkB;AAAA,MAC1B,8CAAC,UAAK,GAAE,aAAY;AAAA,MACpB,8CAAC,UAAK,GAAE,2BAA0B;AAAA,OACpC;AAAA,EAEJ;AAGA,SACE,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,kDAAC,UAAK,GAAE,8DAA6D;AAAA,IACrE,8CAAC,cAAS,QAAO,kBAAiB;AAAA,KACpC;AAEJ;AAEO,IAAM,eAAuC;AAAA,EAClD,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AACX;AAEO,IAAM,iBAA6B,CAAC,SAAS,SAAS,OAAO;AAC7D,IAAM,WAAuB,CAAC,WAAW,SAAS,SAAS,OAAO;AAElE,IAAM,gBAAgB,EAAE,SAAS,KAAK,YAAY,qBAAqB;AACvE,IAAM,cAAc,EAAE,SAAS,GAAG,YAAY,qBAAqB;;;AChD1E,IAAAC,iBAAyC;AAgCvB,IAAAC,uBAAA;AA5BX,IAAM,gBAGR,eAAAC,QAAM,KAAK,CAAC,EAAE,MAAM,QAAQ,MAAM;AACrC,QAAM,MAAM,KAAK,aAAa,KAAK;AACnC,QAAM,gBAAgB,iBAAiB,GAAG;AAC1C,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,aAAa;AAClD,QAAM,SAAS,eAAAA,QAAM,OAAyB,IAAI;AAGlD,8BAAQ,MAAM;AAAE,iBAAa,GAAG;AAAA,EAAG,GAAG,CAAC,GAAG,CAAC;AAG3C,iBAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,UAAU,OAAO,SAAS,UAAU;AACvC,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,QAAQ,GAAG,CAAC;AAEhB,QAAMC,WAAU,KAAK,oBAAoB;AAEzC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,SAAS,MAAM,QAAQ,KAAK,GAAG;AAAA,MAC/B,OAAO,KAAK;AAAA,MAGX;AAAA,SAAC,UAAU,8CAAC,SAAI,WAAU,qCAAoC;AAAA,QAE9DA,WACC,+CAAC,SAAI,WAAU,yCACZ;AAAA,eAAK,YACJ;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,KAAK,KAAK;AAAA,cACV,KAAK,KAAK,aAAa;AAAA,cACvB,SAAQ;AAAA,cACR,QAAQ,MAAM,UAAU,IAAI;AAAA,cAC5B,OAAO,EAAE,SAAS,SAAS,IAAI,GAAG,YAAY,2BAA2B;AAAA;AAAA,UAC3E,IAEA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK,KAAK;AAAA,cACV,SAAQ;AAAA,cACR,cAAc,MAAM,UAAU,IAAI;AAAA,cAClC,OAAO,EAAE,SAAS,SAAS,IAAI,GAAG,YAAY,2BAA2B;AAAA;AAAA,UAC3E;AAAA,UAEF,8CAAC,SAAI,WAAU,uCACb,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,gBACnD,wDAAC,aAAQ,QAAO,sBAAqB,GACvC,GACF;AAAA,WACF,IAEA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL;AAAA,YACA,KAAK,KAAK,aAAa;AAAA,YACvB,SAAQ;AAAA,YACR,QAAQ,MAAM,UAAU,IAAI;AAAA,YAC5B,OAAO,EAAE,SAAS,SAAS,IAAI,GAAG,YAAY,2BAA2B;AAAA;AAAA,QAC3E;AAAA;AAAA;AAAA,EAEJ;AAEJ,GAAG,CAAC,MAAM,SAAS,KAAK,KAAK,OAAO,KAAK,KAAK,EAAE;AAC/C,cAAsB,cAAc;AAE9B,IAAM,WAAW,eAAAD,QAAM,KAAK,CAAC,EAAE,KAAK,QAAQ,MAAiE;AAClH,SACE,+CAAC,SAAI,WAAU,sCACZ;AAAA,QAAI,IAAI,UACP,8CAAC,iBAA4B,MAAY,WAArB,KAAK,EAAkC,CAC5D;AAAA,IACA,IAAI,SAAS,KAAK,MAAM,KAAK,EAAE,QAAQ,IAAI,IAAI,OAAO,CAAC,EAAE,IAAI,CAAC,GAAG,MAChE,8CAAC,SAAuB,WAAU,0EAAxB,SAAS,CAAC,EAAqF,CAC1G;AAAA,KACH;AAEJ,GAAG,CAAC,MAAM,SAAS;AACjB,MAAI,KAAK,IAAI,WAAW,KAAK,IAAI,OAAQ,QAAO;AAChD,SAAO,KAAK,IAAI,MAAM,CAAC,MAAM,MAAM,KAAK,OAAO,KAAK,IAAI,CAAC,EAAE,EAAE;AAC/D,CAAC;AACA,SAAiB,cAAc;;;ACzFhC,IAAAE,iBAAyC;AA+B/B,IAAAC,uBAAA;AA3BH,IAAM,eAAmD,eAAAC,QAAM,KAAK,CAAC,EAAE,KAAK,MAAM;AACvF,QAAM,aAAa,KAAK,iBAAiB,KAAK,cAAc,KAAK;AACjE,QAAM,SAAS,cAAc,UAAU;AAGvC,QAAM,SAAS,KAAK;AACpB,QAAM,gBAAgB,SAAS,iBAAiB,MAAM,IAAI;AAC1D,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAS,aAAa;AACxD,QAAM,SAAS,eAAAA,QAAM,OAAyB,IAAI;AAElD,8BAAQ,MAAM;AAAE,QAAI,OAAQ,cAAa,MAAM;AAAA,EAAG,GAAG,CAAC,MAAM,CAAC;AAE7D,iBAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,aAAa,OAAO,SAAS,UAAU;AAC1C,mBAAa,IAAI;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,WAAW,MAAM,CAAC;AAEtB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,MAAM;AAAA,MACN,QAAO;AAAA,MACP,KAAI;AAAA,MAEJ;AAAA,sDAAC,SAAI,WAAU,iCACZ,mBACC,+CAAC,SAAI,OAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ,UAAU,WAAW,GAC/D;AAAA,WAAC,aAAa,8CAAC,SAAI,WAAU,qCAAoC,OAAO,EAAE,cAAc,MAAM,GAAG;AAAA,UAClG;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,KAAK;AAAA,cACL,KAAI;AAAA,cACJ,WAAU;AAAA,cACV,SAAQ;AAAA,cACR,QAAQ,MAAM,aAAa,IAAI;AAAA,cAC/B,OAAO,EAAE,SAAS,YAAY,IAAI,GAAG,YAAY,2BAA2B;AAAA;AAAA,UAC9E;AAAA,WACF,IAEA,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,wDAAC,UAAK,GAAE,4DAA2D;AAAA,UACnE,8CAAC,cAAS,QAAO,kBAAiB;AAAA,UAClC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI;AAAA,WACvC,GAEJ;AAAA,QACA,+CAAC,SAAI,WAAU,oCACb;AAAA,wDAAC,UAAK,WAAU,kCACb,eAAK,SAAS,KAAK,aAAa,QACnC;AAAA,UACA,8CAAC,UAAK,WAAU,mCAAmC,kBAAO;AAAA,WAC5D;AAAA,QACA,8CAAC,UAAK,WAAU,iCAAiC,6BAAmB,KAAK,UAAU,GAAE;AAAA;AAAA;AAAA,EACvF;AAEJ,GAAG,CAAC,MAAM,SAAS,KAAK,KAAK,OAAO,KAAK,KAAK,EAAE;AAC/C,aAAqB,cAAc;;;AC7DpC,IAAAC,iBAAkB;AAiBZ,IAAAC,uBAAA;AAZC,IAAM,eAGR,eAAAC,QAAM,KAAK,CAAC,EAAE,MAAM,QAAQ,MAAM;AACrC,QAAM,cAAc,eAAe,KAAK,SAAS;AACjD,QAAM,MAAM,KAAK,UAAU,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,KAAK;AAE9D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,SAAS,MAAM,QAAQ,KAAK,GAAG;AAAA,MAE/B;AAAA,uDAAC,SAAI,WAAU,iCACZ;AAAA,UAAAC,aAAY,KAAK,cAAc,KAAK,SAAS;AAAA,UAC9C,8CAAC,UAAK,WAAU,gCAAgC,eAAI;AAAA,WACtD;AAAA,QACA,+CAAC,SAAI,WAAU,iCACb;AAAA,wDAAC,UAAK,WAAU,iCAAgC,OAAO,KAAK,WACzD,uBACH;AAAA,UACA,+CAAC,SAAI,WAAU,iCACb;AAAA,0DAAC,UAAM,yBAAe,KAAK,cAAc,GAAE;AAAA,YAC3C,8CAAC,UAAK,WAAU,qCAAoC,kBAAC;AAAA,YACrD,8CAAC,UAAM,6BAAmB,KAAK,UAAU,GAAE;AAAA,aAC7C;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAS,CAAC,MAAM;AACd,gBAAE,gBAAgB;AAClB,sBAAQ,KAAK,GAAG;AAAA,YAClB;AAAA,YACA,cAAW;AAAA,YAEX,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,4DAAC,UAAK,GAAE,6CAA4C;AAAA,cACpD,8CAAC,cAAS,QAAO,oBAAmB;AAAA,cACpC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI;AAAA,eACvC;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ,GAAG,CAAC,MAAM,SAAS,KAAK,KAAK,OAAO,KAAK,KAAK,EAAE;AAC/C,aAAqB,cAAc;;;AChDpC,IAAAC,iBAAgC;AAqB1B,IAAAC,uBAAA;AAjBC,IAAM,iBAAiB,eAAAC,QAAM,KAAK,CAAC;AAAA,EACxC;AAAA,EAAQ;AAAA,EACR;AAAA,EAAU;AAAA,EACV;AAAA,EAAO;AAAA,EACP;AAAA,EAAS;AAAA,EACT;AAAA,EAAW;AAAA,EACX;AAAA,EAAU;AACZ,MAAkC;AAChC,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAyB,IAAI;AACjE,QAAM,SAAS,eAAe;AAE9B,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO,gBAAgB;AACpC,QAAM,aAAa,aAAa,UAAU,YAAY,cAAc;AAEpE,SACE,+CAAC,SAAI,WAAU,mCACb;AAAA,kDAAC,mBAAgB,OAAO,OAAO,MAAM,QAAQ,MAAM,OAAO,MAAM,QAAQ,OAAO,MAAM,IAAI,MAAM,IAAI;AAAA,IACnG,+CAAC,SAAI,WAAU,mCACb;AAAA,oDAAC,UAAK,WAAU,mCAAmC,iBAAO,MAAM,QAAQ,OAAO,MAAM,IAAG;AAAA,MACxF,8CAAC,UAAK,WAAW,oEAAoE,KAAK,YAAY,CAAC,IACpG,eAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,GAC9C;AAAA,OACF;AAAA,IAEC,cACC,gFACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,CAAC,MAAM;AACd,cAAE,gBAAgB;AAClB,0BAAc,EAAE,cAAc,sBAAsB,CAAC;AAAA,UACvD;AAAA,UACA,cAAW;AAAA,UAEX,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,0DAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,YAC9B,8CAAC,YAAO,IAAG,MAAK,IAAG,KAAI,GAAE,KAAI;AAAA,YAC7B,8CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,aAChC;AAAA;AAAA,MACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,SAAS,MAAM,cAAc,IAAI;AAAA,UACjC,OAAM;AAAA,UAEN,yDAAC,SAAI,WAAU,wBACZ;AAAA,0BAAc,aACb,8CAAC,YAAO,WAAU,wBAAuB,SAAS,MAAM;AAAE,wBAAU,OAAO,MAAM,MAAM,OAAO,OAAO;AAAG,4BAAc,IAAI;AAAA,YAAG,GAAG,8BAAgB;AAAA,YAEjJ,aAAa,YACZ,8CAAC,YAAO,WAAU,wBAAuB,SAAS,MAAM;AAAE,uBAAS,OAAO,MAAM,MAAM,OAAO,OAAO;AAAG,4BAAc,IAAI;AAAA,YAAG,GAAG,8BAAgB;AAAA,YAEhJ,UAAU,SACT,8CAAC,YAAO,WAAU,qDAAoD,SAAS,MAAM;AAAE,oBAAM,OAAO,MAAM,MAAM,OAAO,OAAO;AAAG,4BAAc,IAAI;AAAA,YAAG,GAAG,wBAAU;AAAA,YAEpK,YAAY,WACX,8CAAC,YAAO,WAAU,wBAAuB,SAAS,MAAM;AAAE,sBAAQ,OAAO,MAAM,MAAM,OAAO,OAAO;AAAG,4BAAc,IAAI;AAAA,YAAG,GAAG,0BAAY;AAAA,YAE3I,aAAa,YACZ,8CAAC,YAAO,WAAU,qDAAoD,SAAS,MAAM;AAAE,uBAAS,OAAO,MAAM,MAAM,OAAO,OAAO;AAAG,4BAAc,IAAI;AAAA,YAAG,GAAG,iCAAmB;AAAA,aAEnL;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KAEJ;AAEJ,GAAG,CAAC,MAAM,SAAS;AACjB,SAAO,KAAK,QAAQ,YAAY,KAAK,QAAQ,WACtC,KAAK,QAAQ,iBAAiB,KAAK,QAAQ,gBAC3C,KAAK,QAAQ,WAAW,KAAK,QAAQ,UACrC,KAAK,cAAc,KAAK,aACxB,KAAK,WAAW,KAAK,UACrB,KAAK,aAAa,KAAK,YACvB,KAAK,eAAe,KAAK,cACzB,KAAK,cAAc,KAAK;AACjC,CAAC;AACA,eAAuB,cAAc;;;ACpFtC,IAAAC,iBAAkB;AAMV,IAAAC,uBAAA;AAJD,IAAM,gBAA6C,eAAAC,QAAM,KAAK,CAAC,EAAE,MAAM,MAC5E,+CAAC,SAAI,WAAU,mCACb;AAAA,iDAAC,SAAI,WAAU,wCACZ;AAAA,cAAU,WACT,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI;AAAA,oDAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,MACvD,8CAAC,YAAO,IAAG,OAAM,IAAG,OAAM,GAAE,OAAM;AAAA,MAClC,8CAAC,cAAS,QAAO,oBAAmB;AAAA,OACtC;AAAA,IAED,UAAU,WACT,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI;AAAA,oDAAC,UAAK,GAAE,+DAA8D;AAAA,MACtE,8CAAC,UAAK,GAAE,gEAA+D;AAAA,OACzE;AAAA,IAED,UAAU,WACT,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI;AAAA,oDAAC,UAAK,GAAE,8DAA6D;AAAA,MACrE,8CAAC,cAAS,QAAO,kBAAiB;AAAA,OACpC;AAAA,KAEJ;AAAA,EACA,+CAAC,UAAK;AAAA;AAAA,IAAI;AAAA,IAAM;AAAA,KAAW;AAAA,GAC7B,CACD;AACA,cAAsB,cAAc;AAE9B,IAAM,kBAA4B,eAAAA,QAAM,KAAK,MAClD,8CAAC,SAAI,WAAU,qCACb,wDAAC,SAAI,WAAU,qCAAoC,GACrD,CACD;AACA,gBAAwB,cAAc;;;AN8GvB,IAAAC,uBAAA;AArIT,IAAM,yBAAyD,eAAAC,QAAM,KAAK,CAAC;AAAA,EAChF;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,uBAAuB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,cAAc,SAAS,SAAS;AACtC,QAAM,EAAE,SAAS,IAAI,eAAe,SAAS,aAAa;AAC1D,QAAM,EAAE,UAAU,IAAI,gBAAgB,SAAS,aAAa;AAE5D,QAAM,gBAA4B,cAAc,iBAAiB;AAEjE,QAAM,CAAC,WAAW,YAAY,QAAI,yBAAmB,cAAc,CAAC,CAAC;AACrE,QAAM,iBAAa,iCAAiB,SAAS;AAC7C,QAAM,YAAY,cAAc;AAGhC,gCAAU,MAAM;AACd,iBAAa,cAAc,CAAC,CAAC;AAAA,EAE/B,GAAG,CAAC,SAAS,GAAG,CAAC;AAGjB,QAAM,aAAa,uBAAuB;AAC1C,QAAM,YAAY,sBAAsB;AACxC,QAAM,WAAW,qBAAqB;AACtC,QAAM,WAAW,qBAAqB;AACtC,QAAM,aAAa,uBAAuB;AAC1C,QAAM,UAAU,oBAAoB;AAEpC,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAA2B,CAAC,CAAC;AACzE,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,IAAI;AAE3C,QAAM,oBAAgB,wBAAQ,MAAM;AAClC,WAAO,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM;AACjC,YAAM,UAAU,aAAa,EAAE,gBAAgB,QAAQ,KAAK;AAC5D,YAAM,UAAU,aAAa,EAAE,gBAAgB,QAAQ,KAAK;AAC5D,aAAO,UAAU;AAAA,IACnB,CAAC;AAAA,EACH,GAAG,CAAC,OAAO,CAAC;AAGZ,QAAM,iBAAa;AAAA,IAAQ,MACzB,eAAe,OAAO,OAAK,EAAE,oBAAoB,WAAW,EAAE,oBAAoB,OAAO;AAAA,IACzF,CAAC,cAAc;AAAA,EACjB;AAEA,QAAM,gBAAY;AAAA,IAAQ,MACxB,eAAe,OAAO,OAAK,EAAE,oBAAoB,aAAa;AAAA,IAC9D,CAAC,cAAc;AAAA,EACjB;AAEA,QAAM,gBAAY;AAAA,IAAQ,MACxB,eAAe,OAAO,OAAK,EAAE,oBAAoB,UAAU,EAAE,oBAAoB,gBAAgB;AAAA,IACjG,CAAC,cAAc;AAAA,EACjB;AAEA,gCAAU,MAAM;AACd,QAAI,SAAS;AAGb,QAAI,YAAY,WAAW;AACzB,wBAAkB,CAAC,CAAC;AACpB,iBAAW,KAAK;AAChB;AAAA,IACF;AAEA,UAAM,aAAa,YAAY;AAC7B,iBAAW,IAAI;AACf,UAAI;AACF,cAAM,WAAgB,MAAM,QAAQ,wBAAwB;AAE5D,YAAI,QAAQ;AACV,gBAAM,QAAQ,UAAU,eAAe,CAAC;AACxC,4BAAkB,KAAK;AAAA,QACzB;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,0CAA0C,GAAG;AAC3D,YAAI,OAAQ,mBAAkB,CAAC,CAAC;AAAA,MAClC,UAAE;AACA,YAAI,OAAQ,YAAW,KAAK;AAAA,MAC9B;AAAA,IACF;AAEA,eAAW;AAEX,WAAO,MAAM;AAAE,eAAS;AAAA,IAAO;AAAA,EACjC,GAAG,CAAC,SAAS,UAAU,SAAS,CAAC;AAEjC,QAAM,gBAAY,wBAAkC,OAAO;AAAA,IACzD,SAAS,QAAQ;AAAA,IACjB,OAAO,WAAW;AAAA,IAClB,OAAO,UAAU;AAAA,IACjB,OAAO,UAAU;AAAA,EACnB,IAAI,CAAC,QAAQ,QAAQ,WAAW,QAAQ,UAAU,QAAQ,UAAU,MAAM,CAAC;AAE3E,QAAM,oBAAgB,4BAAY,CAAC,QAAgB;AACjD,WAAO,KAAK,KAAK,UAAU,qBAAqB;AAAA,EAClD,GAAG,CAAC,CAAC;AAGL,QAAM,gBAAY,wBAAQ,MAAM;AAC9B,UAAM,OAA2B,CAAC;AAClC,aAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;AAC7C,WAAK,KAAK,WAAW,MAAM,GAAG,IAAI,CAAC,CAAC;AAAA,IACtC;AACA,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,CAAC;AAGf,QAAM,oBAAgB,wBAAQ,MAAM;AAClC,YAAQ,YAAY;AAAA,MAClB,KAAK,WAAW;AACd,cAAM,QAA2B,CAAC;AAClC,YAAI,kBAAkB;AACpB,cAAI,0BAA0B;AAC5B,kBAAM;AAAA,cACJ,8CAAC,SAAyB,WAAU,uCAClC,wDAAC,4BAAyB,SAAS,kBAAkB,OAAO,sBAAsB,KAD3E,gBAET;AAAA,YACF;AAAA,UACF,OAAO;AACL,kBAAM;AAAA,cACJ,8CAAC,SAAyB,WAAU,uCAClC,yDAAC,YAAO,WAAU,sCAAqC,SAAS,kBAC9D;AAAA,+DAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,gEAAC,UAAK,GAAE,6CAA4C;AAAA,kBACpD,8CAAC,YAAO,IAAG,OAAM,IAAG,KAAI,GAAE,KAAI;AAAA,kBAC9B,8CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,kBACrC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,mBACxC;AAAA,gBACC;AAAA,iBACH,KATO,gBAUT;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,sBAAc,QAAQ,YAAU;AAC9B,gBAAM,OAAO,OAAO,gBAAgB;AACpC,gBAAM,oBAAoB,SAAS,YAAY,SAAS,aAAc,oBAAoB,WAAW,SAAS;AAE9G,gBAAM,YAAY;AAAA,aACf,oBAAoB,WAAW,oBAAoB,YACpD,qBACA,OAAO,YAAY;AAAA,UACrB;AAEA,gBAAM,SAAS;AAAA,aACZ,oBAAoB,WAAW,oBAAoB,YACpD,qBACA,SAAS,aACT,OAAO,YAAY,iBACnB,CAAC,OAAO;AAAA,UACV;AAEA,gBAAM,WAAW;AAAA,aACd,oBAAoB,WAAW,oBAAoB,YACpD,qBACA,SAAS,aACT,OAAO,YAAY,iBACnB,OAAO;AAAA,UACT;AAEA,gBAAM,aAAa;AAAA,YACjB,oBAAoB,WACpB,SAAS,YACT,OAAO,YAAY;AAAA,UACrB;AAEA,gBAAM,YAAY;AAAA,YAChB,oBAAoB,WACpB,SAAS,WACT,OAAO,YAAY;AAAA,UACrB;AAEA,gBAAM;AAAA,YACJ;AAAA,cAAC;AAAA;AAAA,gBAEC;AAAA,gBACA;AAAA,gBACA,UAAU;AAAA,gBACV;AAAA,gBACA,OAAO;AAAA,gBACP;AAAA,gBACA,SAAS;AAAA,gBACT;AAAA,gBACA,WAAW;AAAA,gBACX;AAAA,gBACA,UAAU;AAAA,gBACV;AAAA;AAAA,cAZK,QAAQ;AAAA,YAaf;AAAA,UACF;AAAA,QACF,CAAC;AACD,eAAO;AAAA,MACT;AAAA,MACA,KAAK;AACH,YAAI,cAAc,eAAe;AAE/B,iBAAO,UAAU,IAAI,CAAC,KAAK,WACzB,8CAAC,YAAoC,KAAU,SAAS,iBAAzC,IAAI,CAAC,GAAG,MAAM,MAA0C,CACxE;AAAA,QACH;AAEA,eAAO,WAAW,IAAI,CAAC,MAAM,QAC3B,8CAAC,aAA+B,MAAY,SAAS,iBAArC,KAAK,MAAM,GAAyC,CACrE;AAAA,MACH,KAAK;AACH,eAAO,UAAU,IAAI,CAAC,MAAM,QAC1B,8CAAC,YAA8B,QAAhB,KAAK,MAAM,GAAiB,CAC5C;AAAA,MACH,KAAK;AACH,eAAO,UAAU,IAAI,CAAC,MAAM,QAC1B,8CAAC,YAA8B,MAAY,SAAS,iBAArC,KAAK,MAAM,GAAyC,CACpE;AAAA,MACH;AACE,eAAO,CAAC;AAAA,IACZ;AAAA,EACF,GAAG,CAAC,YAAY,eAAe,WAAW,YAAY,WAAW,WAAW,kBAAkB,iBAAiB,eAAe,YAAY,WAAW,UAAU,QAAQ,CAAC;AAGxK,QAAM,aAAa,cAAc,WAAW,KAAK,EAAE,WAAW,eAAe;AAC7E,QAAM,aAAa,eAAe,YAAY,YAAY;AAE1D,SACE,+CAAC,SAAI,WAAU,iEACb;AAAA,kDAAC,SAAI,WAAU,kCACZ,wBAAc,IAAI,SACjB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,iCAAiC,cAAc,MAAM,0CAA0C,EAAE;AAAA,QAC5G,SAAS,MAAM,aAAa,GAAG;AAAA,QAE/B;AAAA,wDAAC,UAAK,WAAU,uCACb,cAAI,OAAO,CAAC,EAAE,YAAY,IAAI,IAAI,MAAM,CAAC,GAC5C;AAAA,UACC,UAAU,GAAG,IAAI,KAChB,8CAAC,UAAK,WAAU,uCAAuC,oBAAU,GAAG,GAAE;AAAA;AAAA;AAAA,MARnE;AAAA,IAUP,CACD,GACH;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,YAAY,gBAAgB;AAAA,QAElC,qBAAW,eAAe,YAAY,8CAAC,WAAQ,IAAK,aAAa,8CAAC,cAAW,OAAO,YAAY,IAC/F,8CAAC,wBAAM,OAAO,EAAE,QAAQ,OAAO,GAC5B,yBACH;AAAA;AAAA,IAEJ;AAAA,KACF;AAEJ,CAAC;;;AOzRD,IAAAC,iBAAsD;;;ACAtD,IAAAC,iBAAwF;AAGxF,IAAAC,iBAAwC;AAsBpC,IAAAC,uBAAA;AAbJ,IAAM,oBAAoB;AAC1B,IAAM,qBAAqB;AAG3B,IAAM,aAAkC,EAAE,QAAQ,OAAO;AAOzD,IAAM,YAAsB,MAC1B,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,wDAAC,cAAS,QAAO,kBAAiB,GACpC;AAIF,IAAM,kBAAiD,eAAAC,QAAM,KAAK,CAAC;AAAA,EACjE;AAAA,EAAM;AAAA,EAAU;AAAA,EAAU;AAAA,EAAM;AAAA,EAAU;AAC5C,MAAM;AACJ,QAAM,kBAAc,4BAAY,MAAM;AACpC,QAAI,CAAC,SAAU,UAAS,IAAI;AAAA,EAC9B,GAAG,CAAC,UAAU,UAAU,IAAI,CAAC;AAE7B,QAAM,aAAa;AAAA,IACjB;AAAA,IACA,SAAS,UAAU,oCAAoC;AAAA,IACvD,WAAW,sCAAsC;AAAA,EACnD,EAAE,KAAK,GAAG;AAEV,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,WAAW,sCAAsC;AAAA,IACjD,WAAW,sCAAsC;AAAA,EACnD,EAAE,KAAK,GAAG;AAEV,QAAM,SAAS,KAAK,SAAS,KAAK,SAAS;AAE3C,SACE,+CAAC,SAAI,WAAW,WAAW,SAAS,aAAa,MAAK,UAAS,iBAAe,UAC5E;AAAA,kDAAC,SAAI,WAAW,YACb,sBAAY,8CAAC,aAAU,GAC1B;AAAA,IACA,8CAAC,mBAAgB,OAAO,KAAK,QAAQ,MAAM,KAAK,QAAQ,KAAK,IAAI,MAAM,IAAI;AAAA,IAC3E,+CAAC,SAAI,WAAU,2BACb;AAAA,oDAAC,UAAK,WAAU,2BAA2B,eAAK,QAAQ,KAAK,IAAG;AAAA,MAC/D,UAAU,8CAAC,UAAK,WAAU,6BAA6B,kBAAO;AAAA,OACjE;AAAA,KACF;AAEJ,CAAC;AACD,gBAAgB,cAAc;AAG9B,IAAM,qBAAmI,CAAC,EAAE,OAAO,UAAU,YAAY,MACvK,+CAAC,SAAI,WAAU,6BACb;AAAA,iDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,kDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,IAC9B,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,SAAQ;AAAA,KAC9C;AAAA,EACA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAS;AAAA;AAAA,EACX;AAAA,GACF;AAIF,IAAM,qBAA2D,eAAAA,QAAM,KAAK,CAAC;AAAA,EAC3E;AAAA,EAAO;AAAA,EAAU;AAAA,EAAiB;AACpC,MACE,+CAAC,SAAI,WAAU,mCACZ;AAAA,QAAM,WAAW,KAAK,cACrB,8CAAC,UAAK,WAAU,qCAAqC,sBAAW;AAAA,EAEjE,MAAM,IAAI,OACT,+CAAC,SAAe,WAAU,2BACxB;AAAA,kDAAC,mBAAgB,OAAO,EAAE,QAAQ,MAAM,EAAE,QAAQ,EAAE,IAAI,MAAM,IAAI;AAAA,IAClE,8CAAC,UAAK,WAAU,gCAAgC,YAAE,QAAQ,EAAE,IAAG;AAAA,IAC/D;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS,MAAM,SAAS,EAAE,EAAE;AAAA,QAC5B,cAAY,UAAU,EAAE,QAAQ,EAAE,EAAE;AAAA,QAEpC,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,wDAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK;AAAA,UACpC,8CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,WACtC;AAAA;AAAA,IACF;AAAA,OAZQ,EAAE,EAaZ,CACD;AAAA,GACH,CACD;AACD,mBAAmB,cAAc;AAM1B,IAAM,aAAwC,CAAC;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB;AACF,MAAM;AACJ,QAAM,EAAE,OAAO,IAAI,cAAc;AACjC,QAAM,gBAAgB,QAAQ;AAG9B,QAAM,CAAC,UAAU,WAAW,QAAI,yBAA2B,CAAC,CAAC;AAC7D,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,CAAC;AAClC,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,IAAI;AAC3C,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,IAAI;AAC3C,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,KAAK;AAEpD,QAAM,CAAC,aAAa,cAAc,QAAI,yBAA2B,CAAC,CAAC;AACnE,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,KAAK;AAEpD,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,EAAE;AACjD,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAS,EAAE;AACvC,QAAM,CAAC,iBAAiB,eAAe,QAAI,8BAAc;AAEzD,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAsC,MAAM;AAChF,UAAM,MAAM,oBAAI,IAA4B;AAC5C,0BAAsB,QAAQ,OAAK,IAAI,IAAI,EAAE,IAAI,CAAC,CAAC;AACnD,WAAO;AAAA,EACT,CAAC;AAED,QAAM,eAAW,uBAAoB,IAAI;AAGzC,QAAM,UAAU,qBAAqB;AACrC,QAAM,cAAc,wBAAwB;AAC5C,QAAM,cAAc,wBAAwB;AAG5C,QAAM,iBAAa,wBAAQ,MAAM,IAAI,IAAI,kBAAkB,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC;AAGhF,QAAM,yBAAqB,4BAAY,CAAC,MAA2C;AACjF,UAAM,MAAM,EAAE,OAAO;AACrB,mBAAe,GAAG;AAClB,oBAAgB,MAAM;AACpB,gBAAU,GAAG;AAAA,IACf,CAAC;AAAA,EACH,GAAG,CAAC,eAAe,CAAC;AAGpB,gCAAU,MAAM;AACd,QAAI,SAAS;AACb,UAAM,aAAa,YAAY;AAC7B,UAAI,CAAC,OAAQ;AACb,UAAI;AACF,mBAAW,IAAI;AACf,cAAM,WAAW,MAAM,OAAO,WAAW,OAAO,QAAQ,GAAG,CAAC;AAC5D,YAAI,UAAU,SAAS,MAAM;AAC3B,sBAAY,SAAS,IAAI;AACzB,qBAAW,SAAS,KAAK,UAAU,QAAQ;AAC3C,kBAAQ,CAAC;AAAA,QACX;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,sCAAsC,GAAG;AAAA,MACzD,UAAE;AACA,YAAI,OAAQ,YAAW,KAAK;AAAA,MAC9B;AAAA,IACF;AACA,eAAW;AACX,WAAO,MAAM;AAAE,eAAS;AAAA,IAAO;AAAA,EACjC,GAAG,CAAC,QAAQ,QAAQ,CAAC;AAGrB,QAAM,eAAW,4BAAY,YAAY;AACvC,QAAI,CAAC,UAAU,eAAe,CAAC,WAAW,OAAO,KAAK,EAAG;AACzD,UAAM,WAAW,OAAO;AACxB,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,WAAW,MAAM,OAAO,WAAW,OAAO,QAAQ,GAAG,QAAQ;AACnE,UAAI,SAAS,MAAM;AACjB,oBAAY,UAAQ;AAClB,gBAAM,cAAc,IAAI,IAAI,KAAK,IAAI,OAAK,EAAE,EAAE,CAAC;AAC/C,gBAAM,WAAW,SAAS,KAAK,OAAO,CAAC,MAAsB,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;AACnF,iBAAO,CAAC,GAAG,MAAM,GAAG,QAAQ;AAAA,QAC9B,CAAC;AACD,mBAAW,SAAS,KAAK,UAAU,QAAQ;AAC3C,gBAAQ,QAAQ;AAAA,MAClB;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,0CAA0C,GAAG;AAAA,IAC7D,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,SAAS,MAAM,UAAU,MAAM,CAAC;AAGzD,QAAM,yBAAqB,wBAAQ,MAAM;AACvC,UAAM,OAAO,OAAO,YAAY,EAAE,KAAK;AACvC,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,SAAS,OAAO,OAAK;AAC1B,YAAM,QAAQ,EAAE,QAAQ,IAAI,YAAY;AACxC,YAAM,SAAS,EAAE,SAAS,IAAI,YAAY;AAC1C,YAAM,SAAS,EAAE,SAAS,IAAI,YAAY;AAC1C,aAAO,KAAK,SAAS,IAAI,KAAK,MAAM,SAAS,IAAI,KAAK,MAAM,SAAS,IAAI;AAAA,IAC3E,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,QAAQ,CAAC;AAGrB,gCAAU,MAAM;AACd,QAAI,CAAC,OAAO,KAAK,KAAK,mBAAmB,SAAS,GAAG;AACnD,qBAAe,CAAC,CAAC;AACjB,qBAAe,KAAK;AACpB;AAAA,IACF;AAEA,QAAI,YAAY;AAChB,UAAM,QAAQ,WAAW,YAAY;AACnC,qBAAe,IAAI;AACnB,UAAI;AACF,cAAM,WAAW,MAAM,OAAO,YAAY,GAAG,IAAI,OAAO,KAAK,CAAC;AAC9D,YAAI,CAAC,aAAa,SAAS,MAAM;AAC/B,yBAAe,SAAS,IAAI;AAAA,QAC9B;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,8CAA8C,GAAG;AAAA,MACjE,UAAE;AACA,YAAI,CAAC,UAAW,gBAAe,KAAK;AAAA,MACtC;AAAA,IACF,GAAG,kBAAkB;AAErB,WAAO,MAAM;AACX,kBAAY;AACZ,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,QAAQ,mBAAmB,QAAQ,QAAQ,UAAU,CAAC;AAG1D,QAAM,iBAAkB,OAAO,KAAK,KAAK,mBAAmB,WAAW,IACnE,cACA;AACJ,QAAM,gBAAgB,WAAW,eAAe;AAGhD,QAAM,mBAAe,4BAAY,CAAC,SAAyB;AAEzD,QAAI,KAAK,OAAO,iBAAiB,WAAW,IAAI,KAAK,EAAE,EAAG;AAE1D,mBAAe,UAAQ;AACrB,YAAM,OAAO,IAAI,IAAI,IAAI;AACzB,UAAI,SAAS,SAAS;AAEpB,YAAI,KAAK,IAAI,KAAK,EAAE,GAAG;AACrB,eAAK,MAAM;AAAA,QACb,OAAO;AACL,eAAK,MAAM;AACX,eAAK,IAAI,KAAK,IAAI,IAAI;AAAA,QACxB;AAAA,MACF,OAAO;AAEL,YAAI,KAAK,IAAI,KAAK,EAAE,GAAG;AACrB,eAAK,OAAO,KAAK,EAAE;AAAA,QACrB,OAAO;AACL,eAAK,IAAI,KAAK,IAAI,IAAI;AAAA,QACxB;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,eAAe,UAAU,CAAC;AAGpC,gCAAU,MAAM;AACd,wBAAoB,MAAM,KAAK,YAAY,OAAO,CAAC,CAAC;AAAA,EACtD,GAAG,CAAC,aAAa,iBAAiB,CAAC;AAEnC,QAAM,2BAAuB,4BAAY,CAAC,WAAmB;AAC3D,mBAAe,UAAQ;AACrB,YAAM,OAAO,IAAI,IAAI,IAAI;AACzB,WAAK,OAAO,MAAM;AAClB,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAGL,QAAM,mBAAe,4BAAY,CAAC,WAAmB;AAEnD,UAAM,KAAK,SAAS;AACpB,QAAI,CAAC,GAAI;AAET,UAAM,aAAc,GAAW,cAAc;AAC7C,UAAM,eAAgB,GAAW,gBAAgB;AACjD,QAAI,aAAa,KAAK,SAAS,gBAAgB,aAAa,IAAI;AAC9D,eAAS;AAAA,IACX;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAGb,QAAM,kBAAc,wBAAQ,MAAM,MAAM,KAAK,YAAY,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;AAEjF,SACE,+CAAC,SAAI,WAAU,qBAAoB,MAAK,WAAU,wBAAsB,SAAS,YAE9E;AAAA,aAAS,cACR;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,UAAU;AAAA,QACV;AAAA,QACA,YAAY;AAAA;AAAA,IACd;AAAA,IAIF;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,UAAU;AAAA,QACV,aAAa;AAAA;AAAA,IACf;AAAA,IAGA,8CAAC,SAAI,WAAU,2BACZ,0BACC,+CAAC,SAAI,WAAU,8BACb;AAAA,oDAAC,UAAK,WAAU,8BAA6B;AAAA,MAC5C;AAAA,OACH,IACE,eAAe,WAAW,IAC5B,8CAAC,SAAI,WAAU,4BAA4B,qBAAU,IAErD,+CAAC,wBAAM,KAAK,UAAU,OAAO,YAAY,UAAU,cAChD;AAAA,qBAAe,IAAI,UAClB;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA,UAAU,YAAY,IAAI,KAAK,EAAE;AAAA,UACjC,UAAU,KAAK,OAAO,iBAAiB,WAAW,IAAI,KAAK,EAAE;AAAA,UAC7D;AAAA,UACA,UAAU;AAAA,UACV;AAAA;AAAA,QANK,KAAK;AAAA,MAOZ,CACD;AAAA,MACA,eACC,+CAAC,SAAI,WAAU,gCACb;AAAA,sDAAC,UAAK,WAAU,8BAA6B;AAAA,QAC5C;AAAA,SACH;AAAA,OAEJ,GAEJ;AAAA,KACF;AAEJ;AAEA,WAAW,cAAc;;;ADvUrB,IAAAC,uBAAA;AA3CG,IAAM,iBAAgD,CAAC;AAAA,EAC5D;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,cAAc;AAAA,EACd,aAAa;AAAA,EACb;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,eAAe,gBAAgB,QAAI,yBAA2B,CAAC,CAAC;AACvE,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,KAAK;AAG9C,QAAM,qBAAiB;AAAA,IACrB,MAAM,eAAe,IAAI,CAAC,MAAW,EAAE,OAAO;AAAA,IAC9C,CAAC,cAAc;AAAA,EACjB;AAGA,QAAM,4BAAwB,4BAAY,CAAC,UAA4B;AACrE,qBAAiB,KAAK;AAAA,EACxB,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAY,4BAAY,YAAY;AACxC,QAAI,cAAc,WAAW,KAAK,SAAU;AAC5C,QAAI;AACF,kBAAY,IAAI;AAChB,YAAM,QAAQ,WAAW,cAAc,IAAI,OAAK,EAAE,EAAE,CAAC;AACrD,cAAQ;AAAA,IACV,SAAS,KAAK;AACZ,cAAQ,MAAM,0BAA0B,GAAG;AAAA,IAC7C,UAAE;AACA,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,eAAe,UAAU,SAAS,OAAO,CAAC;AAE9C,QAAM,SACJ;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU,cAAc,WAAW,KAAK;AAAA,MAEvC,qBACG,cACA,GAAG,QAAQ,IAAI,cAAc,SAAS,IAAI,IAAI,cAAc,MAAM,MAAM,EAAE;AAAA;AAAA,EAChF;AAGF,SACE,8CAAC,SAAM,QAAM,MAAC,SAAkB,OAAc,UAAS,SAAQ,QAC7D;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,mBAAmB;AAAA,MACnB;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,oBAAmB;AAAA;AAAA,EACrB,GACF;AAEJ;;;AE7EA,IAAAC,iBAAgE;AA0J5D,IAAAC,uBAAA;AAtJJ,IAAM,yBAAyB,IAAI,OAAO;AAEnC,IAAM,mBAAoD,eAAAC,QAAM,KAAK,CAAC;AAAA,EAC3E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,yBAAyB;AAAA,EACzB,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,oBAAoB;AACtB,MAAM;AAEJ,QAAM,eAAgB,QAAQ,MAAM,QAAmB;AACvD,QAAM,gBAAiB,QAAQ,MAAM,SAAoB;AACzD,QAAM,sBAAuB,QAAQ,MAAM,eAA0B;AACrE,QAAM,iBAAiB,QAAQ,QAAQ,MAAM,MAAM;AACnD,QAAM,gBAAgB,QAAQ,SAAS;AAGvC,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,YAAY;AAC7C,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,mBAAmB;AAClE,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,cAAc;AACvD,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAwB,IAAI;AAChE,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAsB,IAAI;AAClE,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,KAAK;AAC9C,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAwB,IAAI;AAEtD,QAAM,mBAAe,uBAAyB,IAAI;AAGlD,gCAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,WAAY,KAAI,gBAAgB,UAAU;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,uBAAmB,4BAAY,CAAC,MAA2C;AAC/E,UAAM,OAAO,EAAE,OAAO,QAAQ,CAAC;AAC/B,QAAI,CAAC,KAAM;AAGX,QAAI,CAAC,KAAK,KAAK,WAAW,QAAQ,GAAG;AACnC,eAAS,8BAA8B;AACvC;AAAA,IACF;AAGA,QAAI,KAAK,OAAO,cAAc;AAC5B,eAAS,iBAAiB;AAC1B;AAAA,IACF;AAEA,aAAS,IAAI;AAEb,QAAI,WAAY,KAAI,gBAAgB,UAAU;AAC9C,UAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,kBAAc,GAAG;AACjB,oBAAgB,IAAI;AAGpB,MAAE,OAAO,QAAQ;AAAA,EACnB,GAAG,CAAC,cAAc,mBAAmB,UAAU,CAAC;AAEhD,QAAM,wBAAoB,4BAAY,MAAM;AAC1C,iBAAa,SAAS,MAAM;AAAA,EAC9B,GAAG,CAAC,CAAC;AAGL,QAAM,mBAAe,4BAAY,MAA8B;AAC7D,UAAM,UAA2B,CAAC;AAClC,QAAI,aAAa;AAEjB,QAAI,KAAK,KAAK,MAAM,cAAc;AAChC,cAAQ,OAAO,KAAK,KAAK;AACzB,mBAAa;AAAA,IACf;AACA,QAAI,YAAY,KAAK,MAAM,qBAAqB;AAC9C,cAAQ,cAAc,YAAY,KAAK;AACvC,mBAAa;AAAA,IACf;AACA,QAAI,iBAAiB,aAAa,gBAAgB;AAChD,cAAQ,SAAS;AACjB,mBAAa;AAAA,IACf;AAEA,QAAI,cAAc;AAChB,mBAAa;AAAA,IACf;AAEA,WAAO,aAAa,UAAU;AAAA,EAChC,GAAG,CAAC,MAAM,aAAa,UAAU,cAAc,cAAc,qBAAqB,gBAAgB,aAAa,CAAC;AAEhH,QAAM,iBAAa,4BAAY,YAAY;AACzC,UAAM,UAAU,aAAa;AAC7B,QAAI,CAAC,WAAW,CAAC,cAAc;AAC7B,cAAQ;AACR;AAAA,IACF;AAEA,gBAAY,IAAI;AAChB,aAAS,IAAI;AAEb,QAAI;AAEF,UAAI,QAAQ;AACV,YAAI,cAAc;AAChB,gBAAM,WAAW,MAAM,QAAQ,SAAS,cAAc,aAAa,MAAM,aAAa,IAAI;AAC1F,WAAC,WAAW,CAAC,GAAsB,QAAQ,SAAS;AAAA,QACtD;AACA,cAAM,OAAO,WAAW,CAAC,CAAC;AAC1B,gBAAQ;AACR;AAAA,MACF;AAGA,YAAM,eAAgC,WAAW,CAAC;AAGlD,UAAI,cAAc;AAChB,cAAM,WAAW,MAAM,QAAQ,SAAS,cAAc,aAAa,MAAM,aAAa,IAAI;AAC1F,qBAAa,QAAQ,SAAS;AAAA,MAChC;AAGA,UAAI,OAAO,KAAK,YAAY,EAAE,SAAS,GAAG;AACxC,cAAM,QAAQ,OAAO,YAAmB;AAAA,MAC1C;AAEA,cAAQ;AAAA,IACV,SAAS,KAAU;AACjB,eAAS,KAAK,WAAW,0BAA0B;AAAA,IACrD,UAAE;AACA,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,cAAc,cAAc,QAAQ,SAAS,OAAO,CAAC;AAGzD,QAAM,eAAe,cAAc,iBAAiB;AAEpD,QAAM,gBACJ,+CAAC,SAAI,WAAU,2CACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU;AAAA,QAET;AAAA;AAAA,IACH;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU;AAAA,QAET,qBAAW,cAAc;AAAA;AAAA,IAC5B;AAAA,KACF;AAGF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ;AAAA,MACR,SAAS,WAAW,MAAM;AAAA,MAAC,IAAI;AAAA,MAC/B;AAAA,MACA,QAAQ;AAAA,MACR,UAAS;AAAA,MAET,yDAAC,SAAI,WAAU,iCAEb;AAAA,uDAAC,SAAI,WAAU,2CACb;AAAA,yDAAC,SAAI,WAAU,wCAAuC,SAAS,mBAC7D;AAAA,0DAAC,mBAAgB,OAAO,cAAc,MAAM,QAAQ,cAAc,MAAM,IAAI;AAAA,YAC5E,8CAAC,SAAI,WAAU,2CACb,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,4DAAC,UAAK,GAAE,qFAAoF;AAAA,cAC5F,8CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,eAChC,GACF;AAAA,aACF;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS;AAAA,cACT,MAAK;AAAA,cACL,UAAU;AAAA,cAET;AAAA;AAAA,UACH;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,OAAO,EAAE,SAAS,OAAO;AAAA,cACzB,eAAY;AAAA;AAAA,UACd;AAAA,WACF;AAAA,QAGA,+CAAC,SAAI,WAAU,kCACb;AAAA,wDAAC,WAAM,WAAU,kCAAkC,qBAAU;AAAA,UAC7D;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAK;AAAA,cACL,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,cACvC,aAAa;AAAA,cACb,UAAU;AAAA,cACV,WAAW;AAAA;AAAA,UACb;AAAA,WACF;AAAA,QAGA,+CAAC,SAAI,WAAU,kCACb;AAAA,wDAAC,WAAM,WAAU,kCAAkC,4BAAiB;AAAA,UACpE;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,cAC9C,aAAa;AAAA,cACb,UAAU;AAAA,cACV,MAAM;AAAA,cACN,WAAW;AAAA;AAAA,UACb;AAAA,WACF;AAAA,QAGC,iBACC,+CAAC,SAAI,WAAU,yEACb;AAAA,wDAAC,WAAM,WAAU,kCAAkC,uBAAY;AAAA,UAC/D;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,MAAK;AAAA,cACL,gBAAc;AAAA,cACd,WAAW,mCAAmC,WAAW,wCAAwC,EAAE;AAAA,cACnG,SAAS,MAAM,YAAY,OAAK,CAAC,CAAC;AAAA,cAClC,UAAU;AAAA,cAEV,wDAAC,UAAK,WAAU,yCAAwC;AAAA;AAAA,UAC1D;AAAA,WACF;AAAA,QAID,SACC,+CAAC,SAAI,WAAU,kCACb;AAAA,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,0DAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,YAC/B,8CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,YACrC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK;AAAA,aAC3C;AAAA,UACC;AAAA,WACH;AAAA,SAEJ;AAAA;AAAA,EACF;AAEJ,CAAC;AAED,iBAAiB,cAAc;;;AC/Q/B,IAAAC,iBAAyE;;;ACAzE,IAAAC,iBAAyC;AAgDjC,IAAAC,uBAAA;AA1BD,IAAM,QAA8B,eAAAC,QAAM,KAAK,CAAC;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,eAAW,uBAAuB,IAAI;AAG5C,gCAAU,MAAM;AACd,QAAI,UAAU,SAAS,SAAS;AAC9B,eAAS,QAAQ,MAAM;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,cAAc,SAAS,uBAAuB,EAAE,GAAG,YAAY,IAAI,SAAS,KAAK,EAAE;AAAA,MAC9F,UAAU;AAAA,MAET;AAAA,wBACC,gBAEA,+CAAC,SAAI,WAAU,uBACb;AAAA,wDAAC,YAAO,WAAU,qBAAoB,SAAS,SAAS,cAAW,QACjE,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,wDAAC,cAAS,QAAO,mBAAkB,GACrC,GACF;AAAA,UACC,SAAS,8CAAC,QAAG,WAAU,sBAAsB,iBAAM;AAAA,WACtD;AAAA,QAEF,8CAAC,SAAI,WAAU,qBACZ,UACH;AAAA;AAAA;AAAA,EACF;AAEJ,CAAC;AACD,MAAM,cAAc;;;ADjDO,IAAAC,uBAAA;AAH3B,IAAM,gBAAgB,CAAC,QAAgB,IAAI,UAAU,KAAK,EAAE,QAAQ,oBAAoB,EAAE;AAE1F,IAAM,kBAA4D,eAAAC,QAAM,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM;AAC/F,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO,+EAAG,gBAAK;AAEjC,QAAM,YAAY,cAAc,IAAI,EAAE,YAAY;AAClD,MAAI,CAAC,UAAW,QAAO,+EAAG,gBAAK;AAE/B,QAAM,QAAQ,CAAC;AACf,MAAI,eAAe;AACnB,QAAM,YAAY,cAAc,IAAI,EAAE,YAAY;AAElD,SAAO,MAAM;AACX,UAAM,aAAa,UAAU,QAAQ,WAAW,YAAY;AAC5D,QAAI,eAAe,IAAI;AACrB,UAAI,eAAe,KAAK,QAAQ;AAC9B,cAAM,KAAK,8CAAC,UAAyB,eAAK,MAAM,YAAY,KAAtC,YAAwC,CAAO;AAAA,MACvE;AACA;AAAA,IACF;AAEA,QAAI,aAAa,cAAc;AAC7B,YAAM,KAAK,8CAAC,UAAmC,eAAK,MAAM,cAAc,UAAU,KAA5D,QAAQ,YAAY,EAA0C,CAAO;AAAA,IAC7F;AAEA,UAAM,WAAW,aAAa,UAAU;AACxC,UAAM;AAAA,MACJ,8CAAC,UAAgC,WAAU,iCACxC,eAAK,MAAM,YAAY,QAAQ,KADvB,QAAQ,UAAU,EAE7B;AAAA,IACF;AAEA,mBAAe;AAAA,EACjB;AAEA,SAAO,+EAAG,gBAAM,SAAS,IAAI,QAAQ,MAAK;AAC5C,CAAC;AACD,gBAAgB,cAAc;AAKvB,IAAM,qBAAwD,eAAAA,QAAM,KAAK,CAAC;AAAA,EAC/E;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,aAAa;AACf,MAAM;AACJ,QAAM,EAAE,mBAAmB,IAAI,cAAc;AAE7C,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAS,EAAE;AACrC,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAgC,CAAC,CAAC;AAChE,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,KAAK;AAC5C,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,KAAK;AAC5C,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,KAAK;AAEpD,QAAM,kBAAc,uBAA6C,IAAI;AACrE,QAAM,gBAAY,uBAAuB,IAAI;AAC7C,QAAM,eAAW,uBAAyB,IAAI;AAC9C,QAAM,gBAAY,uBAAO,CAAC;AAC1B,QAAM,eAAW,uBAAO,EAAE;AAG1B,gCAAU,MAAM;AACd,aAAS,EAAE;AACX,eAAW,CAAC,CAAC;AACb,eAAW,KAAK;AAChB,eAAW,KAAK;AAChB,mBAAe,KAAK;AACpB,cAAU,UAAU;AACpB,aAAS,UAAU;AAAA,EACrB,GAAG,CAAC,SAAS,KAAK,MAAM,CAAC;AAGzB,gCAAU,MAAM;AACd,QAAI,QAAQ;AACV,iBAAW,MAAM,SAAS,SAAS,MAAM,GAAG,GAAG;AAAA,IACjD;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAGX,QAAM,wBAAoB,4BAAY,CAAC,MAA2C;AAChF,UAAM,QAAQ,EAAE,OAAO;AACvB,aAAS,KAAK;AAEd,QAAI,YAAY,QAAS,cAAa,YAAY,OAAO;AAEzD,QAAI,CAAC,MAAM,KAAK,GAAG;AACjB,iBAAW,CAAC,CAAC;AACb,iBAAW,KAAK;AAChB,iBAAW,KAAK;AAChB,gBAAU,UAAU;AACpB,eAAS,UAAU;AACnB;AAAA,IACF;AAEA,eAAW,IAAI;AAEf,gBAAY,UAAU,WAAW,YAAY;AAC3C,eAAS,UAAU;AACnB,gBAAU,UAAU;AAEpB,UAAI;AACF,cAAM,WAAW,MAAM,QAAQ,cAAc,OAAO,CAAC;AAErD,YAAI,SAAS,YAAY,MAAO;AAEhC,YAAI,CAAC,UAAU;AACb,qBAAW,CAAC,CAAC;AACb,qBAAW,KAAK;AAAA,QAClB,OAAO;AACL,qBAAW,SAAS,YAAY,CAAC,CAAC;AAClC,sBAAY,SAAS,UAAU,UAAU,MAAM,EAAE;AAAA,QACnD;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,kBAAkB,GAAG;AACnC,mBAAW,CAAC,CAAC;AACb,mBAAW,KAAK;AAAA,MAClB,UAAE;AACA,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF,GAAG,UAAU;AAAA,EACf,GAAG,CAAC,SAAS,UAAU,CAAC;AAGxB,QAAM,qBAAiB,4BAAY,YAAY;AAC7C,QAAI,eAAe,CAAC,WAAW,CAAC,SAAS,QAAS;AAElD,mBAAe,IAAI;AACnB,UAAM,aAAa,UAAU,UAAU;AAEvC,QAAI;AACF,YAAM,WAAW,MAAM,QAAQ,cAAc,SAAS,SAAS,UAAU;AAEzE,UAAI,CAAC,YAAY,CAAC,SAAS,UAAU,QAAQ;AAC3C,mBAAW,KAAK;AAAA,MAClB,OAAO;AACL,kBAAU,UAAU;AACpB,mBAAW,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,QAAQ,CAAC;AACpD,mBAAW,SAAS,SAAS,UAAU,EAAE;AAAA,MAC3C;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,oCAAoC,GAAG;AAAA,IACvD,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,SAAS,SAAS,WAAW,CAAC;AAGlC,QAAM,mBAAe,4BAAY,MAAM;AACrC,UAAM,KAAK,UAAU;AACrB,QAAI,CAAC,GAAI;AAET,UAAM,YAAY;AAClB,QAAI,GAAG,YAAY,GAAG,gBAAgB,GAAG,eAAe,WAAW;AACjE,qBAAe;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAGnB,QAAM,wBAAoB,4BAAY,CAAC,cAAsB;AAC3D,uBAAmB,SAAS;AAAA,EAC9B,GAAG,CAAC,kBAAkB,CAAC;AAGvB,QAAM,eAAW,wBAAQ,MAAM;AAC7B,UAAM,WAAW,aAAa,QAAQ,KAAK;AAC3C,UAAM,QAAyB,CAAC;AAChC,eAAW,CAAC,IAAI,IAAI,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACjD,YAAM,GAAG,YAAY,CAAC,IAAI;AAAA,IAC5B;AACA,WAAO,EAAE,UAAU,MAAM;AAAA,EAC3B,GAAG,CAAC,QAAQ,KAAK,CAAC;AAElB,SACE,+CAAC,SAAM,QAAgB,SAAkB,OAAc,WAAU,sBAE/D;AAAA,kDAAC,SAAI,WAAU,kCACb,yDAAC,SAAI,WAAU,kCACb;AAAA,qDAAC,SAAI,WAAU,kCAAiC,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAChL;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,QAC9B,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,SAAQ;AAAA,SAC9C;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,WAAU;AAAA,UACV,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU;AAAA,UACV;AAAA;AAAA,MACF;AAAA,MACC,SACC;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,MAAM;AACb,qBAAS,EAAE;AACX,uBAAW,CAAC,CAAC;AACb,uBAAW,KAAK;AAChB,sBAAU,UAAU;AACpB,qBAAS,UAAU;AACnB,qBAAS,SAAS,MAAM;AAAA,UAC1B;AAAA,UACA,cAAW;AAAA,UAEX,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,0DAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK;AAAA,YACpC,8CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,aACtC;AAAA;AAAA,MACF;AAAA,OAEJ,GACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,WAAU;AAAA,QACV,UAAU;AAAA,QAGT;AAAA,WAAC,MAAM,KAAK,KAAK,CAAC,WAAW,QAAQ,WAAW,KAC/C,+CAAC,SAAI,WAAU,4BACb;AAAA,2DAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI;AAAA,4DAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,cAC9B,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,SAAQ;AAAA,eAC9C;AAAA,YACA,8CAAC,UAAM,uBAAY;AAAA,aACrB;AAAA,UAID,WACC,+CAAC,SAAI,WAAU,+BACb;AAAA,0DAAC,SAAI,WAAU,+BAA8B;AAAA,YAC7C,8CAAC,UAAM,uBAAY;AAAA,aACrB;AAAA,UAID,CAAC,WAAW,MAAM,KAAK,KAAK,QAAQ,WAAW,KAC9C,8CAAC,SAAI,WAAU,6BACb,wDAAC,UAAM,qBAAU,GACnB;AAAA,UAID,CAAC,WAAW,QAAQ,IAAI,CAAC,QAAQ;AAChC,gBAAI,aAAa;AACjB,gBAAI,IAAI,MAAM;AAEZ,2BAAa,0BAA0B,IAAI,MAAM,KAAY,SAAS,QAAQ;AAE9E,kBAAI,mBAAmB,KAAK,UAAU,GAAG;AACvC,6BAAa,WAAW,QAAQ,qBAAqB,CAAC,UAAU;AAC9D,wBAAM,YAAY,MAAM,MAAM,CAAC,EAAE,YAAY;AAC7C,yBAAO,SAAS,MAAM,SAAS,IAAI,IAAI,SAAS,MAAM,SAAS,CAAC,KAAK;AAAA,gBACvE,CAAC;AAAA,cACH;AAAA,YACF;AAEA,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,MAAK;AAAA,gBACL,UAAU;AAAA,gBACV,WAAU;AAAA,gBACV,SAAS,MAAM,kBAAkB,IAAI,EAAE;AAAA,gBACvC,WAAW,CAAC,MAAM;AAChB,sBAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,sBAAE,eAAe;AACjB,sCAAkB,IAAI,EAAE;AAAA,kBAC1B;AAAA,gBACF;AAAA,gBAEA;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO,IAAI,MAAM,UAAU,IAAI,MAAM,SAAS,IAAI,MAAM;AAAA,sBACxD,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,sBAC5B,MAAM;AAAA;AAAA,kBACR;AAAA,kBACA,+CAAC,SAAI,WAAU,mCACb;AAAA,mEAAC,SAAI,WAAU,mCACb;AAAA,oEAAC,UAAK,WAAU,mCACb,cAAI,MAAM,QAAQ,IAAI,WAAW,WACpC;AAAA,sBACA,8CAAC,UAAK,WAAU,mCACb,cAAI,aAAa,mBAAmB,IAAI,UAAU,IAAI,IACzD;AAAA,uBACF;AAAA,oBACA,8CAAC,OAAE,WAAU,mCACV,uBACC,8CAAC,mBAAgB,MAAM,YAAY,MAAM,OAAO,IAEhD,8CAAC,QAAG,wBAAU,GAElB;AAAA,qBACF;AAAA;AAAA;AAAA,cAjCK,IAAI;AAAA,YAkCX;AAAA,UAEJ,CAAC;AAAA,UAGA,CAAC,WAAW,CAAC,eAAe,CAAC,WAAW,QAAQ,SAAS,KAAK,MAAM,KAAK,KACxE,8CAAC,SAAI,WAAU,qCACb,wDAAC,UAAM,qBAAU,GACnB;AAAA,UAID,eACC,8CAAC,SAAI,WAAU,oCACb,wDAAC,SAAI,WAAU,kEAAiE,GAClF;AAAA;AAAA;AAAA,IAEJ;AAAA,KACF;AAEJ,CAAC;AACD,mBAAmB,cAAc;;;AE5UjC,IAAAC,iBAA2C;AA2NjC,IAAAC,uBAAA;AAvNH,IAAM,uBAA4D,eAAAC,QAAM,KAAK,CAAC;AAAA,EACnF;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,kBAAkB;AAAA,IAChB,EAAE,OAAO,OAAO,OAAO,EAAE;AAAA,IACzB,EAAE,OAAO,OAAO,OAAO,IAAM;AAAA,IAC7B,EAAE,OAAO,OAAO,OAAO,IAAM;AAAA,IAC7B,EAAE,OAAO,MAAM,OAAO,IAAM;AAAA,IAC5B,EAAE,OAAO,MAAM,OAAO,IAAO;AAAA,IAC7B,EAAE,OAAO,OAAO,OAAO,IAAO;AAAA,IAC9B,EAAE,OAAO,MAAM,OAAO,KAAQ;AAAA,EAChC;AACF,MAAM;AAEJ,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAiB,CAAC;AAClD,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAkC;AAAA,IACxE,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,sBAAsB;AAAA,IACtB,sBAAsB;AAAA,IACtB,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,EACf,CAAC;AAED,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAmB,CAAC,CAAC;AACrD,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAS,EAAE;AAC/C,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,KAAK;AAC9C,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAwB,IAAI;AAGtD,gCAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,UAAM,WAAW,CAAC,aAAa,QAAQ,SAAS;AAC9C,cAAQ,IAAI,kBAAkB,UAAU;AACxC,kBAAa,YAAY,2BAAsC,CAAC;AAChE,kBAAa,YAAY,gBAA6B,CAAC,CAAC;AAExD,YAAM,OAAO,YAAY,uBAAmC,CAAC;AAC7D,sBAAgB;AAAA,QACd,gBAAgB,KAAK,SAAS,cAAc;AAAA,QAC5C,cAAc,KAAK,SAAS,YAAY;AAAA,QACxC,sBAAsB,KAAK,SAAS,oBAAoB;AAAA,QACxD,sBAAsB,KAAK,SAAS,oBAAoB;AAAA,QACxD,iBAAiB,KAAK,SAAS,eAAe;AAAA,QAC9C,eAAe,KAAK,SAAS,aAAa;AAAA,QAC1C,eAAe,KAAK,SAAS,aAAa;AAAA,QAC1C,aAAa,KAAK,SAAS,WAAW;AAAA,MACxC,CAAC;AACD,eAAS,IAAI;AAAA,IACf;AAEA,QAAI,QAAQ;AACV,eAAS;AAAA,IACX;AAGA,UAAM,eAAe,QAAQ,GAAG,mBAAmB,CAAC,UAAe;AACjE,YAAM,aAAa,OAAO,WAAW,QAAQ;AAE7C,UAAI,OAAO,WAAW,QAAQ,MAAM;AAClC,eAAO,OAAO,QAAQ,MAAM,MAAM,OAAO;AAAA,MAC3C;AAEA,UAAI,QAAQ;AACV,iBAAS,UAAU;AAAA,MACrB;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,oBAAc,YAAY;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,QAAM,mBAAmB,CAAC,QAAgB;AACxC,oBAAgB,WAAS,EAAE,GAAG,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,GAAG,EAAE,EAAE;AAAA,EAC1D;AAGA,QAAM,oBAAoB,cAAe,SAAS,MAAM,2BAAsC;AAE9F,QAAM,wBAAwB,CAAC,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG;AAC3D,QAAM,yBAAyB,CAAC,GAAK,SAAS,MAAM,gBAA6B,CAAC,CAAE,EAAE,KAAK,EAAE,KAAK,GAAG;AACrG,QAAM,oBAAoB,0BAA0B;AAEpD,QAAM,uBAAuB,SAAS,MAAM,uBAAmC,CAAC;AAChF,QAAM,sBAA+C;AAAA,IACnD,gBAAgB,qBAAqB,SAAS,cAAc;AAAA,IAC5D,cAAc,qBAAqB,SAAS,YAAY;AAAA,IACxD,sBAAsB,qBAAqB,SAAS,oBAAoB;AAAA,IACxE,sBAAsB,qBAAqB,SAAS,oBAAoB;AAAA,IACxE,iBAAiB,qBAAqB,SAAS,eAAe;AAAA,IAC9D,eAAe,qBAAqB,SAAS,aAAa;AAAA,IAC1D,eAAe,qBAAqB,SAAS,aAAa;AAAA,IAC1D,aAAa,qBAAqB,SAAS,WAAW;AAAA,EACxD;AACA,QAAM,wBAAwB,OAAO,KAAK,YAAY,EAAE,KAAK,OAAK,aAAa,CAAC,MAAM,oBAAoB,CAAC,CAAC;AAE5G,QAAM,UAAU,qBAAqB,qBAAqB;AAE1D,QAAM,sBAAsB,MAAM;AAChC,QAAI,WAAW,KAAK,GAAG;AACrB,YAAM,UAAU,WAAW,KAAK,EAAE,YAAY;AAC9C,UAAI,CAAC,SAAS,SAAS,OAAO,GAAG;AAC/B,oBAAY,UAAQ,CAAC,GAAG,MAAM,OAAO,CAAC;AAAA,MACxC;AACA,oBAAc,EAAE;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,gBAAgB,CAAC,MAA6C;AAClE,QAAI,EAAE,QAAQ,SAAS;AACrB,QAAE,eAAe;AACjB,0BAAoB;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,qBAAqB,CAAC,OAAe;AACzC,gBAAY,UAAQ,KAAK,OAAO,OAAK,MAAM,EAAE,CAAC;AAAA,EAChD;AAEA,QAAM,aAAa,YAAY;AAC7B,QAAI,CAAC,QAAS;AACd,gBAAY,IAAI;AAChB,aAAS,IAAI;AACb,QAAI;AACF,YAAM,cAAmB,CAAC;AAC1B,UAAI,oBAAqC;AAEzC,UAAI,mBAAmB;AACrB,oBAAY,0BAA0B;AAAA,MACxC;AAEA,UAAI,mBAAmB;AACrB,oBAAY,eAAe;AAAA,MAC7B;AAEA,UAAI,uBAAuB;AACzB,cAAM,iBAAiB,OAAO,KAAK,YAAY;AAC/C,cAAM,eAAgB,QAAQ,MAAM,uBAAoC,CAAC;AAGzE,cAAM,gBAAgB,aAAa,OAAO,OAAK,CAAC,eAAe,SAAS,CAAC,CAAC;AAG1E,cAAM,qBAAqB,eAAe,OAAO,OAAK,aAAa,CAA8B,CAAC;AAGlG,4BAAoB,CAAC,GAAG,eAAe,GAAG,kBAAkB;AAAA,MAC9D;AAEA,UAAI,OAAO,KAAK,WAAW,EAAE,SAAS,KAAK,sBAAsB,MAAM;AACrE,cAAM,UAAe,CAAC;AAEtB,YAAI,OAAO,KAAK,WAAW,EAAE,SAAS,GAAG;AACvC,kBAAQ,OAAO;AACf,cAAI,QAAQ,KAAM,QAAO,OAAO,QAAQ,MAAM,WAAW;AAAA,QAC3D;AAEA,YAAI,sBAAsB,MAAM;AAC9B,kBAAQ,eAAe;AACvB,cAAI,QAAQ,MAAM;AAEhB,oBAAQ,KAAK,sBAAsB;AAAA,UACrC;AAAA,QACF;AAGA,cAAO,QAAgB,QAAQ,OAAO;AAAA,MACxC;AACA,cAAQ;AAAA,IACV,SAAS,KAAU;AACjB,eAAS,KAAK,WAAW,2BAA2B;AAAA,IACtD,UAAE;AACA,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF;AAGA,SACE,+CAAC,SAAM,QAAgB,SAAkB,OAAc,WAAU,wBAM/D;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,UACL,MAAM;AAAA,UACN,WAAW;AAAA,UACX,SAAS;AAAA,UACT,WAAW;AAAA,UACX,SAAS;AAAA,UACT,eAAe;AAAA,UACf,KAAK;AAAA,UACL,YAAY;AAAA,QACd;AAAA,QAIA;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,WAAW;AAAA,gBACX,QAAQ;AAAA,cACV;AAAA,cAEA;AAAA,+DAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,cAAc,QAAQ,KAAK,MAAM,GACpF;AAAA,gEAAC,SAAI,OAAO,EAAE,YAAY,oCAAoC,SAAS,OAAO,cAAc,OAAO,OAAO,6BAA6B,GACrI,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI,wDAAC,UAAK,GAAE,+CAA8C,GACxD,GACF;AAAA,kBACA,8CAAC,QAAG,OAAO,EAAE,UAAU,QAAQ,OAAO,6BAA6B,YAAY,KAAK,QAAQ,EAAE,GAAG,gCAEjG;AAAA,mBACF;AAAA,gBAEA,+CAAC,SAAI,WAAU,+BAA8B,OAAO,EAAE,cAAc,OAAO,GACzE;AAAA,gEAAC,WAAM,OAAO,EAAE,SAAS,SAAS,cAAc,OAAO,YAAY,KAAK,UAAU,QAAQ,OAAO,+BAA+B,eAAe,aAAa,eAAe,QAAQ,GAAG,uBAEtL;AAAA,kBACA,+CAAC,SAAI,OAAO,EAAE,UAAU,WAAW,GACjC;AAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO;AAAA,wBACP,UAAU,OAAK,YAAY,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,wBACjD,OAAO;AAAA,0BACL,OAAO;AAAA,0BACP,SAAS;AAAA,0BACT,cAAc;AAAA,0BACd,QAAQ;AAAA,0BACR,YAAY;AAAA,0BACZ,OAAO;AAAA,0BACP,UAAU;AAAA,0BACV,YAAY;AAAA,0BACZ,YAAY;AAAA,0BACZ,SAAS;AAAA,0BACT,QAAQ,WAAW,gBAAgB;AAAA,0BACnC,YAAY;AAAA,wBACd;AAAA,wBACA,UAAU;AAAA,wBAET,0BAAgB,IAAI,SACnB,8CAAC,YAAuB,OAAO,IAAI,OAAQ,cAAI,SAAlC,IAAI,KAAoC,CACtD;AAAA;AAAA,oBACH;AAAA,oBACA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,OAAO,QAAQ,KAAK,OAAO,WAAW,oBAAoB,eAAe,QAAQ,OAAO,8BAA8B,GACxJ,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,wDAAC,cAAS,QAAO,kBAAiB,GACpC,GACF;AAAA,qBACF;AAAA,mBACF;AAAA,gBAEA,+CAAC,SAAI,WAAU,iCAAgC,OAAO,EAAE,SAAS,QAAQ,eAAe,SAAS,GAC/F;AAAA,gEAAC,WAAM,OAAO,EAAE,SAAS,SAAS,cAAc,OAAO,YAAY,KAAK,UAAU,QAAQ,OAAO,+BAA+B,eAAe,aAAa,eAAe,QAAQ,GAAG,0BAEtL;AAAA,kBACA,8CAAC,SAAI,OAAO,EAAE,YAAY,6BAA6B,cAAc,OAAO,UAAU,UAAU,QAAQ,sCAAsC,GAC3I,iBAAO,QAAQ,YAAY,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,GAAG,OAAO,QACtD;AAAA,oBAAC;AAAA;AAAA,sBAEC,OAAO;AAAA,wBACL,SAAS;AAAA,wBACT,YAAY;AAAA,wBACZ,gBAAgB;AAAA,wBAChB,SAAS;AAAA,wBACT,cAAc,QAAQ,IAAI,SAAS,IAAI,wCAAwC;AAAA,sBACjF;AAAA,sBAEA;AAAA,sEAAC,UAAK,OAAO,EAAE,UAAU,QAAQ,YAAY,KAAK,OAAO,4BAA4B,GAClF,cAAI,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,GAAG,GAC3E;AAAA,wBACA;AAAA,0BAAC;AAAA;AAAA,4BACC,MAAK;AAAA,4BACL,MAAK;AAAA,4BACL,gBAAc;AAAA,4BACd,WAAW,mCAAmC,QAAQ,wCAAwC,EAAE;AAAA,4BAChG,SAAS,MAAM,iBAAiB,GAAG;AAAA,4BACnC,UAAU;AAAA,4BACV,OAAO,EAAE,WAAW,eAAe,iBAAiB,eAAe;AAAA,4BAEnE,wDAAC,UAAK,WAAU,yCAAwC;AAAA;AAAA,wBAC1D;AAAA;AAAA;AAAA,oBAtBK;AAAA,kBAuBP,CACD,GACH;AAAA,mBACF;AAAA;AAAA;AAAA,UACF;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,WAAW;AAAA,gBACX,QAAQ;AAAA,cACV;AAAA,cAEA;AAAA,+DAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,cAAc,QAAQ,KAAK,MAAM,GACpF;AAAA,gEAAC,SAAI,OAAO,EAAE,YAAY,mCAAmC,SAAS,OAAO,cAAc,OAAO,OAAO,4BAA4B,GACnI,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI;AAAA,kEAAC,UAAK,GAAE,4FAA2F;AAAA,oBACnG,8CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,oBACrC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK;AAAA,qBAC3C,GACF;AAAA,kBACA,8CAAC,QAAG,OAAO,EAAE,UAAU,QAAQ,OAAO,6BAA6B,YAAY,KAAK,QAAQ,EAAE,GAAG,gCAEjG;AAAA,mBACF;AAAA,gBAEA,+CAAC,SAAI,WAAU,+BAA8B,OAAO,EAAE,cAAc,OAAO,GACzE;AAAA,gEAAC,WAAM,OAAO,EAAE,SAAS,SAAS,cAAc,OAAO,YAAY,KAAK,UAAU,QAAQ,OAAO,+BAA+B,eAAe,aAAa,eAAe,QAAQ,GAAG,+BAEtL;AAAA,kBACA,+CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,OAAO,UAAU,WAAW,GAC9D;AAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,OAAO;AAAA,wBACP,UAAU,OAAK,cAAc,EAAE,OAAO,KAAK;AAAA,wBAC3C,WAAW;AAAA,wBACX,aAAY;AAAA,wBACZ,OAAO;AAAA,0BACL,MAAM;AAAA,0BACN,UAAU;AAAA,0BACV,SAAS;AAAA,0BACT,cAAc;AAAA,0BACd,QAAQ;AAAA,0BACR,YAAY;AAAA,0BACZ,OAAO;AAAA,0BACP,UAAU;AAAA,0BACV,SAAS;AAAA,wBACX;AAAA,wBACA,UAAU;AAAA;AAAA,oBACZ;AAAA,oBACA;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,SAAS;AAAA,wBACT,UAAU,YAAY,CAAC,WAAW,KAAK;AAAA,wBACvC,OAAO;AAAA,0BACL,SAAS;AAAA,0BACT,cAAc;AAAA,0BACd,YAAY;AAAA,0BACZ,OAAO;AAAA,0BACP,QAAQ;AAAA,0BACR,YAAY;AAAA,0BACZ,UAAU;AAAA,0BACV,QAAQ,YAAY,CAAC,WAAW,KAAK,IAAI,gBAAgB;AAAA,0BACzD,SAAS,YAAY,CAAC,WAAW,KAAK,IAAI,MAAM;AAAA,0BAChD,YAAY;AAAA,0BACZ,SAAS;AAAA,0BACT,YAAY;AAAA,0BACZ,gBAAgB;AAAA,wBAClB;AAAA,wBACD;AAAA;AAAA,oBAED;AAAA,qBACF;AAAA,mBACF;AAAA,gBAEA,+CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,UAAU,QAAQ,KAAK,OAAO,WAAW,OAAO,GAC5E;AAAA,2BAAS,IAAI,QACZ;AAAA,oBAAC;AAAA;AAAA,sBAEC,OAAO;AAAA,wBACL,SAAS;AAAA,wBACT,YAAY;AAAA,wBACZ,KAAK;AAAA,wBACL,SAAS;AAAA,wBACT,cAAc;AAAA,wBACd,YAAY;AAAA,wBACZ,OAAO;AAAA,wBACP,QAAQ;AAAA,wBACR,UAAU;AAAA,wBACV,YAAY;AAAA,sBACd;AAAA,sBAEC;AAAA;AAAA,wBACD;AAAA,0BAAC;AAAA;AAAA,4BACC,SAAS,MAAM,mBAAmB,EAAE;AAAA,4BACpC,OAAO;AAAA,8BACL,SAAS;AAAA,8BACT,YAAY;AAAA,8BACZ,gBAAgB;AAAA,8BAChB,YAAY;AAAA,8BACZ,QAAQ;AAAA,8BACR,QAAQ;AAAA,8BACR,SAAS;AAAA,8BACT,OAAO;AAAA,8BACP,SAAS;AAAA,4BACX;AAAA,4BACA,UAAU;AAAA,4BACV,cAAW;AAAA,4BAEX,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI;AAAA,4EAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK;AAAA,8BACpC,8CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,+BACtC;AAAA;AAAA,wBACF;AAAA;AAAA;AAAA,oBAnCK;AAAA,kBAoCP,CACD;AAAA,kBACA,SAAS,WAAW,KACnB,8CAAC,UAAK,OAAO,EAAE,UAAU,QAAQ,OAAO,+BAA+B,SAAS,SAAS,WAAW,SAAS,GAAG,4CAEhH;AAAA,mBAEJ;AAAA;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,IAEF;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,UACL,YAAY;AAAA,UACZ,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,WAAW;AAAA,UACX,SAAS;AAAA,UACT,eAAe;AAAA,UACf,KAAK;AAAA,QACP;AAAA,QAEC;AAAA,mBACC,+CAAC,SAAI,OAAO,EAAE,OAAO,6BAA6B,UAAU,QAAQ,SAAS,QAAQ,YAAY,UAAU,KAAK,OAAO,YAAY,IAAI,GACrI;AAAA,2DAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ;AAAA,4DAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,cAAE,8CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,cAAE,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK;AAAA,eAAE;AAAA,YAC5O;AAAA,aACH;AAAA,UAEF;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,UAAU,YAAY,CAAC;AAAA,cACvB,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,QAAS,YAAY,CAAC,UAAW,gBAAgB;AAAA,gBACjD,SAAU,YAAY,CAAC,UAAW,MAAM;AAAA,gBACxC,YAAY;AAAA,gBACZ,WAAY,YAAY,CAAC,UAAW,SAAS;AAAA,cAC/C;AAAA,cAEC,qBACC,+CAAC,UAAK,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,gBAAgB,UAAU,KAAK,MAAM,GACzF;AAAA,8DAAC,SAAI,WAAU,iBAAgB,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SACxI,wDAAC,UAAK,GAAE,+BAA8B,GACxC;AAAA,gBAAM;AAAA,iBAER,IACE;AAAA;AAAA,UACN;AAAA;AAAA;AAAA,IACF;AAAA,KAEF;AAEJ,CAAC;AAED,qBAAqB,cAAc;;;Ab1c/B,IAAAC,uBAAA;AAFG,IAAM,2BAA6D,eAAAC,QAAM,KAAK,CAAC,EAAE,OAAO,QAAQ,MAAM;AAC3G,SACE,+CAAC,SAAI,WAAU,8BACb;AAAA,kDAAC,QAAG,WAAU,6BAA6B,iBAAM;AAAA,IAChD,WACC,8CAAC,YAAO,WAAU,6BAA4B,SAAS,SAAS,cAAW,SACzE,wDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,OAAM,8BAChE,wDAAC,UAAK,GAAE,wBAAuB,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,GACpH,GACF;AAAA,KAEJ;AAEJ,CAAC;AACD,yBAAyB,cAAc;AAEhC,IAAM,0BAA2D,eAAAA,QAAM,KAAK,CAAC,EAAE,aAAa,cAAc,oBAAoB,iBAAiB,SAAS,aAAa,UAAU,cAAc,MAAM;AACxM,SACE,+CAAC,SAAI,WAAU,6BACb;AAAA,kDAAC,mBAAgB,OAAO,cAAc,MAAM,aAAa,MAAM,IAAI,WAAU,8BAA6B;AAAA,IAC1G,+CAAC,SAAI,WAAU,gCACb;AAAA,oDAAC,QAAG,WAAU,4BAA4B,uBAAY;AAAA,MACrD,WAAW,eACV,8CAAC,YAAO,WAAU,sCAAqC,SAAS,aAAa,cAAW,gBACtF,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,UAAK,GAAE,8DAA6D;AAAA,QACrE,8CAAC,UAAK,GAAE,2DAA0D;AAAA,SACpE,GACF;AAAA,OAEJ;AAAA,IACC,iBACC,+CAAC,UAAK,WAAW,kCAAkC,WAAW,2CAA2C,yCAAyC,IAC/I;AAAA,iBACC,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAC/B,8CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,QACrC,8CAAC,UAAK,GAAE,8FAA6F;AAAA,SACvG,IAEA,+CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,UAAK,GAAE,KAAI,GAAE,MAAK,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,QACxD,8CAAC,UAAK,GAAE,4BAA2B;AAAA,SACrC;AAAA,MAED,WAAW,WAAW;AAAA,OACzB;AAAA,IAED,sBACC,8CAAC,OAAE,WAAU,mCAAmC,8BAAmB;AAAA,KAEvE;AAEJ,CAAC;AACD,wBAAwB,cAAc;AAE/B,IAAM,4BAA+D,eAAAA,QAAM,KAAK,CAAC;AAAA,EACtF;AAAA,EAAe;AAAA,EAAiB;AAAA,EAAgB;AAAA,EAChD;AAAA,EAAa;AAAA,EACb;AAAA,EAAe;AAAA,EAAW;AAAA,EAC1B,cAAc;AAAA,EAAU,gBAAgB;AAAA,EAAY,cAAc;AAAA,EAAU,aAAa;AAAA,EACzF,aAAa;AAAA,EAAS,eAAe;AACvC,MAAM;AACJ,SACE,+CAAC,SAAI,WAAU,+BACb;AAAA,mDAAC,YAAO,WAAU,kCAAiC,SAAS,eAAe,UAAU,WACnF;AAAA,oDAAC,SAAI,WAAU,mCACb,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,QAC9B,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,SAAQ;AAAA,SAC9C,GACF;AAAA,MACA,8CAAC,UAAM,uBAAY;AAAA,OACrB;AAAA,IACC,kBAAkB,oBAAoB,WAAW,oBAAoB,YACpE,+CAAC,YAAO,WAAU,kCAAiC,SAAS,iBAC1D;AAAA,oDAAC,SAAI,WAAU,mCACb,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,QAC9B,8CAAC,UAAK,GAAE,kuBAAiuB;AAAA,SAC3uB,GACF;AAAA,MACA,8CAAC,UAAM,yBAAc;AAAA,OACvB;AAAA,IAED,kBACC,oBAAoB,UAClB,+CAAC,YAAO,WAAU,yEAAwE,SAAS,iBACjG;AAAA,oDAAC,SAAI,WAAU,mCACb,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,cAAS,QAAO,gBAAe;AAAA,QAChC,8CAAC,UAAK,GAAE,kFAAiF;AAAA,SAC3F,GACF;AAAA,MACA,8CAAC,UAAM,uBAAY;AAAA,OACrB,IAEA,+CAAC,YAAO,WAAU,yEAAwE,SAAS,gBACjG;AAAA,oDAAC,SAAI,WAAU,mCACb,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,UAAK,GAAE,2CAA0C;AAAA,QAClD,8CAAC,cAAS,QAAO,oBAAmB;AAAA,QACpC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,SACvC,GACF;AAAA,MACA,8CAAC,UAAM,sBAAW;AAAA,OACpB;AAAA,IAIH,CAAC,kBACA,YACE,+CAAC,YAAO,WAAU,kCAAiC,SAAS,eAC1D;AAAA,oDAAC,SAAI,WAAU,mCACb,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAC/B,8CAAC,UAAK,IAAG,QAAO,IAAG,QAAO,IAAG,SAAQ,IAAG,SAAQ;AAAA,SAClD,GACF;AAAA,MACA,8CAAC,UAAM,wBAAa;AAAA,OACtB,IAEA,+CAAC,YAAO,WAAU,yEAAwE,SAAS,aACjG;AAAA,oDAAC,SAAI,WAAU,mCACb,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAC/B,8CAAC,UAAK,IAAG,QAAO,IAAG,QAAO,IAAG,SAAQ,IAAG,SAAQ;AAAA,SAClD,GACF;AAAA,MACA,8CAAC,UAAM,sBAAW;AAAA,OACpB;AAAA,KAGN;AAEJ,CAAC;AACD,0BAA0B,cAAc;AAEjC,IAAM,cAA0C,eAAAA,QAAM,KAAK,CAAC,UAAU;AAC3E,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB;AAAA,IACA,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB;AAAA,IACA,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,gBAAgB;AAAA;AAAA,IAEhB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA,aAAa;AAAA,IACb,eAAe;AAAA,IACf;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,EAAE,eAAe,OAAO,IAAI,cAAc;AAChD,QAAM,UAAU,eAAe;AAC/B,QAAM,EAAE,SAAS,IAAI,eAAe,SAAS,QAAQ,MAAM;AAC3D,QAAM,EAAE,UAAU,IAAI,gBAAgB,SAAS,QAAQ,MAAM;AAE7D,QAAM,gBAAgB,QAAQ;AAC9B,QAAM,kBAAkB,gBAAgB,SAAS,OAAO,UAAU,aAAa,GAAG,eAAe;AACjG,QAAM,gBAAgB,SAAS,SAAS;AAExC,QAAM,0BAAsB,4BAAY,YAAY;AAClD,QAAI,oBAAqB,QAAO,oBAAoB;AACpD,QAAI,CAAC,QAAS;AACd,QAAI;AACF,YAAM,QAAQ,OAAO;AAAA,IACvB,SAAS,GAAG;AACV,cAAQ,MAAM,0BAA0B,CAAC;AAAA,IAC3C;AAAA,EACF,GAAG,CAAC,SAAS,mBAAmB,CAAC;AAEjC,QAAM,yBAAqB,4BAAY,YAAY;AACjD,QAAI,mBAAoB,QAAO,mBAAmB;AAClD,QAAI,CAAC,WAAW,CAAC,cAAe;AAChC,QAAI;AACF,YAAM,QAAQ,cAAc,CAAC,aAAa,CAAC;AAAA,IAC7C,SAAS,GAAG;AACV,cAAQ,MAAM,yBAAyB,CAAC;AAAA,IAC1C;AAAA,EACF,GAAG,CAAC,SAAS,eAAe,kBAAkB,CAAC;AAE/C,QAAM,yBAAqB,4BAAY,OAAO,aAAqB;AACjE,QAAI,mBAAoB,QAAO,mBAAmB,QAAQ;AAC1D,QAAI,CAAC,QAAS;AACd,QAAI;AACF,YAAM,QAAQ,cAAc,CAAC,QAAQ,CAAC;AAAA,IACxC,SAAS,GAAG;AACV,cAAQ,MAAM,yBAAyB,CAAC;AAAA,IAC1C;AAAA,EACF,GAAG,CAAC,SAAS,kBAAkB,CAAC;AAEhC,QAAM,sBAAkB,4BAAY,OAAO,aAAqB;AAC9D,QAAI,gBAAiB,QAAO,gBAAgB,QAAQ;AACpD,QAAI,CAAC,QAAS;AACd,QAAI;AAAE,YAAM,QAAQ,WAAW,CAAC,QAAQ,CAAC;AAAA,IAAG,SAAS,GAAG;AAAE,cAAQ,MAAM,wBAAwB,CAAC;AAAA,IAAG;AAAA,EACtG,GAAG,CAAC,SAAS,eAAe,CAAC;AAE7B,QAAM,wBAAoB,4BAAY,OAAO,aAAqB;AAChE,QAAI,kBAAmB,QAAO,kBAAkB,QAAQ;AACxD,QAAI,CAAC,QAAS;AACd,QAAI;AAAE,YAAM,QAAQ,aAAa,CAAC,QAAQ,CAAC;AAAA,IAAG,SAAS,GAAG;AAAE,cAAQ,MAAM,0BAA0B,CAAC;AAAA,IAAG;AAAA,EAC1G,GAAG,CAAC,SAAS,iBAAiB,CAAC;AAE/B,QAAM,0BAAsB,4BAAY,OAAO,aAAqB;AAClE,QAAI,oBAAqB,QAAO,oBAAoB,QAAQ;AAC5D,QAAI,CAAC,QAAS;AACd,QAAI;AAAE,YAAM,QAAQ,cAAc,CAAC,QAAQ,CAAC;AAAA,IAAG,SAAS,GAAG;AAAE,cAAQ,MAAM,0BAA0B,CAAC;AAAA,IAAG;AAAA,EAC3G,GAAG,CAAC,SAAS,mBAAmB,CAAC;AAEjC,QAAM,yBAAqB,4BAAY,OAAO,aAAqB;AACjE,QAAI,mBAAoB,QAAO,mBAAmB,QAAQ;AAC1D,QAAI,CAAC,QAAS;AACd,QAAI;AAAE,YAAM,QAAQ,iBAAiB,CAAC,QAAQ,CAAC;AAAA,IAAG,SAAS,GAAG;AAAE,cAAQ,MAAM,yBAAyB,CAAC;AAAA,IAAG;AAAA,EAC7G,GAAG,CAAC,SAAS,kBAAkB,CAAC;AAEhC,QAAM,sBAAkB,4BAAY,YAAY;AAC9C,QAAI,gBAAiB,QAAO,gBAAgB;AAC5C,QAAI,CAAC,QAAS;AACd,QAAI;AAAE,YAAM,QAAQ,UAAU;AAAA,IAAG,SAAS,GAAG;AAAE,cAAQ,MAAM,uBAAuB,CAAC;AAAA,IAAG;AAAA,EAC1F,GAAG,CAAC,SAAS,eAAe,CAAC;AAE7B,QAAM,wBAAoB,4BAAY,YAAY;AAChD,QAAI,kBAAmB,QAAO,kBAAkB;AAChD,QAAI,CAAC,QAAS;AACd,QAAI;AAAE,YAAM,QAAQ,YAAY;AAAA,IAAG,SAAS,GAAG;AAAE,cAAQ,MAAM,yBAAyB,CAAC;AAAA,IAAG;AAAA,EAC9F,GAAG,CAAC,SAAS,iBAAiB,CAAC;AAE/B,QAAM,EAAE,QAAQ,IAAI,kBAAkB,OAAO;AAC7C,QAAM,EAAE,aAAa,cAAc,mBAAmB,IAAI,kBAAkB,OAAO;AAEnF,QAAM,CAAC,oBAAoB,qBAAqB,QAAI,yBAAS,KAAK;AAClE,QAAM,CAAC,sBAAsB,uBAAuB,QAAI,yBAAS,KAAK;AACtE,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,yBAAS,KAAK;AAC5D,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,yBAAS,KAAK;AAGhE,QAAM,iBAAiB,iBAAiB,CAAC,aAAa,oBAAoB,WAAW,oBAAoB;AAEzG,QAAM,6BAAyB,4BAAY,MAAM;AAC/C,4BAAwB,IAAI;AAAA,EAC9B,GAAG,CAAC,CAAC;AAEL,QAAM,2BAAuB,4BAAY,MAAM;AAC7C,QAAI,iBAAkB,QAAO,iBAAiB;AAC9C,0BAAsB,IAAI;AAAA,EAC5B,GAAG,CAAC,gBAAgB,CAAC;AAIrB,MAAI,CAAC,QAAS,QAAO;AAErB,SACE,+CAAC,SAAI,WAAW,sBAAsB,SAAS,GAAG,KAAK,GACrD;AAAA,kDAAC,mBAAgB,OAAc,SAAkB;AAAA,IAEjD;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU,QAAQ,SAAS,MAAM,MAAM;AAAA,QACvC;AAAA;AAAA,IACF;AAAA,IAEC,WACC,+CAAC,SAAI,WAAU,qCACb;AAAA,oDAAC,SAAI,WAAU,0CACb,yDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SACvI;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAC/B,8CAAC,UAAK,IAAG,QAAO,IAAG,QAAO,IAAG,SAAQ,IAAG,SAAQ;AAAA,SAClD,GACF;AAAA,MACA,8CAAC,UAAK,WAAU,0CAAyC,qDAAuC;AAAA,OAClG,IAEA,gFACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,eAAe,MAAM,mBAAmB,IAAI;AAAA,UAC5C,iBAAiB,MAAM,qBAAqB,IAAI;AAAA,UAChD,gBAAgB;AAAA,UAChB,iBAAiB;AAAA,UACjB,aAAa;AAAA,UACb,eAAe;AAAA,UACf;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb,eAAe;AAAA,UACf,aAAa;AAAA,UACb,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,cAAc;AAAA;AAAA,MAChB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,kBAAkB,gBAAgB,uBAAuB;AAAA,UACzD,gBAAgB;AAAA,UAChB,aAAa;AAAA,UACb,eAAe;AAAA,UACf,iBAAiB;AAAA,UACjB,gBAAgB;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,MAEC,sBAAuB,uBAAM;AAC5B,cAAM,YAAY,2BAA2B;AAC7C,eACE;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,gBAAgB;AAAA,YAChB,SAAS,MAAM,sBAAsB,KAAK;AAAA,YAC1C;AAAA,YACA,OAAO;AAAA,YACP,mBAAmB;AAAA,YACnB,aAAa;AAAA,YACb,WAAW;AAAA,YACX,UAAU;AAAA,YACV,aAAa;AAAA,YACb,YAAY;AAAA;AAAA,QACd;AAAA,MAEJ,GAAG;AAAA,MAEF,wBAAyB,uBAAM;AAC9B,cAAM,WAAW,6BAA6B;AAC9C,eACE;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,SAAS,MAAM,wBAAwB,KAAK;AAAA,YAC5C,QAAQ;AAAA,YACR;AAAA,YACA,OAAO;AAAA,YACP,WAAW;AAAA,YACX,kBAAkB;AAAA,YAClB,iBAAiB;AAAA,YACjB,wBAAwB;AAAA,YACxB,aAAa;AAAA,YACb,WAAW;AAAA,YACX,aAAa;AAAA,YACb,aAAa;AAAA,YACb,mBAAmB;AAAA,YACnB,aAAa;AAAA,YACb,cAAc;AAAA,YACd,mBAAmB;AAAA;AAAA,QACrB;AAAA,MAEJ,GAAG;AAAA,OACL;AAAA,IAID,WAAW,mBACV;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ;AAAA,QACR,SAAS,MAAM,mBAAmB,KAAK;AAAA,QACvC;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IAID,WAAW,qBACV;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ;AAAA,QACR,SAAS,MAAM,qBAAqB,KAAK;AAAA,QACzC;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ,CAAC;AAED,YAAY,cAAc;;;Actc1B,IAAAC,iBAAsD;AAuIhD,IAAAC,uBAAA;AA/HC,IAAM,qBAAwD,CAAC;AAAA,EACpE;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA,QAAQ;AAAA,EACR,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EACxB,8BAA8B;AAAA,EAC9B,mBAAmB;AAAA,EACnB,wBAAwB;AAAA,EACxB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,sBAAsB;AACxB,MAAM;AACJ,QAAM,EAAE,OAAO,IAAI,cAAc;AACjC,QAAM,gBAAgB,QAAQ;AAG9B,QAAM,CAAC,KAAK,MAAM,QAAI,yBAA+B,WAAW;AAChE,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAgB,CAAC;AAGzC,QAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,EAAE;AACnC,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAS,EAAE;AACjD,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,KAAK;AAG9C,QAAM,CAAC,eAAe,gBAAgB,QAAI,yBAA2B,CAAC,CAAC;AAGvE,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAwB,IAAI;AAGtD,QAAM,4BAAwB,wBAAQ,MAAM;AAC1C,QAAI,CAAC,UAAU,CAAC,iBAAiB,QAAQ,YAAa,QAAO,CAAC;AAE9D,UAAM,MAAM,oBAAI,IAAY;AAC5B,WAAO,OAAO,OAAO,cAAc,EAAE,QAAQ,CAAC,YAAiB;AAC7D,UAAI,QAAQ,SAAS,eAAe,QAAQ,OAAO,SAAS;AAC1D,eAAO,KAAK,QAAQ,MAAM,OAAO,EAAE,QAAQ,SAAO;AAChD,cAAI,QAAQ,cAAe,KAAI,IAAI,GAAG;AAAA,QACxC,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AACD,WAAO,MAAM,KAAK,GAAG;AAAA,EACvB,GAAG,CAAC,QAAQ,eAAe,GAAG,CAAC;AAG/B,QAAM,mBAAe,4BAAY,YAAY;AAC3C,QAAI,CAAC,UAAU,CAAC,iBAAiB,WAAY;AAG7C,QAAI,cAAc,WAAW,GAAG;AAC9B,eAAS,kCAAkC;AAC3C;AAAA,IACF;AAEA,QAAI,QAAQ,UAAU,CAAC,KAAK,KAAK,GAAG;AAClC,eAAS,yBAAyB;AAClC;AAAA,IACF;AAEA,kBAAc,IAAI;AAClB,aAAS,IAAI;AAEb,QAAI;AACF,UAAI;AAEJ,UAAI,QAAQ,aAAa;AACvB,cAAM,eAAe,cAAc,CAAC,EAAE;AACtC,yBAAiB,OAAO,QAAQ,aAAa;AAAA,UAC3C,SAAS,CAAC,eAAe,YAAY;AAAA,QACvC,CAAQ;AACR,cAAM,eAAe,OAAO;AAAA,MAC9B,OAAO;AAEL,cAAM,YAAY,cAAc,IAAI,YAAU,OAAO,EAAE;AAEvD,YAAI,CAAC,UAAU,SAAS,aAAa,GAAG;AACtC,oBAAU,KAAK,aAAa;AAAA,QAC9B;AAEA,cAAM,UAAe;AAAA,UACnB,MAAM,KAAK,KAAK;AAAA,UAChB,SAAS;AAAA,UACT,QAAQ;AAAA,QACV;AAEA,YAAI,YAAY,KAAK,GAAG;AACtB,kBAAQ,cAAc,YAAY,KAAK;AAAA,QACzC;AAEA,yBAAiB,OAAO,QAAQ,QAAQ,OAAO;AAC/C,cAAM,eAAe,OAAO;AAAA,MAC9B;AAGA,UAAI,WAAW;AACb,kBAAU,cAAc;AAAA,MAC1B,OAAO;AACL,gBAAQ;AAAA,MACV;AAAA,IAEF,SAAS,KAAU;AACjB,eAAS,KAAK,WAAW,0BAA0B;AAAA,IACrD,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,QAAQ,eAAe,YAAY,eAAe,KAAK,MAAM,UAAU,aAAa,WAAW,OAAO,CAAC;AAG3G,QAAM,cAAU,wBAAQ,MAAM;AAC5B,QAAI,QAAQ,eAAe,cAAc,WAAW,EAAG,QAAO;AAC9D,QAAI,QAAQ,UAAU,SAAS,KAAK,CAAC,KAAK,KAAK,EAAG,QAAO;AACzD,QAAI,QAAQ,UAAU,SAAS,KAAK,cAAc,WAAW,EAAG,QAAO;AACvE,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,KAAK,MAAM,IAAI,CAAC;AAEnC,MAAI;AACJ,MAAI,QAAQ,aAAa;AACvB,aACE,+CAAC,SAAI,WAAU,gCACb;AAAA,oDAAC,YAAO,WAAU,+DAA8D,SAAS,SAAS,UAAU,YAAa,6BAAkB;AAAA,MAC3I,8CAAC,YAAO,WAAU,+DAA8D,SAAS,cAAc,UAAU,cAAc,CAAC,SAC7H,uBAAa,sBAAsB,mBACtC;AAAA,OACF;AAAA,EAEJ,WAAW,QAAQ,UAAU,SAAS,GAAG;AACvC,aACE,+CAAC,SAAI,WAAU,gCACb;AAAA,oDAAC,YAAO,WAAU,+DAA8D,SAAS,SAAS,UAAU,YAAa,6BAAkB;AAAA,MAC3I,8CAAC,YAAO,WAAU,+DAA8D,SAAS,MAAM;AAAE,iBAAS,IAAI;AAAG,gBAAQ,CAAC;AAAA,MAAG,GAAG,UAAU,cAAc,CAAC,SAAS,kBAElK;AAAA,OACF;AAAA,EAEJ,WAAW,QAAQ,UAAU,SAAS,GAAG;AACvC,aACE,+CAAC,SAAI,WAAU,gCACb;AAAA,oDAAC,YAAO,WAAU,+DAA8D,SAAS,MAAM;AAAE,iBAAS,IAAI;AAAG,gBAAQ,CAAC;AAAA,MAAG,GAAG,UAAU,YAAY,kBAAI;AAAA,MAC1J,8CAAC,YAAO,WAAU,+DAA8D,SAAS,cAAc,UAAU,cAAc,CAAC,SAC7H,uBAAa,sBAAsB,mBACtC;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,8CAAC,SAAM,QAAgB,SAAS,aAAa,MAAM;AAAA,EAAE,IAAI,SAAS,OAAc,UAAS,SAAQ,QAC/F,yDAAC,SAAI,WAAU,8BAGb;AAAA,mDAAC,SAAI,WAAU,8BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,6BAA6B,QAAQ,cAAc,sCAAsC,EAAE;AAAA,UACtG,SAAS,MAAM;AACb,mBAAO,WAAW;AAClB,oBAAQ,CAAC;AACT,6BAAiB,CAAC,CAAC;AACnB,qBAAS,IAAI;AAAA,UACf;AAAA,UACA,UAAU;AAAA,UAET;AAAA;AAAA,MACH;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,6BAA6B,QAAQ,SAAS,sCAAsC,EAAE;AAAA,UACjG,SAAS,MAAM;AACb,mBAAO,MAAM;AACb,oBAAQ,CAAC;AACT,6BAAiB,CAAC,CAAC;AACnB,qBAAS,IAAI;AAAA,UACf;AAAA,UACA,UAAU;AAAA,UAET;AAAA;AAAA,MACH;AAAA,OACF;AAAA,IAGC,QAAQ,UAAU,SAAS,KAC1B,gFAEE;AAAA,qDAAC,SAAI,WAAU,+BACb;AAAA,uDAAC,WAAM,WAAU,+BAA+B;AAAA;AAAA,UAAe;AAAA,UAAC,8CAAC,UAAK,OAAO,EAAE,OAAO,qBAAqB,GAAG,eAAC;AAAA,WAAO;AAAA,QACtH;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,YACvC,aAAa;AAAA,YACb,UAAU;AAAA,YACV,WAAW;AAAA;AAAA,QACb;AAAA,SACF;AAAA,MAEA,+CAAC,SAAI,WAAU,+BACb;AAAA,sDAAC,WAAM,WAAU,+BAA+B,iCAAsB;AAAA,QACtE;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA,YAC9C,aAAa;AAAA,YACb,UAAU;AAAA,YACV,WAAW;AAAA,YACX,MAAM;AAAA;AAAA,QACR;AAAA,SACF;AAAA,MAEA,+CAAC,SAAI,WAAU,mEACb;AAAA,sDAAC,WAAM,WAAU,+BAA+B,4BAAiB;AAAA,QACjE;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,MAAK;AAAA,YACL,gBAAc;AAAA,YACd,WAAW,gCAAgC,WAAW,qCAAqC,EAAE;AAAA,YAC7F,SAAS,MAAM,YAAY,OAAK,CAAC,CAAC;AAAA,YAClC,UAAU;AAAA,YAEV,wDAAC,UAAK,WAAU,sCAAqC;AAAA;AAAA,QACvD;AAAA,SACF;AAAA,OACF;AAAA,KAIC,QAAQ,UAAU,SAAS,KAAM,QAAQ,gBAC1C,+CAAC,SAAI,WAAU,+BACb;AAAA,qDAAC,SAAI,WAAU,qCAAoC;AAAA;AAAA,QACzC,8CAAC,UAAK,OAAO,EAAE,OAAO,qBAAqB,GAAG,eAAC;AAAA,SACzD;AAAA,MACA,8CAAC,SAAI,OAAO,EAAE,QAAQ,QAAQ,SAAS,UAAU,SAAS,SAAS,QAAQ,eAAe,SAAS,GACjG;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,QAAQ,cAAc,UAAU;AAAA,UACtC,mBAAmB;AAAA,UACnB,gBAAgB,QAAQ,cAAc,wBAAwB,CAAC;AAAA,UAC/D,sBAAsB;AAAA,UACtB;AAAA,UACA;AAAA,UACA,mBAAmB;AAAA;AAAA,MACrB,GACF;AAAA,OACF;AAAA,IAGD,SACC,+CAAC,SAAI,WAAU,+BACb;AAAA,qDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,sDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,QAC/B,8CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,QACrC,8CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK;AAAA,SAC3C;AAAA,MACC;AAAA,OACH;AAAA,KAGJ,GACF;AAEJ;","names":["import_react","import_react","React","import_react","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","React","import_ermis_chat_sdk","import_jsx_runtime","React","import_jsx_runtime","import_react","import_react","import_react","ch","import_react","import_react","import_react","import_react","import_react","import_ermis_chat_sdk","import_jsx_runtime","React","import_react","import_react","import_ermis_chat_sdk","import_jsx_runtime","React","import_jsx_runtime","DefaultEmpty","React","import_react","import_jsx_runtime","React","import_react","import_virtua","import_react","import_ermis_chat_sdk","import_react","import_ermis_chat_sdk","import_react","client","import_react","import_react","import_react","import_jsx_runtime","React","import_react","import_react","import_react","import_react","import_jsx_runtime","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_ermis_chat_sdk","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_react","import_jsx_runtime","React","import_jsx_runtime","React","DefaultEmpty","import_react","import_react","import_react","import_ermis_chat_sdk","import_react","import_react","import_ermis_chat_sdk","import_react","import_jsx_runtime","React","import_react","import_virtua","import_jsx_runtime","React","import_react","import_ermis_chat_sdk","import_jsx_runtime","formatFileSize","React","isImage","isVideo","import_react","import_jsx_runtime","MAX_PREVIEW_LENGTH","truncateText","React","import_react","import_jsx_runtime","MAX_PREVIEW_LENGTH","truncateText","getAttachmentSummary","React","import_jsx_runtime","React","import_react","import_react","import_virtua","import_jsx_runtime","getFileIcon","import_react","import_jsx_runtime","React","isVideo","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","getFileIcon","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_react","import_virtua","import_jsx_runtime","React","import_jsx_runtime","import_react","import_jsx_runtime","React","import_react","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context/ChatProvider.tsx","../src/components/ErmisCallProvider.tsx","../src/context/ErmisCallContext.tsx","../src/components/ErmisCallUI.tsx","../src/hooks/useCallContext.ts","../src/components/Modal.tsx","../src/components/Avatar.tsx","../src/components/MediaLightbox.tsx","../src/utils.ts","../src/hooks/useChatClient.ts","../src/hooks/useChannel.ts","../src/hooks/useChannelListUpdates.ts","../src/channelTypeUtils.ts","../src/channelRoleUtils.ts","../src/hooks/useChannelRowUpdates.ts","../src/hooks/useBannedState.ts","../src/hooks/useBlockedState.ts","../src/hooks/useOnlineStatus.ts","../src/hooks/useOnlineUsers.ts","../src/hooks/usePendingState.ts","../src/components/ChannelList.tsx","../src/components/TopicModal.tsx","../src/components/ChannelActions.tsx","../src/components/Dropdown.tsx","../src/components/Channel.tsx","../src/components/ForwardMessageModal.tsx","../src/components/ChannelHeader.tsx","../src/components/VirtualMessageList.tsx","../src/hooks/useLoadMessages.ts","../src/hooks/useScrollToMessage.ts","../src/hooks/useChannelMessages.ts","../src/hooks/useChannelData.ts","../src/components/MessageItem.tsx","../src/components/QuotedMessagePreview.tsx","../src/components/MessageActionsBox.tsx","../src/hooks/useMessageActions.ts","../src/hooks/useChannelCapabilities.ts","../src/messageTypeUtils.ts","../src/components/MessageReactions.tsx","../src/components/MessageQuickReactions.tsx","../src/components/MessageRenderers.tsx","../src/components/ChannelInfo/utils.tsx","../src/components/PinnedMessages.tsx","../src/components/ReadReceipts.tsx","../src/components/TypingIndicator.tsx","../src/hooks/useTypingIndicator.ts","../src/components/PendingOverlay.tsx","../src/components/SkippedOverlay.tsx","../src/components/BannedOverlay.tsx","../src/components/ClosedTopicOverlay.tsx","../src/components/MessageInput.tsx","../src/hooks/useMentions.ts","../src/hooks/useFileUpload.ts","../src/hooks/useEmojiPicker.ts","../src/hooks/useMessageSend.ts","../src/components/MessageInputDefaults.tsx","../src/components/MentionSuggestions.tsx","../src/components/FilesPreview.tsx","../src/components/ReplyPreview.tsx","../src/components/EditPreview.tsx","../src/components/ChannelInfo/ChannelInfo.tsx","../src/components/ChannelInfo/ChannelInfoTabs.tsx","../src/components/ChannelInfo/MediaGridItem.tsx","../src/components/ChannelInfo/LinkListItem.tsx","../src/components/ChannelInfo/FileListItem.tsx","../src/components/ChannelInfo/MemberListItem.tsx","../src/components/ChannelInfo/States.tsx","../src/components/ChannelInfo/AddMemberModal.tsx","../src/components/UserPicker.tsx","../src/components/ChannelInfo/EditChannelModal.tsx","../src/components/ChannelInfo/MessageSearchPanel.tsx","../src/components/Panel.tsx","../src/components/ChannelInfo/ChannelSettingsPanel.tsx","../src/components/CreateChannelModal.tsx"],"sourcesContent":["// Styles\nimport './styles/index.css';\n\n// Context\nexport { ChatProvider } from './context/ChatProvider';\nexport type { ChatProviderProps, ChatContextValue, Theme } from './context/ChatProvider';\n\n// Hooks\nexport { useChatClient } from './hooks/useChatClient';\nexport { useChannel } from './hooks/useChannel';\nexport type { UseChannelReturn } from './hooks/useChannel';\nexport { useChannelListUpdates } from './hooks/useChannelListUpdates';\nexport { useChannelRowUpdates } from './hooks/useChannelRowUpdates';\nexport { useBannedState } from './hooks/useBannedState';\nexport { useBlockedState } from './hooks/useBlockedState';\nexport { useOnlineStatus } from './hooks/useOnlineStatus';\nexport type { OnlineStatus } from './hooks/useOnlineStatus';\nexport { useOnlineUsers } from './hooks/useOnlineUsers';\nexport { usePendingState } from './hooks/usePendingState';\n\n// Components\nexport { Avatar } from './components/Avatar';\nexport type { AvatarProps } from './components/Avatar';\n\nexport { ChannelList, ChannelItem, ChannelTopicGroup } from './components/ChannelList';\nexport type { ChannelListProps, ChannelItemProps } from './components/ChannelList';\n\nexport { DefaultChannelActions, computeDefaultActions } from './components/ChannelActions';\nexport type { ChannelAction, ChannelActionsProps } from './types';\n\nexport { Channel } from './components/Channel';\nexport type { ChannelProps } from './components/Channel';\n\nexport { ChannelHeader } from './components/ChannelHeader';\nexport type { ChannelHeaderProps } from './components/ChannelHeader';\nexport type { ChannelHeaderData } from './types';\n\nexport type {\n MessageListProps,\n MessageBubbleProps,\n MessageItemProps,\n SystemMessageItemProps,\n DateSeparatorProps,\n JumpToLatestProps,\n} from './types';\n\nexport { VirtualMessageList } from './components/VirtualMessageList';\n\nexport { PinnedMessages } from './components/PinnedMessages';\nexport type { PinnedMessagesProps, PinnedMessageItemProps } from './types';\n\nexport { MessageItem, SystemMessageItem } from './components/MessageItem';\nexport { MessageActionsBox } from './components/MessageActionsBox';\nexport type { MessageActionsBoxProps } from './types';\n\nexport { Dropdown, closeAllDropdowns } from './components/Dropdown';\nexport type { DropdownProps } from './components/Dropdown';\n\nexport { MessageReactions } from './components/MessageReactions';\nexport type { MessageReactionsProps, ReactionUser, LatestReaction } from './types';\n\nexport { MessageQuickReactions } from './components/MessageQuickReactions';\n\nexport { useMessageActions } from './hooks/useMessageActions';\n\nexport { formatTime, getDateKey, formatDateLabel, getMessageUserId, replaceMentionsForPreview } from './utils';\nexport {\n isGroupChannel,\n isDirectChannel,\n isTopicChannel,\n isPublicGroupChannel,\n isGeneralProxy,\n hasTopicsEnabled,\n supportsBlocking,\n} from './channelTypeUtils';\nexport {\n CHANNEL_ROLES,\n isPendingMember,\n isSkippedMember,\n isOwnerMember,\n isFriendChannel,\n canManageChannel,\n canRemoveTargetMember,\n canBanTargetMember,\n canPromoteTargetMember,\n canDemoteTargetMember,\n} from './channelRoleUtils';\nexport type { ChannelRole } from './channelRoleUtils';\n\nexport {\n MESSAGE_TYPES,\n ATTACHMENT_TYPES,\n isSystemMessage,\n isStickerMessage,\n isRegularMessage,\n isSignalMessage,\n isImageAttachment,\n isVideoAttachment,\n isVoiceRecordingAttachment,\n isLinkPreviewAttachment,\n isImage,\n isVideo,\n} from './messageTypeUtils';\nexport type { MessageType, AttachmentType } from './messageTypeUtils';\n\nexport {\n defaultMessageRenderers,\n RegularMessage,\n SystemMessage,\n SignalMessage,\n PollMessage,\n StickerMessage,\n ErrorMessage,\n AttachmentList,\n MessageAttachment,\n} from './components/MessageRenderers';\nexport type { MessageRendererProps, AttachmentProps } from './components/MessageRenderers';\n\nexport { MediaLightbox } from './components/MediaLightbox';\nexport type { MediaLightboxProps, MediaLightboxItem } from './types';\n\nexport { MessageInput } from './components/MessageInput';\nexport type {\n MessageInputProps,\n SendButtonProps,\n AttachButtonProps,\n EmojiPickerProps,\n EmojiButtonProps,\n} from './components/MessageInput';\n\nexport { FilesPreview } from './components/FilesPreview';\nexport type { FilePreviewItem, FilesPreviewProps } from './components/FilesPreview';\n\nexport { MentionSuggestions } from './components/MentionSuggestions';\nexport type { MentionSuggestionsProps } from './components/MentionSuggestions';\n\nexport { useMentions } from './hooks/useMentions';\nexport type { MentionMember, MentionPayload, UseMentionsOptions, UseMentionsReturn } from './hooks/useMentions';\n\nexport { useScrollToMessage } from './hooks/useScrollToMessage';\nexport type { UseScrollToMessageOptions, UseScrollToMessageReturn } from './hooks/useScrollToMessage';\n\nexport { useLoadMessages, dedupMessages } from './hooks/useLoadMessages';\nexport type { UseLoadMessagesOptions, UseLoadMessagesReturn } from './hooks/useLoadMessages';\n\nexport { useChannelMessages } from './hooks/useChannelMessages';\nexport type { UseChannelMessagesOptions } from './hooks/useChannelMessages';\n\nexport { QuotedMessagePreview } from './components/QuotedMessagePreview';\nexport type { QuotedMessagePreviewProps } from './components/QuotedMessagePreview';\nexport { ReplyPreview } from './components/ReplyPreview';\nexport type { ReplyPreviewProps } from './types';\n\nexport { ForwardMessageModal } from './components/ForwardMessageModal';\nexport type { ForwardMessageModalProps, ForwardChannelItemProps } from './components/ForwardMessageModal';\n\nexport { TopicModal } from './components/TopicModal';\n\nexport { TypingIndicator } from './components/TypingIndicator';\nexport type { TypingIndicatorProps } from './components/TypingIndicator';\nexport { useTypingIndicator } from './hooks/useTypingIndicator';\nexport type { TypingUser } from './hooks/useTypingIndicator';\n\nexport {\n ChannelInfo,\n DefaultChannelInfoHeader,\n DefaultChannelInfoCover,\n DefaultChannelInfoActions,\n DefaultChannelInfoTabs,\n} from './components/ChannelInfo';\n\nexport { Modal } from './components/Modal';\nexport { Panel } from './components/Panel';\nexport type {\n ChannelInfoProps,\n ChannelInfoHeaderProps,\n ChannelInfoCoverProps,\n ChannelInfoActionsProps,\n ChannelInfoTabsProps,\n ChannelInfoMemberItemProps,\n ChannelInfoMediaItemProps,\n ChannelInfoLinkItemProps,\n ChannelInfoFileItemProps,\n ChannelInfoEmptyStateProps,\n AttachmentItem,\n MediaTab,\n ModalProps,\n AddMemberModalProps,\n AddMemberUserItemProps,\n AddMemberButtonProps,\n} from './types';\n\nexport { UserPicker } from './components/UserPicker';\nexport type { UserPickerProps, UserPickerUser, UserPickerItemProps, UserPickerSelectedBoxProps } from './types';\n\nexport { CreateChannelModal } from './components/CreateChannelModal';\nexport type { CreateChannelModalProps } from './types';\n\n// Call Components\nexport { ErmisCallContext } from './context/ErmisCallContext';\nexport type { CallContextValue } from './context/ErmisCallContext';\nexport { useCallContext } from './hooks/useCallContext';\nexport { ErmisCallProvider } from './components/ErmisCallProvider';\nexport type { ErmisCallProviderProps } from './components/ErmisCallProvider';\nexport { ErmisCallUI } from './components/ErmisCallUI';\nexport type {\n ErmisCallUIProps,\n ErmisCallRingingProps,\n ErmisCallConnectedAudioProps,\n ErmisCallConnectedVideoProps,\n ErmisCallErrorProps,\n ErmisCallControlsBarProps,\n} from './types';\n","import React, { createContext, useState, useCallback } from 'react';\nimport type { Channel, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { Theme, ChatContextValue, ChatProviderProps, ReadStateEntry } from '../types';\nimport { ErmisCallProvider } from '../components/ErmisCallProvider';\nimport { ErmisCallUI } from '../components/ErmisCallUI';\n\nexport type { Theme, ChatContextValue, ChatProviderProps } from '../types';\n\nexport const ChatContext = createContext<ChatContextValue | null>(null);\n\nexport const ChatProvider: React.FC<ChatProviderProps> = ({\n client,\n children,\n initialTheme = 'light',\n enableCall = false,\n callSessionId,\n callWasmPath,\n callRelayUrl,\n CallUIComponent,\n incomingCallAudioPath,\n outgoingCallAudioPath,\n onCallStart,\n onCallEnd,\n onCallError,\n onIncomingCall,\n onCallAccepted,\n onCallRejected,\n}) => {\n const [activeChannelRaw, setActiveChannelRaw] = useState<Channel | null>(null);\n const [theme, setTheme] = useState<Theme>(initialTheme);\n const [messages, setMessages] = useState<FormatMessageResponse[]>([]);\n const [quotedMessage, setQuotedMessage] = useState<FormatMessageResponse | null>(null);\n const [editingMessage, setEditingMessage] = useState<FormatMessageResponse | null>(null);\n const [readState, setReadState] = useState<Record<string, ReadStateEntry>>({});\n const [forwardingMessage, setForwardingMessage] = useState<FormatMessageResponse | null>(null);\n const [jumpToMessageId, setJumpToMessageId] = useState<string | null>(null);\n\n const activeChannel = activeChannelRaw;\n\n const setActiveChannel = useCallback((channel: Channel | null) => {\n setActiveChannelRaw(channel);\n setQuotedMessage(null);\n setEditingMessage(null);\n if (channel) {\n setMessages([...channel.state.latestMessages]);\n setReadState({ ...channel.state.read });\n } else {\n setMessages([]);\n setReadState({});\n }\n }, []);\n\n /** Re-read messages from SDK state into React state */\n const syncMessages = useCallback(() => {\n if (activeChannel) {\n setMessages([...activeChannel.state.latestMessages]);\n }\n }, [activeChannel]);\n\n const value: ChatContextValue = {\n client,\n activeChannel,\n setActiveChannel,\n theme,\n setTheme,\n messages,\n setMessages,\n syncMessages,\n quotedMessage,\n setQuotedMessage,\n editingMessage,\n setEditingMessage,\n readState,\n setReadState,\n forwardingMessage,\n setForwardingMessage,\n jumpToMessageId,\n setJumpToMessageId,\n enableCall,\n };\n\n const CallUIView = CallUIComponent ? <CallUIComponent /> : (\n <ErmisCallUI\n incomingCallAudioPath={incomingCallAudioPath}\n outgoingCallAudioPath={outgoingCallAudioPath}\n />\n );\n\n const content = (\n <ChatContext.Provider value={value}>\n <div className={`ermis-chat ermis-chat--${theme}`}>\n {children}\n {enableCall && CallUIView}\n </div>\n </ChatContext.Provider>\n );\n\n if (enableCall) {\n if (!callSessionId) {\n console.warn('ErmisChat React: enableCall is true but callSessionId is missing.');\n }\n return (\n <ErmisCallProvider\n client={client}\n sessionId={callSessionId || ''}\n wasmPath={callWasmPath}\n relayUrl={callRelayUrl}\n onCallStart={onCallStart}\n onCallEnd={onCallEnd}\n onCallError={onCallError}\n onIncomingCall={onIncomingCall}\n onCallAccepted={onCallAccepted}\n onCallRejected={onCallRejected}\n >\n {content}\n </ErmisCallProvider>\n );\n }\n\n return content;\n};\n","import React, { useEffect, useState, useCallback, useRef } from 'react';\nimport { CallStatus, ErmisCallNode, type UserCallInfo, type CallEventData } from '@ermis-network/ermis-chat-sdk';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\nimport type { ErmisCallProviderProps } from '../types';\n\nexport type { ErmisCallProviderProps } from '../types';\n\nexport const ErmisCallProvider: React.FC<ErmisCallProviderProps> = ({\n children,\n client,\n sessionId,\n wasmPath = '/ermis_call_node_wasm_bg.wasm',\n relayUrl = 'https://iroh-relay.ermis.network:8443',\n onCallStart,\n onCallEnd,\n onCallError,\n onIncomingCall,\n onCallAccepted,\n onCallRejected,\n}) => {\n const [callNode, setCallNode] = useState<ErmisCallNode | null>(null);\n const [callStatus, setCallStatus] = useState<CallStatus | ''>('');\n const [localStream, setLocalStream] = useState<MediaStream | null>(null);\n const [remoteStream, setRemoteStream] = useState<MediaStream | null>(null);\n const [callType, setCallType] = useState<string>('audio');\n const [callerInfo, setCallerInfo] = useState<UserCallInfo | undefined>(undefined);\n const [receiverInfo, setReceiverInfo] = useState<UserCallInfo | undefined>(undefined);\n const [isIncoming, setIsIncoming] = useState<boolean>(false);\n const [isMicMuted, setIsMicMuted] = useState(false);\n const [isVideoMuted, setIsVideoMuted] = useState(true); // Default to true until a video track is added\n const [audioDevices, setAudioDevices] = useState<MediaDeviceInfo[]>([]);\n const [videoDevices, setVideoDevices] = useState<MediaDeviceInfo[]>([]);\n const [selectedAudioDeviceId, setSelectedAudioDeviceId] = useState<string>('');\n const [selectedVideoDeviceId, setSelectedVideoDeviceId] = useState<string>('');\n const [isScreenSharing, setIsScreenSharing] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const [isRemoteMicMuted, setIsRemoteMicMuted] = useState(false);\n const [isRemoteVideoMuted, setIsRemoteVideoMuted] = useState(false);\n\n // Call duration timer (C7 — exposed via context)\n const [callDuration, setCallDuration] = useState(0);\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const startTimer = useCallback(() => {\n setCallDuration(0);\n timerRef.current = setInterval(() => {\n setCallDuration((prev) => prev + 1);\n }, 1000);\n }, []);\n\n const stopTimer = useCallback(() => {\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n setCallDuration(0);\n }, []);\n\n useEffect(() => {\n if (callStatus === CallStatus.CONNECTED) {\n startTimer();\n } else {\n stopTimer();\n }\n return () => stopTimer();\n }, [callStatus, startTimer, stopTimer]);\n\n useEffect(() => {\n if (!client || !sessionId) return;\n\n // Create new call node instance\n const node = new ErmisCallNode(client, sessionId, wasmPath, relayUrl);\n setCallNode(node);\n\n // Register Call Events\n node.onCallEvent = (data: CallEventData) => {\n setIsIncoming(data.type === 'incoming');\n setCallType(data.callType);\n setCallerInfo(data.callerInfo);\n setReceiverInfo(data.receiverInfo);\n // C1: Lifecycle callback — incoming call\n if (data.type === 'incoming' && data.callerInfo) {\n onIncomingCall?.(data.callerInfo);\n }\n };\n\n node.onError = (error: string) => {\n setErrorMessage(error);\n // C1: Lifecycle callback — error\n onCallError?.(error);\n };\n node.onDeviceChange = (audio, video) => {\n setAudioDevices(audio);\n setVideoDevices(video);\n };\n node.onScreenShareChange = (isSharing: boolean) => setIsScreenSharing(isSharing);\n\n node.getDevices().then(({ audioDevices: a, videoDevices: v }) => {\n setAudioDevices(a);\n setVideoDevices(v);\n });\n\n node.onCallStatus = (status: string | null) => {\n const parsedStatus = status as CallStatus | '';\n setCallStatus(parsedStatus);\n if (parsedStatus === CallStatus.ENDED || !parsedStatus) {\n setLocalStream(null);\n setRemoteStream(null);\n setIsIncoming(false);\n setCallStatus('');\n }\n };\n\n node.onLocalStream = (stream: MediaStream) => {\n setLocalStream(stream);\n const audioTracks = stream.getAudioTracks();\n setIsMicMuted(audioTracks.length === 0 || !audioTracks[0].enabled);\n const videoTracks = stream.getVideoTracks();\n setIsVideoMuted(videoTracks.length === 0 || !videoTracks[0].enabled);\n };\n\n node.onRemoteStream = (stream: MediaStream) => setRemoteStream(stream);\n\n // Listen for remote peer transceiver state via data channel\n node.onDataChannelMessage = (state: { audio_enable?: boolean; video_enable?: boolean }) => {\n if (typeof state?.audio_enable === 'boolean') {\n setIsRemoteMicMuted(!state.audio_enable);\n }\n if (typeof state?.video_enable === 'boolean') {\n setIsRemoteVideoMuted(!state.video_enable);\n }\n };\n\n // Listen for remote peer requesting to upgrade call (audio → video)\n // Pattern 2: Automatically switch UI layout to video without prompting.\n node.onUpgradeCall = () => {\n setCallType('video');\n // Note: We don't turn on our own camera automatically.\n };\n\n return () => {\n const cleanup = async () => {\n try {\n await node.endCall();\n } catch (e) { } // ignore during unmount\n };\n cleanup();\n };\n }, [client, sessionId, wasmPath, relayUrl, onIncomingCall, onCallError]);\n\n const createCall = useCallback(async (type: 'audio' | 'video', cid: string) => {\n if (!callNode) return;\n setCallType(type);\n setIsIncoming(false);\n setCallStatus(CallStatus.RINGING);\n await callNode.createCall(type, cid);\n // C1: Lifecycle callback — call started\n onCallStart?.(type, cid);\n }, [callNode, onCallStart]);\n\n const acceptCall = useCallback(async () => {\n if (callNode) await callNode.acceptCall();\n // C1: Lifecycle callback — call accepted\n onCallAccepted?.();\n }, [callNode, onCallAccepted]);\n\n const rejectCall = useCallback(async () => {\n if (callNode) await callNode.rejectCall();\n setCallStatus('');\n setIsIncoming(false);\n // C1: Lifecycle callback — call rejected\n onCallRejected?.();\n }, [callNode, onCallRejected]);\n\n const endCall = useCallback(async () => {\n if (callNode) await callNode.endCall();\n // C1: Lifecycle callback — call ended (capture duration before reset)\n const duration = callDuration;\n setCallStatus('');\n setIsIncoming(false);\n setLocalStream(null);\n setRemoteStream(null);\n onCallEnd?.(duration);\n }, [callNode, callDuration, onCallEnd]);\n\n const toggleScreenShare = useCallback(async () => {\n if (!callNode) return;\n if (isScreenSharing) {\n await callNode.stopScreenShare();\n } else {\n await callNode.startScreenShare();\n }\n }, [callNode, isScreenSharing]);\n\n const switchAudioDevice = useCallback(async (deviceId: string) => {\n if (!callNode) return;\n const success = await callNode.switchAudioDevice(deviceId);\n if (success) setSelectedAudioDeviceId(deviceId);\n }, [callNode]);\n\n const switchVideoDevice = useCallback(async (deviceId: string) => {\n if (!callNode) return;\n const success = await callNode.switchVideoDevice(deviceId);\n if (success) setSelectedVideoDeviceId(deviceId);\n }, [callNode]);\n\n const clearError = useCallback(() => setErrorMessage(null), []);\n\n const upgradeCall = useCallback(async () => {\n if (!callNode) return;\n await callNode.upgradeCall();\n setCallType('video');\n }, [callNode]);\n\n const toggleMic = useCallback(async () => {\n if (!callNode || !localStream) return;\n const newMutedState = !isMicMuted;\n await callNode.toggleMic(!newMutedState);\n setIsMicMuted(newMutedState);\n }, [callNode, localStream, isMicMuted]);\n\n const toggleVideo = useCallback(async () => {\n if (!callNode) return;\n if (localStream) {\n if (localStream.getVideoTracks().length > 0) {\n const newMutedState = !isVideoMuted;\n await callNode.toggleCamera(!newMutedState);\n setIsVideoMuted(newMutedState);\n } else {\n // One-way video case: we are in a video call but our camera is off (no track).\n // Clicking toggle video should add our camera track via requestUpgradeCall.\n // This avoids sending the UPGRADE_CALL signal to the backend again.\n await callNode.requestUpgradeCall(true);\n setIsVideoMuted(false);\n }\n }\n }, [callNode, localStream, isVideoMuted]);\n\n const value = {\n callNode,\n callStatus,\n localStream,\n remoteStream,\n callType,\n callerInfo,\n receiverInfo,\n isIncoming,\n createCall,\n acceptCall,\n rejectCall,\n endCall,\n toggleMic,\n toggleVideo,\n isMicMuted,\n isVideoMuted,\n audioDevices,\n videoDevices,\n selectedAudioDeviceId,\n selectedVideoDeviceId,\n isScreenSharing,\n errorMessage,\n toggleScreenShare,\n switchAudioDevice,\n switchVideoDevice,\n clearError,\n isRemoteMicMuted,\n isRemoteVideoMuted,\n upgradeCall,\n callDuration,\n };\n\n return (\n <ErmisCallContext.Provider value={value}>\n {children}\n </ErmisCallContext.Provider>\n );\n};\n\nErmisCallProvider.displayName = 'ErmisCallProvider';\n","import React from 'react';\nimport { CallStatus, type ErmisCallNode, type UserCallInfo } from '@ermis-network/ermis-chat-sdk';\n\nexport type CallContextValue = {\n callNode: ErmisCallNode | null;\n callStatus: CallStatus | '';\n localStream: MediaStream | null;\n remoteStream: MediaStream | null;\n callType: string;\n callerInfo?: UserCallInfo | undefined;\n receiverInfo?: UserCallInfo | undefined;\n isIncoming: boolean;\n createCall: (type: 'audio' | 'video', cid: string) => Promise<void>;\n acceptCall: () => Promise<void>;\n rejectCall: () => Promise<void>;\n endCall: () => Promise<void>;\n toggleMic: () => void;\n toggleVideo: () => void;\n isMicMuted: boolean;\n isVideoMuted: boolean;\n audioDevices: MediaDeviceInfo[];\n videoDevices: MediaDeviceInfo[];\n selectedAudioDeviceId: string;\n selectedVideoDeviceId: string;\n isScreenSharing: boolean;\n errorMessage: string | null;\n toggleScreenShare: () => Promise<void>;\n switchAudioDevice: (id: string) => Promise<void>;\n switchVideoDevice: (id: string) => Promise<void>;\n clearError: () => void;\n isRemoteMicMuted: boolean;\n isRemoteVideoMuted: boolean;\n upgradeCall: () => Promise<void>;\n callDuration: number;\n};\n\nexport const ErmisCallContext = React.createContext<CallContextValue | undefined>(undefined);\n","import React, { useEffect, useRef, useState, useCallback } from 'react';\nimport { useCallContext } from '../hooks/useCallContext';\nimport { Modal } from './Modal';\nimport { Avatar } from './Avatar';\nimport { CallStatus } from '@ermis-network/ermis-chat-sdk';\nimport type { ErmisCallUIProps } from '../types';\n\n/** Format seconds into MM:SS */\nconst formatDuration = (totalSeconds: number): string => {\n const m = Math.floor(totalSeconds / 60).toString().padStart(2, '0');\n const s = (totalSeconds % 60).toString().padStart(2, '0');\n return `${m}:${s}`;\n};\n\nexport const ErmisCallUI: React.FC<ErmisCallUIProps> = React.memo(({\n className,\n incomingCallTitle = (type: string) => `Incoming ${type} call`,\n outgoingCallTitle = (type: string) => `Outgoing ${type} call`,\n ongoingCallTitle = (type: string) => `Ongoing ${type} Call`,\n isCallingYouLabel = 'is calling you...',\n ringingLabel = 'Ringing...',\n rejectCallLabel = 'Reject',\n acceptCallLabel = 'Accept',\n endCallLabel = 'End Call',\n cancelLabel = 'Cancel',\n toggleMicTitle = 'Toggle Mic',\n toggleVideoTitle = 'Toggle Video',\n shareScreenTitle = 'Share Screen',\n stopScreenShareTitle = 'Stop Sharing',\n connectedLabel = 'Connected',\n audioCallBadgeLabel = 'Audio Call',\n videoCallBadgeLabel = 'Video Call',\n fullscreenTitle = 'Fullscreen',\n exitFullscreenTitle = 'Exit Fullscreen',\n upgradeCallTitle = 'Request Video Upgrade',\n suppressIncomingCalls = false,\n onCallDurationChange,\n AvatarComponent = Avatar,\n MicIcon: PropMicIcon,\n MicOffIcon: PropMicOffIcon,\n VideoIcon: PropVideoIcon,\n VideoOffIcon: PropVideoOffIcon,\n PhoneIcon: PropPhoneIcon,\n ScreenShareIcon: PropScreenShareIcon,\n ScreenShareOffIcon: PropScreenShareOffIcon,\n FullscreenIcon: PropFullscreenIcon,\n ExitFullscreenIcon: PropExitFullscreenIcon,\n UpgradeCallIcon: PropUpgradeCallIcon,\n incomingCallAudioPath = '/call_incoming.mp3',\n outgoingCallAudioPath = '/call_outgoing.mp3',\n RingingComponent: CustomRingingComponent,\n ConnectedAudioComponent: CustomConnectedAudioComponent,\n ConnectedVideoComponent: CustomConnectedVideoComponent,\n ErrorComponent: CustomErrorComponent,\n ControlsBarComponent: CustomControlsBarComponent,\n}) => {\n const {\n callStatus,\n callType,\n callerInfo,\n receiverInfo,\n isIncoming,\n localStream,\n remoteStream,\n acceptCall,\n rejectCall,\n endCall,\n toggleMic,\n toggleVideo,\n isMicMuted,\n isVideoMuted,\n audioDevices,\n videoDevices,\n selectedAudioDeviceId,\n selectedVideoDeviceId,\n isScreenSharing,\n errorMessage,\n toggleScreenShare,\n switchAudioDevice,\n switchVideoDevice,\n clearError,\n isRemoteMicMuted,\n upgradeCall,\n callDuration,\n } = useCallContext();\n\n const localVideoRef = useRef<HTMLVideoElement>(null);\n const remoteVideoRef = useRef<HTMLVideoElement>(null);\n const remoteAudioRef = useRef<HTMLAudioElement>(null);\n const ringingAudioRef = useRef<HTMLAudioElement>(null);\n const callContainerRef = useRef<HTMLDivElement>(null);\n\n // Fullscreen state\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n const toggleFullscreen = useCallback(() => {\n if (!callContainerRef.current) return;\n if (!document.fullscreenElement) {\n callContainerRef.current.requestFullscreen?.().catch(() => {});\n } else {\n document.exitFullscreen?.().catch(() => {});\n }\n }, []);\n\n useEffect(() => {\n const handleChange = () => setIsFullscreen(!!document.fullscreenElement);\n document.addEventListener('fullscreenchange', handleChange);\n return () => document.removeEventListener('fullscreenchange', handleChange);\n }, []);\n\n // C5: Notify consumer of duration changes\n useEffect(() => {\n if (callDuration > 0) {\n onCallDurationChange?.(callDuration);\n }\n }, [callDuration, onCallDurationChange]);\n\n useEffect(() => {\n if (localVideoRef.current && localStream) {\n localVideoRef.current.srcObject = localStream;\n }\n }, [localStream, callType, callStatus]);\n\n useEffect(() => {\n if (remoteStream) {\n if (callType === 'video' && remoteVideoRef.current) {\n remoteVideoRef.current.srcObject = remoteStream;\n }\n if (remoteAudioRef.current) {\n remoteAudioRef.current.srcObject = remoteStream;\n }\n }\n }, [remoteStream, callType, callStatus]);\n\n useEffect(() => {\n if (callStatus === CallStatus.RINGING && ringingAudioRef.current) {\n const playPromise = ringingAudioRef.current.play();\n if (playPromise !== undefined) {\n playPromise.catch((e) => console.log('ErmisChat: Audio play blocked by browser:', e));\n }\n } else if (ringingAudioRef.current) {\n ringingAudioRef.current.pause();\n ringingAudioRef.current.currentTime = 0;\n }\n }, [callStatus]);\n\n if (!callStatus && !errorMessage) return null;\n\n // C3: Suppress incoming call UI (DND mode)\n if (suppressIncomingCalls && isIncoming && callStatus === CallStatus.RINGING) return null;\n\n const isOpen = callStatus === CallStatus.RINGING || callStatus === CallStatus.CONNECTED || !!errorMessage;\n if (!isOpen) return null;\n\n const title = errorMessage ? 'Call Error' : (\n callStatus === CallStatus.RINGING\n ? (isIncoming ? incomingCallTitle(callType) : outgoingCallTitle(callType))\n : ongoingCallTitle(callType)\n );\n\n const peerInfo = isIncoming ? callerInfo : receiverInfo;\n const modalMaxWidth = callType === 'video' && callStatus === CallStatus.CONNECTED ? '720px' : '480px';\n\n // Default icons\n const FinalPhoneIcon = PropPhoneIcon || (() => (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"></path>\n </svg>\n ));\n\n const FinalVideoIcon = PropVideoIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\"></polygon>\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n </svg>\n ));\n\n const FinalVideoOffIcon = PropVideoOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M16 16v1a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2m5.66 0H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10M1 1l22 22\"></path>\n </svg>\n ));\n\n const FinalMicIcon = PropMicIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"></path>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"></path>\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"></line>\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"></line>\n </svg>\n ));\n\n const FinalMicOffIcon = PropMicOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6\"></path>\n <path d=\"M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23\"></path>\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"></line>\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"></line>\n </svg>\n ));\n\n const FinalScreenShareIcon = PropScreenShareIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"></line>\n <path d=\"M16 11l-4 4-4-4\"></path>\n <path d=\"M12 15V7\"></path>\n </svg>\n ));\n\n const FinalScreenShareOffIcon = PropScreenShareOffIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"></line>\n <line x1=\"12\" y1=\"10\" x2=\"12\" y2=\"10\"></line>\n </svg>\n ));\n\n const FinalFullscreenIcon = PropFullscreenIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M8 3H5a2 2 0 0 0-2 2v3\"></path>\n <path d=\"M21 8V5a2 2 0 0 0-2-2h-3\"></path>\n <path d=\"M3 16v3a2 2 0 0 0 2 2h3\"></path>\n <path d=\"M16 21h3a2 2 0 0 0 2-2v-3\"></path>\n </svg>\n ));\n\n const FinalExitFullscreenIcon = PropExitFullscreenIcon || (() => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M4 14h6v6\"></path>\n <path d=\"M20 10h-6V4\"></path>\n <path d=\"M14 10l7-7\"></path>\n <path d=\"M3 21l7-7\"></path>\n </svg>\n ));\n\n // C4: Upgrade call icon (defaults to FinalVideoIcon)\n const FinalUpgradeCallIcon = PropUpgradeCallIcon || FinalVideoIcon;\n\n /* ================================================================\n Shared Controls Bar — used by both audio and video active states\n ================================================================ */\n const renderControls = () => {\n // C6: Allow consumer to replace controls bar entirely\n if (CustomControlsBarComponent) {\n return (\n <CustomControlsBarComponent\n callType={callType}\n toggleMic={toggleMic}\n toggleVideo={toggleVideo}\n toggleScreenShare={toggleScreenShare}\n toggleFullscreen={toggleFullscreen}\n upgradeCall={upgradeCall}\n endCall={endCall}\n isMicMuted={isMicMuted}\n isVideoMuted={isVideoMuted}\n isScreenSharing={isScreenSharing}\n isFullscreen={isFullscreen}\n audioDevices={audioDevices}\n videoDevices={videoDevices}\n selectedAudioDeviceId={selectedAudioDeviceId}\n selectedVideoDeviceId={selectedVideoDeviceId}\n switchAudioDevice={switchAudioDevice}\n switchVideoDevice={switchVideoDevice}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__controls\">\n {/* Mic */}\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleMic}\n className={`ermis-call-ui__control-btn ${isMicMuted ? 'ermis-call-ui__control-btn--muted' : ''}`}\n data-tooltip={toggleMicTitle}\n >\n {isMicMuted ? <FinalMicOffIcon /> : <FinalMicIcon />}\n </button>\n {audioDevices.length > 0 && (\n <select\n className=\"ermis-call-ui__device-select\"\n value={selectedAudioDeviceId}\n onChange={(e) => switchAudioDevice(e.target.value)}\n >\n {audioDevices.map(d => (\n <option key={d.deviceId} value={d.deviceId}>{d.label || 'Microphone'}</option>\n ))}\n </select>\n )}\n </div>\n\n {/* Video controls */}\n {callType === 'video' ? (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleVideo}\n className={`ermis-call-ui__control-btn ${isVideoMuted ? 'ermis-call-ui__control-btn--muted' : ''}`}\n data-tooltip={toggleVideoTitle}\n >\n {isVideoMuted ? <FinalVideoOffIcon /> : <FinalVideoIcon />}\n </button>\n {videoDevices.length > 0 && (\n <select\n className=\"ermis-call-ui__device-select\"\n value={selectedVideoDeviceId}\n onChange={(e) => switchVideoDevice(e.target.value)}\n >\n {videoDevices.map(d => (\n <option key={d.deviceId} value={d.deviceId}>{d.label || 'Camera'}</option>\n ))}\n </select>\n )}\n </div>\n ) : (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={upgradeCall}\n className=\"ermis-call-ui__control-btn\"\n data-tooltip={upgradeCallTitle}\n >\n <FinalUpgradeCallIcon />\n </button>\n </div>\n )}\n\n {/* Screen Share */}\n {callType === 'video' && typeof navigator.mediaDevices?.getDisplayMedia === 'function' && (\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleScreenShare}\n className={`ermis-call-ui__control-btn ${isScreenSharing ? 'ermis-call-ui__control-btn--active' : ''}`}\n data-tooltip={isScreenSharing ? stopScreenShareTitle : shareScreenTitle}\n >\n {isScreenSharing ? <FinalScreenShareIcon /> : <FinalScreenShareOffIcon />}\n </button>\n </div>\n )}\n\n {/* Fullscreen */}\n <div className=\"ermis-call-ui__action-group\">\n <button\n onClick={toggleFullscreen}\n className=\"ermis-call-ui__control-btn\"\n data-tooltip={isFullscreen ? exitFullscreenTitle : fullscreenTitle}\n >\n {isFullscreen ? <FinalExitFullscreenIcon /> : <FinalFullscreenIcon />}\n </button>\n </div>\n\n {/* Separator before end call */}\n <div className=\"ermis-call-ui__controls-separator\" />\n\n {/* End Call */}\n <button\n onClick={endCall}\n className=\"ermis-call-ui__control-btn ermis-call-ui__control-btn--danger\"\n data-tooltip={endCallLabel}\n >\n <FinalPhoneIcon />\n </button>\n </div>\n );\n };\n\n /* ================================================================\n Render ringing state\n ================================================================ */\n const renderRinging = () => {\n // C6: Allow consumer to replace ringing view entirely\n if (CustomRingingComponent) {\n return (\n <CustomRingingComponent\n peerInfo={peerInfo}\n callType={callType}\n isIncoming={isIncoming}\n acceptCall={acceptCall}\n rejectCall={rejectCall}\n endCall={endCall}\n AvatarComponent={AvatarComponent}\n isCallingYouLabel={isCallingYouLabel}\n ringingLabel={ringingLabel}\n rejectCallLabel={rejectCallLabel}\n acceptCallLabel={acceptCallLabel}\n endCallLabel={endCallLabel}\n audioCallBadgeLabel={audioCallBadgeLabel}\n videoCallBadgeLabel={videoCallBadgeLabel}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__ringing\">\n {/* Avatar with pulse rings */}\n <div className=\"ermis-call-ui__ringing-avatar\">\n <div className=\"ermis-call-ui__ringing-avatar-inner\">\n <AvatarComponent\n image={peerInfo?.avatar}\n name={peerInfo?.name}\n size={88}\n />\n </div>\n </div>\n\n <h3 className=\"ermis-call-ui__ringing-name\">\n {peerInfo?.name}\n </h3>\n <p className=\"ermis-call-ui__ringing-status\">\n {isIncoming ? isCallingYouLabel : ringingLabel}\n </p>\n\n {/* Call type badge */}\n <div className=\"ermis-call-ui__type-badge\">\n {callType === 'video' ? <FinalVideoIcon /> : <FinalPhoneIcon />}\n {callType === 'video' ? videoCallBadgeLabel : audioCallBadgeLabel}\n </div>\n\n {/* Action buttons */}\n <div className=\"ermis-call-ui__ringing-actions\">\n {isIncoming ? (\n <>\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={rejectCall}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--reject\"\n >\n <FinalPhoneIcon />\n </button>\n <span className=\"ermis-call-ui__action-label\">{rejectCallLabel}</span>\n </div>\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={acceptCall}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--accept\"\n >\n {callType === 'video' ? <FinalVideoIcon /> : <FinalPhoneIcon />}\n </button>\n <span className=\"ermis-call-ui__action-label\">{acceptCallLabel}</span>\n </div>\n </>\n ) : (\n <div className=\"ermis-call-ui__ringing-action\">\n <button\n onClick={endCall}\n className=\"ermis-call-ui__action-circle ermis-call-ui__action-circle--reject\"\n >\n <FinalPhoneIcon />\n </button>\n <span className=\"ermis-call-ui__action-label\">{endCallLabel}</span>\n </div>\n )}\n </div>\n </div>\n );\n };\n\n /* ================================================================\n Render connected state\n ================================================================ */\n const renderConnected = () => {\n if (callType === 'video') {\n // C6: Allow consumer to replace connected video view\n if (CustomConnectedVideoComponent) {\n return (\n <CustomConnectedVideoComponent\n localVideoRef={localVideoRef}\n remoteVideoRef={remoteVideoRef}\n isRemoteMicMuted={isRemoteMicMuted}\n renderControls={renderControls}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__active\">\n <div className=\"ermis-call-ui__video-container\">\n <video\n ref={remoteVideoRef}\n autoPlay\n playsInline\n className=\"ermis-call-ui__video-remote\"\n />\n <div className=\"ermis-call-ui__video-local\">\n <video\n ref={localVideoRef}\n autoPlay\n playsInline\n muted\n className=\"ermis-call-ui__video-local-stream\"\n />\n </div>\n {/* Remote mic muted indicator */}\n {isRemoteMicMuted && (\n <div className=\"ermis-call-ui__remote-muted-badge\">\n <FinalMicOffIcon />\n </div>\n )}\n {/* Glassmorphism controls overlay */}\n <div className=\"ermis-call-ui__video-controls-overlay\">\n {renderControls()}\n </div>\n </div>\n </div>\n );\n }\n\n // Audio call\n // C6: Allow consumer to replace connected audio view\n if (CustomConnectedAudioComponent) {\n return (\n <CustomConnectedAudioComponent\n peerInfo={peerInfo}\n callDuration={callDuration}\n isRemoteMicMuted={isRemoteMicMuted}\n AvatarComponent={AvatarComponent}\n connectedLabel={connectedLabel}\n renderControls={renderControls}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__active\">\n <div className=\"ermis-call-ui__audio-container\">\n <div className=\"ermis-call-ui__audio-avatar-wrapper\">\n <AvatarComponent\n image={peerInfo?.avatar}\n name={peerInfo?.name}\n size={100}\n />\n {/* Remote mic muted indicator */}\n {isRemoteMicMuted && (\n <div className=\"ermis-call-ui__remote-muted-badge ermis-call-ui__remote-muted-badge--audio\">\n <FinalMicOffIcon />\n </div>\n )}\n </div>\n <h3 className=\"ermis-call-ui__active-name\">\n {peerInfo?.name}\n </h3>\n\n {/* Status + Timer */}\n <div className=\"ermis-call-ui__active-status\">\n <span className=\"ermis-call-ui__active-status-dot\" />\n <span>{connectedLabel}</span>\n <span className=\"ermis-call-ui__timer\">\n {formatDuration(callDuration)}\n </span>\n </div>\n\n {/* Audio wave visualizer */}\n <div className=\"ermis-call-ui__audio-waves\">\n {Array.from({ length: 9 }).map((_, i) => (\n <span key={i} className=\"ermis-call-ui__audio-wave-bar\" />\n ))}\n </div>\n\n <audio ref={remoteAudioRef} autoPlay className=\"ermis-call-ui__audio--hidden\" />\n\n {/* Controls bar */}\n {renderControls()}\n </div>\n </div>\n );\n };\n\n /* ================================================================\n Render error state\n ================================================================ */\n const renderError = () => {\n if (!errorMessage) return null;\n\n // C6: Allow consumer to replace error view\n if (CustomErrorComponent) {\n return (\n <CustomErrorComponent\n errorMessage={errorMessage}\n clearError={clearError}\n cancelLabel={cancelLabel}\n PhoneIcon={FinalPhoneIcon}\n />\n );\n }\n\n return (\n <div className=\"ermis-call-ui__error\">\n <div className=\"ermis-call-ui__error-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"var(--ermis-color-danger)\" strokeWidth=\"2\" width=\"56\" height=\"56\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n </div>\n <p className=\"ermis-call-ui__error-text\">{errorMessage}</p>\n <button\n className=\"ermis-call-ui__error-dismiss\"\n onClick={clearError}\n >\n <FinalPhoneIcon /> {cancelLabel}\n </button>\n </div>\n );\n };\n\n return (\n <Modal isOpen={isOpen} onClose={endCall} title={title} hideCloseButton closeOnOutsideClick={false} maxWidth={modalMaxWidth}>\n <div className={`ermis-call-ui ${isFullscreen ? 'ermis-call-ui--fullscreen' : ''}${className ? ` ${className}` : ''}`} ref={callContainerRef}>\n {/* Ringing audio */}\n {(incomingCallAudioPath || outgoingCallAudioPath) && (\n <audio\n ref={ringingAudioRef}\n src={isIncoming ? incomingCallAudioPath : outgoingCallAudioPath}\n loop\n className=\"ermis-call-ui__audio--hidden\"\n />\n )}\n\n {/* ============ ERROR STATE ============ */}\n {errorMessage && renderError()}\n\n {/* ============ RINGING STATE ============ */}\n {!errorMessage && callStatus === CallStatus.RINGING && renderRinging()}\n\n {/* ============ CONNECTED STATE ============ */}\n {!errorMessage && callStatus === CallStatus.CONNECTED && renderConnected()}\n </div>\n </Modal>\n );\n});\n\nErmisCallUI.displayName = 'ErmisCallUI';\n","import { useContext } from 'react';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\n\nexport const useCallContext = () => {\n const context = useContext(ErmisCallContext);\n if (context === undefined) {\n throw new Error('useCallContext must be used within an ErmisCallProvider');\n }\n return context;\n};\n","import React, { useEffect } from 'react';\nimport type { ModalProps } from '../types';\n\nexport const Modal: React.FC<ModalProps> = ({\n isOpen,\n onClose,\n title,\n children,\n footer,\n maxWidth = '480px',\n hideCloseButton = false,\n closeOnOutsideClick = true,\n}) => {\n useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && isOpen) onClose();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [isOpen, onClose]);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"ermis-modal-overlay\" onClick={closeOnOutsideClick ? onClose : undefined}>\n <div \n className=\"ermis-modal-content\" \n style={{ maxWidth }} \n onClick={e => e.stopPropagation()}\n >\n {(title || !hideCloseButton) && (\n <div className=\"ermis-modal-header\">\n {title ? (\n typeof title === 'string' ? <h3>{title}</h3> : title\n ) : <div />}\n {!hideCloseButton && (\n <button className=\"ermis-modal-close\" onClick={onClose} aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n )}\n </div>\n )}\n\n <div className=\"ermis-modal-body\">\n {children}\n </div>\n\n {footer && (\n <div className=\"ermis-modal-footer\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n};\n","import React, { useMemo, useState } from 'react';\nimport { MediaLightbox } from './MediaLightbox';\nimport type { AvatarProps } from '../types';\n\nexport type { AvatarProps } from '../types';\n\n/**\n * Extracts 1–2 initials from a name.\n */\nfunction getInitials(name?: string): string {\n if (!name) return '?';\n if (name.startsWith('0x')) return '0x';\n const parts = name.trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n }\n return parts[0][0].toUpperCase();\n}\n\n/**\n * Avatar component with image or initial fallback.\n */\nexport const Avatar: React.FC<AvatarProps> = React.memo(({\n image,\n name,\n size = 36,\n className,\n disableLightbox,\n}) => {\n const [isLoaded, setIsLoaded] = useState(false);\n const [hasError, setHasError] = useState(false);\n const [isLightboxOpen, setIsLightboxOpen] = useState(false);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Reset state if image URL changes\n React.useEffect(() => {\n if (image) {\n setHasError(false);\n if (imgRef.current?.complete) {\n setIsLoaded(true);\n } else {\n setIsLoaded(false);\n }\n }\n }, [image]);\n\n const initials = useMemo(() => getInitials(name), [name]);\n\n const wrapperStyle = useMemo<React.CSSProperties>(() => ({\n width: size,\n height: size,\n minWidth: size,\n position: 'relative',\n borderRadius: '100%', /* Or var(--ermis-radius-full) */\n overflow: 'hidden',\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n cursor: image && !hasError && !disableLightbox ? 'pointer' : undefined,\n }), [size, image, hasError, disableLightbox]);\n\n const contentStyle = useMemo<React.CSSProperties>(() => ({\n width: '100%',\n height: '100%',\n fontSize: size * 0.4,\n lineHeight: 1,\n }), [size]);\n\n const handleAvatarClick = React.useCallback((e: React.MouseEvent) => {\n if (image && !hasError && !disableLightbox) {\n e.stopPropagation();\n e.preventDefault();\n setIsLightboxOpen(true);\n }\n }, [image, hasError, disableLightbox]);\n\n return (\n <>\n <div \n className={`ermis-avatar-wrapper${className ? ` ${className}` : ''}`} \n style={wrapperStyle}\n onClick={handleAvatarClick}\n >\n {/* 1. Underlying Fallback (Placeholder) */}\n <div\n className=\"ermis-avatar ermis-avatar--fallback\"\n style={contentStyle}\n title={name}\n >\n {initials}\n </div>\n\n {/* 2. Actual Image (Lazy, Fades in natively using CSS opacity) */}\n {image && !hasError && (\n <img\n ref={imgRef}\n className=\"ermis-avatar__img\"\n src={image}\n alt={name || 'Avatar'}\n loading=\"lazy\"\n onLoad={() => setIsLoaded(true)}\n onError={() => setHasError(true)}\n style={{\n ...contentStyle,\n position: 'absolute',\n top: 0,\n left: 0,\n opacity: isLoaded ? 1 : 0,\n transition: 'opacity 0.3s ease-in-out',\n objectFit: 'cover',\n }}\n />\n )}\n </div>\n\n {isLightboxOpen && image && !hasError && (\n <MediaLightbox\n items={[{ type: 'image', src: image, alt: name || 'Avatar' }]}\n isOpen={isLightboxOpen}\n onClose={() => setIsLightboxOpen(false)}\n />\n )}\n </>\n );\n});\n\nAvatar.displayName = 'Avatar';\n","import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';\nimport ReactDOM from 'react-dom';\nimport { preloadImage } from '../utils';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { MediaLightboxProps } from '../types';\n\n/** Extract a reasonable filename from a URL or alt text */\nconst getFilename = (src: string, alt?: string): string => {\n if (alt) return alt;\n try {\n const pathname = new URL(src).pathname;\n const segments = pathname.split('/');\n return segments[segments.length - 1] || 'download';\n } catch {\n return 'download';\n }\n};\n\n/**\n * MediaLightbox – full-screen overlay for viewing images & videos.\n * Supports prev/next navigation, keyboard controls, and image zoom.\n * Renders via React portal into document.body.\n */\nexport const MediaLightbox: React.FC<MediaLightboxProps> = React.memo(({\n items,\n initialIndex = 0,\n isOpen,\n onClose,\n}) => {\n const [currentIndex, setCurrentIndex] = useState(initialIndex);\n const [zoom, setZoom] = useState(1);\n const [pan, setPan] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const dragStart = useRef({ x: 0, y: 0 });\n const panStart = useRef({ x: 0, y: 0 });\n const videoRef = useRef<HTMLVideoElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Reset state when opening or when items change\n useEffect(() => {\n if (isOpen) {\n setCurrentIndex(initialIndex);\n setZoom(1);\n setPan({ x: 0, y: 0 });\n }\n }, [isOpen, initialIndex]);\n\n // Preload adjacent images\n useEffect(() => {\n if (!isOpen) return;\n const preloadIdx = [currentIndex - 1, currentIndex + 1];\n preloadIdx.forEach(idx => {\n if (idx >= 0 && idx < items.length && items[idx].type === 'image') {\n preloadImage(items[idx].src);\n }\n });\n }, [isOpen, currentIndex, items]);\n\n // Pause video when navigating away or closing\n useEffect(() => {\n return () => {\n if (videoRef.current) {\n videoRef.current.pause();\n }\n };\n }, [currentIndex]);\n\n // Lock body scroll when open\n useEffect(() => {\n if (isOpen) {\n const prev = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => { document.body.style.overflow = prev; };\n }\n }, [isOpen]);\n\n const goTo = useCallback((idx: number) => {\n if (videoRef.current) videoRef.current.pause();\n setCurrentIndex(idx);\n setZoom(1);\n setPan({ x: 0, y: 0 });\n }, []);\n\n const goPrev = useCallback(() => {\n if (currentIndex > 0) goTo(currentIndex - 1);\n }, [currentIndex, goTo]);\n\n const goNext = useCallback(() => {\n if (currentIndex < items.length - 1) goTo(currentIndex + 1);\n }, [currentIndex, items.length, goTo]);\n\n // Keyboard navigation\n useEffect(() => {\n if (!isOpen) return;\n const handleKey = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'Escape':\n onClose();\n break;\n case 'ArrowLeft':\n goPrev();\n break;\n case 'ArrowRight':\n goNext();\n break;\n }\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [isOpen, onClose, goPrev, goNext]);\n\n // Double-click zoom toggle (image only)\n const handleDoubleClick = useCallback(() => {\n const current = items[currentIndex];\n if (current?.type !== 'image') return;\n\n if (zoom === 1) {\n setZoom(2);\n } else {\n setZoom(1);\n setPan({ x: 0, y: 0 });\n }\n }, [currentIndex, items, zoom]);\n\n // Wheel zoom (image only)\n const handleWheel = useCallback((e: React.WheelEvent) => {\n const current = items[currentIndex];\n if (current?.type !== 'image') return;\n e.preventDefault();\n\n setZoom(prev => {\n const next = prev - e.deltaY * 0.002;\n const clamped = Math.max(1, Math.min(3, next));\n if (clamped === 1) setPan({ x: 0, y: 0 });\n return clamped;\n });\n }, [currentIndex, items]);\n\n // Mouse drag for panning (image zoomed)\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (zoom <= 1) return;\n e.preventDefault();\n setIsDragging(true);\n dragStart.current = { x: e.clientX, y: e.clientY };\n panStart.current = { ...pan };\n }, [zoom, pan]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!isDragging) return;\n const dx = e.clientX - dragStart.current.x;\n const dy = e.clientY - dragStart.current.y;\n setPan({ x: panStart.current.x + dx, y: panStart.current.y + dy });\n }, [isDragging]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n // Click on backdrop closes\n const handleBackdropClick = useCallback((e: React.MouseEvent) => {\n if (e.target === containerRef.current) {\n onClose();\n }\n }, [onClose]);\n\n const { client } = useChatClient();\n\n const currentItem = items[currentIndex];\n const hasMultiple = items.length > 1;\n\n const handleDownload = useCallback(async () => {\n if (!currentItem) return;\n const filename = getFilename(currentItem.src, currentItem.alt);\n\n try {\n const blob = await client.downloadMedia(currentItem.src);\n const urlBlob = window.URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = urlBlob;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n a.remove();\n window.URL.revokeObjectURL(urlBlob);\n } catch {\n window.open(currentItem.src, '_blank', 'noopener,noreferrer');\n }\n }, [client, currentItem]);\n\n const content = useMemo(() => {\n if (!currentItem) return null;\n\n if (currentItem.type === 'video') {\n return (\n <video\n ref={videoRef}\n className=\"ermis-lightbox__video\"\n src={currentItem.src}\n poster={currentItem.posterSrc}\n controls\n autoPlay\n preload=\"metadata\"\n onClick={(e) => e.stopPropagation()}\n />\n );\n }\n\n const imgStyle: React.CSSProperties = {\n transform: `scale(${zoom}) translate(${pan.x / zoom}px, ${pan.y / zoom}px)`,\n cursor: zoom > 1 ? (isDragging ? 'grabbing' : 'grab') : 'default',\n };\n\n return (\n <img\n className={`ermis-lightbox__image${zoom > 1 ? ' ermis-lightbox__image--zoomed' : ''}`}\n src={currentItem.src}\n alt={currentItem.alt || ''}\n style={imgStyle}\n draggable={false}\n onDoubleClick={handleDoubleClick}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n onClick={(e) => e.stopPropagation()}\n />\n );\n }, [currentItem, zoom, pan, isDragging, handleDoubleClick, handleMouseDown, handleMouseMove, handleMouseUp]);\n\n if (!isOpen || !currentItem) return null;\n\n return ReactDOM.createPortal(\n <div className=\"ermis-lightbox\" onWheel={handleWheel}>\n <div className=\"ermis-lightbox__backdrop\" />\n\n {/* Header: counter + actions */}\n <div className=\"ermis-lightbox__header\">\n {hasMultiple && (\n <span className=\"ermis-lightbox__counter\">\n {currentIndex + 1} / {items.length}\n </span>\n )}\n <div className=\"ermis-lightbox__actions\">\n <button\n className=\"ermis-lightbox__action-btn\"\n onClick={handleDownload}\n aria-label=\"Download\"\n title=\"Download\"\n >\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n <button\n className=\"ermis-lightbox__action-btn\"\n onClick={onClose}\n aria-label=\"Close\"\n title=\"Close\"\n >\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Main content area */}\n <div\n ref={containerRef}\n className=\"ermis-lightbox__content\"\n onClick={handleBackdropClick}\n >\n {/* Prev button */}\n {hasMultiple && currentIndex > 0 && (\n <button\n className=\"ermis-lightbox__nav ermis-lightbox__nav--prev\"\n onClick={(e) => { e.stopPropagation(); goPrev(); }}\n aria-label=\"Previous\"\n >\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n )}\n\n {/* Media */}\n {content}\n\n {/* Next button */}\n {hasMultiple && currentIndex < items.length - 1 && (\n <button\n className=\"ermis-lightbox__nav ermis-lightbox__nav--next\"\n onClick={(e) => { e.stopPropagation(); goNext(); }}\n aria-label=\"Next\"\n >\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n </button>\n )}\n </div>\n\n {/* Filename */}\n {currentItem.alt && (\n <div className=\"ermis-lightbox__filename\">{currentItem.alt}</div>\n )}\n </div>,\n document.body\n );\n});\nMediaLightbox.displayName = 'MediaLightbox';\n","import type { MentionMember } from './types';\nimport type { Attachment, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Format a Date or date-string to a short time string (HH:MM).\n */\nexport function formatTime(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n}\n\n/**\n * Format a date as \"HH:MM, Today\", \"HH:MM, Yesterday\", or \"HH:MM, MM/DD/YYYY\".\n */\nexport function formatReadTimestamp(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const msgDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());\n const diffMs = today.getTime() - msgDay.getTime();\n const diffDays = Math.round(diffMs / 86400000);\n const time = d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n\n if (diffDays === 0) return `${time}, Today`;\n if (diffDays === 1) return `${time}, Yesterday`;\n const mm = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n const yyyy = d.getFullYear();\n return `${time}, ${mm}/${dd}/${yyyy}`;\n}\n\n/**\n * Return a YYYY-M-D key for date comparison (used by date separators).\n */\nexport function getDateKey(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;\n}\n\n/**\n * Format a date into a human-friendly label (Today / Yesterday / full date).\n */\nexport function formatDateLabel(date: Date | string | undefined): string {\n if (!date) return '';\n const d = date instanceof Date ? date : new Date(date);\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const msgDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());\n const diffMs = today.getTime() - msgDay.getTime();\n const diffDays = Math.round(diffMs / 86400000);\n\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n return d.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n}\n\n/**\n * Get the user id from a message, checking multiple possible sources.\n */\nexport function getMessageUserId(message: FormatMessageResponse): string {\n return message.user?.id || message.user_id || '';\n}\n\n/**\n * Replace @user_id with @UserName for plain text previews.\n * Returns the formatted string.\n */\nexport function replaceMentionsForPreview(\n text: string,\n message: FormatMessageResponse | { mentioned_users?: string[]; mentioned_all?: boolean },\n userMap: Record<string, string>,\n renderWrapper?: (userId: string, name: string) => string\n): string {\n const mentionedUsers: string[] = (message as any).mentioned_users ?? [];\n const mentionedAll: boolean = (message as any).mentioned_all ?? false;\n\n // If no mentions, nothing to replace\n if (mentionedUsers.length === 0 && !mentionedAll) {\n return text;\n }\n\n const replacements: { pattern: string; label: string }[] = [];\n\n for (const userId of mentionedUsers) {\n if (!userId) continue;\n const name = userMap[userId] ?? userId;\n replacements.push({\n pattern: `@${userId}`,\n label: renderWrapper ? renderWrapper(userId, name) : `@${name}`,\n });\n }\n\n if (mentionedAll) {\n replacements.push({\n pattern: '@all',\n label: renderWrapper ? renderWrapper('__all__', 'all') : '@all'\n });\n }\n\n if (replacements.length === 0) return text;\n\n // Escape special regex characters in the patterns\n const escaped = replacements.map((r) => r.pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n const regex = new RegExp(`(${escaped.join('|')})`, 'g');\n\n // Map pattern back to label for quick lookup\n const patternToLabel = new Map(replacements.map((r) => [r.pattern, r.label]));\n\n return text.replace(regex, (match) => patternToLabel.get(match) || match);\n}\n\n/**\n * Common helper to build a dictionary of User ID -> Display Name\n * from the channel state, used for rendering Mentions and System logs.\n */\nexport function buildUserMap(channelState: any): Record<string, string> {\n const map: Record<string, string> = {};\n const members = channelState?.members;\n if (members && typeof members === 'object') {\n for (const [id, member] of Object.entries<any>(members)) {\n map[id] = member?.user?.name || member?.user_id || id;\n }\n }\n return map;\n}\n\n/**\n * Move caret to the very end of a contenteditable element.\n */\nexport function moveCaretToEnd(el: HTMLElement) {\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.selectNodeContents(el);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Move caret immediately after a specific DOM node.\n */\nexport function moveCaretAfterNode(node: Node) {\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Checks if a given attachment represents user-managed media (e.g., photo, video, text file, voice)\n * as opposed to backend-injected automated system cards (like linkPreviews or slash commands).\n */\nexport function isUserManagedAttachment(attachment: Attachment): boolean {\n const type = attachment.type || 'file';\n return ['image', 'video', 'file', 'voiceRecording'].includes(type);\n}\n\n/**\n * Lightweight in-memory image preloader.\n */\nconst preloadedUrls = new Set<string>();\nconst MAX_CACHE_SIZE = 500;\n\nexport function preloadImage(url: string): void {\n if (!url || preloadedUrls.has(url)) return;\n\n if (preloadedUrls.size >= MAX_CACHE_SIZE) {\n const first = preloadedUrls.values().next().value;\n if (first) preloadedUrls.delete(first);\n }\n\n const img = new Image();\n img.src = url;\n preloadedUrls.add(url);\n}\n\nexport function isImagePreloaded(url: string): boolean {\n return preloadedUrls.has(url);\n}\n\n/**\n * Format bytes into a human-readable file size (e.g. \"1.2 MB\").\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n}\n\n/**\n * Format a date string into a relative label:\n * \"Today\", \"Yesterday\", \"Xd ago\", or \"Mon DD\" / \"Mon DD, YYYY\".\n */\nexport function formatRelativeDate(dateStr: string): string {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n if (diffDays < 7) return `${diffDays}d ago`;\n\n return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined });\n}\n\n/**\n * Get a cleaned display name from a raw file_name.\n * Strips UUID-heavy prefixes that the API sometimes prepends.\n */\nexport function getDisplayName(fileName: string): string {\n const parts = fileName.split('-');\n if (parts.length > 5) {\n const ext = fileName.split('.').pop() || '';\n return `file.${ext}`;\n }\n return fileName;\n}\n\n/**\n * Extract the hostname from a URL string. Returns the original string on error.\n */\nexport function extractDomain(url: string): string {\n try {\n return new URL(url).hostname;\n } catch {\n return url;\n }\n}\n","import { useContext } from 'react';\nimport { ChatContext } from '../context/ChatProvider';\nimport type { ChatContextValue } from '../context/ChatProvider';\n\nexport const useChatClient = (): ChatContextValue => {\n const ctx = useContext(ChatContext);\n if (!ctx) {\n throw new Error('useChatClient must be used within a ChatProvider');\n }\n return ctx;\n};\n","import { useState, useEffect, useCallback } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport type { UseChannelReturn } from '../types';\n\nexport type { UseChannelReturn } from '../types';\n\nexport const useChannel = (): UseChannelReturn => {\n const { activeChannel } = useChatClient();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n return {\n channel: activeChannel,\n loading,\n error,\n };\n};\n","import { useEffect, useRef } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isDirectChannel } from '../channelTypeUtils';\nimport { isPendingMember } from '../channelRoleUtils';\n\n/**\n * Subscribes to real-time events and keeps the channel list in sync:\n *\n * 1. `message.new` → moves channel to top, auto-calls `markRead()` if\n * the channel is currently active\n * 2. `message.read` → triggers re-render so the unread badge disappears\n *\n * The SDK already mutates `channel.state.latestMessages` and\n * `channel.state.unreadCount` before our listener fires, so we only\n * need to re-order / flush the React state.\n */\nexport function useChannelListUpdates(\n channels: Channel[],\n setChannels: React.Dispatch<React.SetStateAction<Channel[]>>,\n): void {\n const { client, activeChannel, setActiveChannel } = useChatClient();\n\n // Ref to always have the latest activeChannel without re-subscribing\n const activeChannelRef = useRef(activeChannel);\n activeChannelRef.current = activeChannel;\n\n useEffect(() => {\n // --- message.new: re-sort + auto mark-read ---\n const handleNewMessage = (event: Event) => {\n const eventCid = event.cid;\n if (!eventCid) return;\n\n // If the new message is on the active channel and from someone else,\n // mark it as read immediately so unreadCount resets to 0.\n // Skip markRead if the current user is banned, blocked, or pending in that channel.\n const active = activeChannelRef.current;\n if (active?.cid === eventCid && event.user?.id !== client.userID) {\n const isBannedInActive = Boolean(active.state?.membership?.banned);\n const isBlockedInActive = isDirectChannel(active) && Boolean(active.state?.membership?.blocked);\n const isPendingActive = isPendingMember(active.state?.membership?.channel_role as string);\n\n if (!isBannedInActive && !isBlockedInActive && !isPendingActive) {\n active.markRead().catch(() => {\n // silently ignore mark-read errors\n });\n }\n }\n\n setChannels((prev) => {\n const idx = prev.findIndex((ch) => ch.cid === eventCid);\n if (idx <= 0) {\n // Already at top or not found — just create a new reference\n return idx === 0 ? [...prev] : prev;\n }\n\n const channel = prev[idx];\n\n // Don't move banned channels to the top\n if (channel.state?.membership?.banned) {\n return [...prev];\n }\n\n // Move channel to the top\n const updated = [...prev];\n const [ch] = updated.splice(idx, 1);\n updated.unshift(ch);\n return updated;\n });\n };\n\n // --- channel.deleted: remove from list and reset active ---\n const handleChannelDeleted = (event: Event) => {\n const eventCid = event.cid || event.channel?.cid;\n if (!eventCid) return;\n\n if (activeChannelRef.current?.cid === eventCid) {\n setActiveChannel(null);\n }\n\n setChannels((prev) => prev.filter((ch) => ch.cid !== eventCid));\n };\n\n // --- member.removed / notification.invite_rejected: remove from list if it's current user ---\n const handleMemberRemoved = (event: Event) => {\n const eventCid = event.cid || event.channel?.cid;\n // channel_id is often used in notification.* events instead of .cid directly\n const normalizedCid = eventCid\n ? eventCid\n : (event as Record<string, unknown>).channel_id\n ? `${(event as Record<string, unknown>).channel_type}:${(event as Record<string, unknown>).channel_id}`\n : undefined;\n\n if (!normalizedCid) return;\n\n const removedUserId = event.member?.user_id || event.member?.user?.id || event.user?.id;\n\n // If the current user was removed or rejected the invite, remove the channel from their list\n if (removedUserId === client.userID) {\n if (activeChannelRef.current?.cid === normalizedCid) {\n setActiveChannel(null);\n }\n setChannels((prev) => prev.filter((ch) => ch.cid !== normalizedCid));\n }\n // Note: We don't trigger a global global re-render here if someone else is removed.\n // Individual ChannelRow components handle UI updates (e.g., via channel.updated or member.removed events locally).\n };\n\n // --- channel.created: fetch channel details and prepend to list ---\n const handleChannelCreated = async (event: Event, forceWatch: boolean = false) => {\n const type = event.channel?.type || (event as Record<string, unknown>).channel_type;\n const id = event.channel?.id || (event as Record<string, unknown>).channel_id;\n const cid = event.channel?.cid || event.cid || `${type}:${id}`;\n\n if (!type || !id) return;\n\n try {\n // Initialize or retrieve channel instance from SDK cache\n const channelInstance = client.channel(type as string, id as string);\n\n // If this is a member.added event (where event.member belongs to the current user),\n // we optimistically inject the membership so it instantly jumps into pending invites!\n // We DO NOT do this for channel.created, because in channel.created, event.member is the creator (owner).\n if (!forceWatch && event.type === 'member.added' && event.member && channelInstance.state) {\n channelInstance.state.membership = {\n ...channelInstance.state.membership,\n ...event.member,\n } as unknown as Record<string, unknown>;\n }\n\n // If the caller requested an explicit api call (e.g. for channel.created)\n if (forceWatch && !channelInstance.initialized) {\n await channelInstance.watch().catch((err) => console.error('Failed to watch channel:', err));\n }\n\n setChannels((prev) => {\n // Double check to prevent duplicates after async pause\n if (prev.some((c) => c.cid === cid)) {\n return prev;\n }\n return [channelInstance, ...prev];\n });\n\n // Loop wait for the core SDK to finish populating the local state from its own watch\n if (!channelInstance.initialized) {\n let attempts = 0;\n const checkInitialized = setInterval(() => {\n attempts++;\n if (channelInstance.initialized || attempts > 60 /* 3s max */) {\n clearInterval(checkInitialized);\n if (channelInstance.initialized) {\n // Force useMemo in ChannelList to recalculate classification (invite vs regular) just in case\n setChannels((p) => [...p]);\n // Manually synthesize a channel.updated event to bust the React.memo inside ChannelItem\n const clientObj = channelInstance.getClient();\n if ('dispatchEvent' in clientObj && typeof clientObj.dispatchEvent === 'function') {\n (clientObj.dispatchEvent as Function)({\n type: 'channel.updated',\n cid: channelInstance.cid,\n channel: channelInstance.data,\n });\n }\n }\n }\n }, 50);\n }\n } catch (err) {\n console.error('Failed to watch newly created channel:', err);\n }\n };\n\n // --- member.added / notification.added_to_channel: fetch if current user is added/invited ---\n const handleMemberAdded = async (event: Event) => {\n const addedUserId = event.member?.user_id || event.member?.user?.id;\n // If the current user was invited or added, fetch the channel (NO API duplication)\n if (addedUserId === client.userID) {\n await handleChannelCreated(event, false);\n }\n };\n\n // --- notification.invite_accepted: force re-grouping ---\n const handleMemberUpdated = (event: Event) => {\n const updatedUserId = event.member?.user_id || event.member?.user?.id || event.user?.id;\n if (updatedUserId === client.userID) {\n setChannels((prev) => {\n // Defensively mutate the channel's membership before grouping logic runs\n const eventCid =\n event.cid ||\n event.channel?.cid ||\n ((event as Record<string, unknown>).channel_id\n ? `${(event as Record<string, unknown>).channel_type}:${(event as Record<string, unknown>).channel_id}`\n : undefined);\n\n if (eventCid && event.member) {\n const targetChannel = prev.find((c) => c.cid === eventCid);\n // We forcefully map the updated incoming member data into the static channel representation\n if (targetChannel && targetChannel.state) {\n targetChannel.state.membership = {\n ...targetChannel.state.membership,\n ...event.member,\n } as unknown as Record<string, unknown>;\n }\n }\n\n return [...prev]; // Force react map to regenerate\n });\n }\n };\n\n // --- channel.topic.enabled / disabled / created / channel.pinned / channel.unpinned: force re-render so ChannelList toggles Accordion UI, inserts new topic, or updates pinned channels ---\n const handleGenericUpdate = (event: Event) => {\n setChannels((prev) => [...prev]);\n };\n\n const sub1 = client.on('message.new', handleNewMessage);\n const sub2 = client.on('channel.deleted', handleChannelDeleted);\n const sub3 = client.on('member.removed', handleMemberRemoved);\n const sub4 = client.on('channel.created', (event) => handleChannelCreated(event, true));\n const sub5 = client.on('member.added', handleMemberAdded);\n const sub6 = client.on('notification.added_to_channel', handleMemberAdded);\n const sub7 = client.on('notification.invite_rejected', handleMemberRemoved);\n const sub8 = client.on('notification.invite_accepted', handleMemberUpdated);\n const sub9 = client.on('channel.topic.enabled', handleGenericUpdate);\n const sub10 = client.on('channel.topic.disabled', handleGenericUpdate);\n const sub11 = client.on('channel.topic.created', handleGenericUpdate);\n const sub12 = client.on('channel.pinned', handleGenericUpdate);\n const sub13 = client.on('channel.unpinned', handleGenericUpdate);\n const sub14 = client.on('notification.invite_messaging_skipped', handleMemberUpdated);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n sub12.unsubscribe();\n sub13.unsubscribe();\n sub14.unsubscribe();\n };\n }, [client, setChannels, setActiveChannel]);\n}\n","import type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n// ─── Group Channel Types ───────────────────────────\n// Types that behave like group/team channels (roles, capabilities, settings, topics)\nconst GROUP_CHANNEL_TYPES = new Set(['team', 'meeting']);\n\n// ─── Direct Channel Types ──────────────────────────\n// Types that behave like 1-on-1 direct messaging (block/unblock)\nconst DIRECT_CHANNEL_TYPES = new Set(['messaging']);\n\n// ─── Semantic Helpers ──────────────────────────────\n\n/** Channel supports group features: roles, capabilities, settings, topics, edit, delete */\nexport function isGroupChannel(channel: Channel | null | undefined): boolean {\n return channel ? GROUP_CHANNEL_TYPES.has(channel.type) : false;\n}\n\n/** Channel is a direct (1-on-1) conversation: block/unblock, no roles */\nexport function isDirectChannel(channel: Channel | null | undefined): boolean {\n return channel ? DIRECT_CHANNEL_TYPES.has(channel.type) : false;\n}\n\n/** Channel is a topic (sub-channel of a group channel) */\nexport function isTopicChannel(channel: Channel | null | undefined): boolean {\n return channel ? (channel.type === 'topic' || Boolean(channel.data?.parent_cid)) : false;\n}\n\n/** Channel is a public group that users can join without invite */\nexport function isPublicGroupChannel(channel: Channel | null | undefined): boolean {\n return isGroupChannel(channel) && Boolean(channel?.data?.public);\n}\n\n/** The proxy \"general\" channel of a topics-enabled group */\nexport function isGeneralProxy(channel: Channel | null | undefined): boolean {\n return isGroupChannel(channel) && channel?.data?.name === 'general';\n}\n\n/** Channel has topics feature enabled */\nexport function hasTopicsEnabled(channel: Channel | null | undefined): boolean {\n return isGroupChannel(channel) && Boolean(channel?.data?.topics_enabled);\n}\n\n/** Whether blocked state is relevant for this channel type */\nexport function supportsBlocking(channel: Channel | null | undefined): boolean {\n return isDirectChannel(channel);\n}\n","import type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isDirectChannel } from './channelTypeUtils';\n\nexport const CHANNEL_ROLES = {\n OWNER: 'owner',\n MODERATOR: 'moder',\n MEMBER: 'member',\n PENDING: 'pending',\n SKIPPED: 'skipped',\n} as const;\n\nexport type ChannelRole = typeof CHANNEL_ROLES[keyof typeof CHANNEL_ROLES] | string;\n\n/** Checks if the user is in a pending state */\nexport function isPendingMember(role?: string): boolean {\n return role === CHANNEL_ROLES.PENDING;\n}\n\n/** Checks if the user is in a skipped state (skipped a direct message invite) */\nexport function isSkippedMember(role?: string): boolean {\n return role === CHANNEL_ROLES.SKIPPED;\n}\n\n/** Checks if the user has management permissions (owner or moderator) */\nexport function canManageChannel(role?: string): boolean {\n return role === CHANNEL_ROLES.OWNER || role === CHANNEL_ROLES.MODERATOR;\n}\n\n/** Determines if the current user has the permission to remove a specific target member */\nexport function canRemoveTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n const isTargetRemovable =\n targetRole === CHANNEL_ROLES.MEMBER ||\n targetRole === CHANNEL_ROLES.PENDING ||\n (currentUserRole === CHANNEL_ROLES.OWNER && targetRole === CHANNEL_ROLES.MODERATOR);\n \n return canManageChannel(currentUserRole) && isTargetRemovable;\n}\n\n/** Determines if the current user has the permission to ban a specific target member */\nexport function canBanTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n return canRemoveTargetMember(currentUserRole, targetRole) && targetRole !== CHANNEL_ROLES.PENDING;\n}\n\n/** Determines if the current user has the permission to promote a member to moderator */\nexport function canPromoteTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n return currentUserRole === CHANNEL_ROLES.OWNER && targetRole === CHANNEL_ROLES.MEMBER;\n}\n\n/** Determines if the current user has the permission to demote a moderator to simple member */\nexport function canDemoteTargetMember(currentUserRole?: string, targetRole?: string): boolean {\n return currentUserRole === CHANNEL_ROLES.OWNER && targetRole === CHANNEL_ROLES.MODERATOR;\n}\n\n/** Checks if the user is an owner of the channel */\nexport function isOwnerMember(role?: string): boolean {\n return role === CHANNEL_ROLES.OWNER;\n}\n\n/**\n * Checks if a direct channel represents a \"friend\" relationship:\n * both members must have the 'owner' channel_role.\n */\nexport function isFriendChannel(\n channel: Channel | null | undefined,\n targetUserId: string,\n currentUserId: string,\n): boolean {\n if (!channel || !isDirectChannel(channel)) return false;\n const targetMember = channel.state?.members?.[targetUserId];\n const currentMember = channel.state?.members?.[currentUserId];\n return isOwnerMember(targetMember?.channel_role as string)\n && isOwnerMember(currentMember?.channel_role as string);\n}\n","import { useEffect, useState } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isDirectChannel } from '../channelTypeUtils';\n\n/**\n * Custom hook to abstract real-time row-level updates for a single channel.\n * Manages the local unread count, last message preview, and banned status for the channel row in the list.\n */\nexport function useChannelRowUpdates(channel: Channel, currentUserId?: string) {\n // Track banned state for the current user in this channel\n const [isBannedInChannel, setIsBannedInChannel] = useState(() => Boolean(channel.state?.membership?.banned));\n const [isBlockedInChannel, setIsBlockedInChannel] = useState(() => {\n if (!isDirectChannel(channel)) return false;\n return Boolean(channel.state?.membership?.blocked);\n });\n\n // Force re-render when messages, members, or read state changes\n const [updateCount, setUpdateCount] = useState(0);\n\n useEffect(() => {\n setIsBannedInChannel(Boolean(channel.state?.membership?.banned));\n setIsBlockedInChannel(\n isDirectChannel(channel) ? Boolean(channel.state?.membership?.blocked) : false\n );\n\n const handleBanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBannedInChannel(true);\n }\n };\n const handleUnbanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBannedInChannel(false);\n }\n };\n\n const handleUpdate = () => setUpdateCount((c) => c + 1);\n\n const sub1 = channel.on('member.banned', handleBanned);\n const sub2 = channel.on('member.unbanned', handleUnbanned);\n const sub3 = channel.on('message.new', handleUpdate);\n const sub4 = channel.on('message.read', handleUpdate);\n const sub5 = channel.on('message.updated', handleUpdate);\n const sub6 = channel.on('message.deleted', handleUpdate);\n const sub7 = channel.on('channel.updated', handleUpdate);\n const sub8 = channel.on('member.added', handleUpdate);\n const sub9 = channel.on('member.removed', handleUpdate);\n\n // Blocked state (messaging channels only)\n const handleBlocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlockedInChannel(true);\n }\n };\n const handleUnblocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlockedInChannel(false);\n }\n };\n const sub10 = channel.on('member.blocked', handleBlocked);\n const sub11 = channel.on('member.unblocked', handleUnblocked);\n const sub12 = channel.on('channel.topic.created', handleUpdate);\n const sub13 = channel.on('channel.pinned', handleUpdate);\n const sub14 = channel.on('channel.unpinned', handleUpdate);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n sub12.unsubscribe();\n sub13.unsubscribe();\n sub14.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBannedInChannel, isBlockedInChannel, updateCount };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\n/**\n * Hook that tracks whether the current user is banned in the given channel.\n *\n * Reads the initial value from `channel.state.membership.banned` and subscribes\n * to `member.banned` / `member.unbanned` WebSocket events for real-time updates.\n * If the channel is a topic, it also synchronizes with the parent channel's ban state.\n *\n * Only triggers a re-render when the *current user* is the target of the event.\n */\nexport function useBannedState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isBanned, setIsBanned] = useState<boolean>(() => {\n if (!channel) return false;\n const parentCid = channel.data?.parent_cid as string | undefined;\n const parentChannel = parentCid ? channel.getClient().activeChannels[parentCid] : undefined;\n return Boolean(channel.state?.membership?.banned || parentChannel?.state?.membership?.banned);\n });\n\n useEffect(() => {\n if (!channel) {\n setIsBanned(false);\n return;\n }\n\n const parentCid = channel.data?.parent_cid as string | undefined;\n const parentChannel = parentCid ? channel.getClient().activeChannels[parentCid] : undefined;\n\n // Sync initial state when channel changes\n setIsBanned(Boolean(channel.state?.membership?.banned || parentChannel?.state?.membership?.banned));\n\n const handleBanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBanned(true);\n }\n };\n\n const handleUnbanned = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n const eventCid = event.cid || (event.channel_type ? `${event.channel_type}:${event.channel_id}` : undefined);\n let cBanned = Boolean(channel.state?.membership?.banned);\n let pBanned = Boolean(parentChannel?.state?.membership?.banned);\n \n if (eventCid === channel.cid) cBanned = false;\n if (parentChannel && eventCid === parentChannel.cid) pBanned = false;\n \n setIsBanned(cBanned || pBanned);\n }\n };\n\n const sub1 = channel.on('member.banned', handleBanned);\n const sub2 = channel.on('member.unbanned', handleUnbanned);\n\n let sub3: { unsubscribe: () => void } | undefined;\n let sub4: { unsubscribe: () => void } | undefined;\n\n if (parentChannel) {\n sub3 = parentChannel.on('member.banned', handleBanned);\n sub4 = parentChannel.on('member.unbanned', handleUnbanned);\n }\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n if (sub3) sub3.unsubscribe();\n if (sub4) sub4.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBanned };\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isDirectChannel } from '../channelTypeUtils';\n\n/**\n * Hook that tracks whether the current user has blocked the other party\n * in a messaging (1-1) channel.\n *\n * Reads the initial value from `channel.state.membership.blocked` and subscribes\n * to `member.blocked` / `member.unblocked` WebSocket events for real-time updates.\n *\n * Only triggers a re-render when the *current user* is the target of the event\n * (i.e., the blocker). When user A blocks user B, only A's membership has\n * `blocked: true`. B is unaffected.\n *\n * This hook is only meaningful for `messaging` channels. For `team` channels,\n * use `useBannedState` instead.\n */\nexport function useBlockedState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isBlocked, setIsBlocked] = useState<boolean>(() => {\n if (!isDirectChannel(channel)) return false;\n return Boolean(channel?.state?.membership?.blocked);\n });\n\n useEffect(() => {\n if (!channel || !isDirectChannel(channel)) {\n setIsBlocked(false);\n return;\n }\n\n // Sync initial state when channel changes\n setIsBlocked(Boolean(channel.state?.membership?.blocked));\n\n const handleBlocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlocked(true);\n }\n };\n\n const handleUnblocked = (event: any) => {\n if (event.member?.user_id === currentUserId) {\n setIsBlocked(false);\n }\n };\n\n const sub1 = channel.on('member.blocked', handleBlocked);\n const sub2 = channel.on('member.unblocked', handleUnblocked);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isBlocked };\n}\n","import { useState, useEffect, useMemo } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isFriendChannel } from '../channelRoleUtils';\n\nexport type OnlineStatus = 'online' | 'offline' | 'unknown';\n\n/**\n * Hook that returns the online/offline status of a specific user.\n *\n * The status is determined by checking `channel.state.watchers` on the\n * \"friend\" channel (direct channel where both members have `owner` role).\n * Real-time updates are received via `user.watching.start` and\n * `user.watching.stop` WebSocket events on that channel.\n *\n * Returns `'unknown'` if the user is not a friend (no qualifying channel found).\n *\n * @param userId – The user ID to check the online status of.\n * @param channels – The full list of loaded channels (from ChannelList).\n */\nexport function useOnlineStatus(\n userId: string | undefined,\n channels: Channel[],\n): OnlineStatus {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Find the friend channel for this user — memoized to avoid re-scans.\n const friendChannel = useMemo(() => {\n if (!userId || !currentUserId || userId === currentUserId) return null;\n return channels.find((ch) => isFriendChannel(ch, userId, currentUserId)) || null;\n }, [channels, userId, currentUserId]);\n\n // Derive initial status from watchers state.\n const [status, setStatus] = useState<OnlineStatus>(() => {\n if (!friendChannel || !userId) return 'unknown';\n return friendChannel.state?.watchers?.[userId] ? 'online' : 'offline';\n });\n\n useEffect(() => {\n if (!friendChannel || !userId) {\n setStatus('unknown');\n return;\n }\n\n // Sync initial state (in case friendChannel ref changed).\n setStatus(friendChannel.state?.watchers?.[userId] ? 'online' : 'offline');\n\n const handleWatchingStart = (event: Event) => {\n if (event.user?.id === userId) {\n setStatus('online');\n }\n };\n\n const handleWatchingStop = (event: Event) => {\n if (event.user?.id === userId) {\n setStatus('offline');\n }\n };\n\n const sub1 = friendChannel.on('user.watching.start', handleWatchingStart);\n const sub2 = friendChannel.on('user.watching.stop', handleWatchingStop);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [friendChannel, userId]);\n\n return status;\n}\n","import { useState, useEffect, useMemo, useRef } from 'react';\nimport type { Channel, Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isFriendChannel } from '../channelRoleUtils';\n\n/**\n * Bulk hook that returns a `Set<string>` of user IDs that are currently online.\n *\n * Only users who are \"friends\" (exist in a direct channel where both\n * members have `owner` role) are tracked. The status is derived from\n * `channel.state.watchers` and kept in sync via `user.watching.start`\n * and `user.watching.stop` WebSocket events at the **client** level\n * for efficiency (single subscription instead of N per-channel ones).\n *\n * Usage in ChannelList: `const onlineUsers = useOnlineUsers(channels);`\n * Then check: `onlineUsers.has(userId)`.\n *\n * @param channels – The full list of loaded channels (from ChannelList).\n */\nexport function useOnlineUsers(channels: Channel[]): Set<string> {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Build a map: friendUserId → Channel (the friend channel).\n // This memoizes the friend channel lookup so we only iterate once per channels change.\n const friendMap = useMemo(() => {\n const map = new Map<string, Channel>();\n if (!currentUserId) return map;\n\n for (const ch of channels) {\n const members = ch.state?.members;\n if (!members) continue;\n\n // Find the \"other\" user in this channel\n for (const memberId of Object.keys(members)) {\n if (memberId === currentUserId) continue;\n if (isFriendChannel(ch, memberId, currentUserId)) {\n map.set(memberId, ch);\n }\n }\n }\n return map;\n }, [channels, currentUserId]);\n\n // Compute the initial set of online users from watchers.\n const computeOnlineSet = (): Set<string> => {\n const set = new Set<string>();\n for (const [userId, ch] of friendMap.entries()) {\n if (ch.state?.watchers?.[userId]) {\n set.add(userId);\n }\n }\n return set;\n };\n\n const [onlineUsers, setOnlineUsers] = useState<Set<string>>(() => computeOnlineSet());\n\n // Keep friendMap in a ref so that event handlers always see the latest version.\n const friendMapRef = useRef(friendMap);\n friendMapRef.current = friendMap;\n\n // Re-compute when friendMap changes (new channels loaded, channels array mutated).\n useEffect(() => {\n setOnlineUsers(computeOnlineSet());\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [friendMap]);\n\n // Subscribe at the client level for efficiency.\n useEffect(() => {\n if (!currentUserId) return;\n\n const handleWatchingStart = (event: Event) => {\n const userId = event.user?.id;\n const eventCid = event.cid;\n if (!userId || !eventCid) return;\n\n // Check if this userId belongs to a tracked friend channel\n const tracked = friendMapRef.current.get(userId);\n if (tracked && tracked.cid === eventCid) {\n setOnlineUsers((prev) => {\n if (prev.has(userId)) return prev;\n const next = new Set(prev);\n next.add(userId);\n return next;\n });\n }\n };\n\n const handleWatchingStop = (event: Event) => {\n const userId = event.user?.id;\n const eventCid = event.cid;\n if (!userId || !eventCid) return;\n\n const tracked = friendMapRef.current.get(userId);\n if (tracked && tracked.cid === eventCid) {\n setOnlineUsers((prev) => {\n if (!prev.has(userId)) return prev;\n const next = new Set(prev);\n next.delete(userId);\n return next;\n });\n }\n };\n\n const sub1 = client.on('user.watching.start', handleWatchingStart);\n const sub2 = client.on('user.watching.stop', handleWatchingStop);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [client, currentUserId]);\n\n return onlineUsers;\n}\n","import { useState, useEffect } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { isPendingMember } from '../channelRoleUtils';\n\n/**\n * Hook that tracks whether the current user is in a 'pending' state for the given channel.\n */\nexport function usePendingState(channel: Channel | null | undefined, currentUserId?: string) {\n const [isPending, setIsPending] = useState<boolean>(() => {\n const membership = channel?.state?.membership || channel?.state?.members?.[currentUserId || ''];\n return isPendingMember(membership?.channel_role as string);\n });\n\n useEffect(() => {\n if (!channel || !currentUserId) {\n setIsPending(false);\n return;\n }\n\n const checkPending = () => {\n const membership = channel.state?.membership || channel.state?.members?.[currentUserId];\n return isPendingMember(membership?.channel_role as string);\n };\n\n // Sync initial state\n setIsPending(checkPending());\n\n const defensiveUpdateState = (event: Record<string, unknown>) => {\n // The SDK does not aggressively mutate local state for all events,\n // so we manually map the incoming `member` data onto the channel state so `checkPending` sees it.\n if (event.member && channel.state && channel.state.membership) {\n channel.state.membership = {\n ...channel.state.membership,\n ...(event.member as Record<string, unknown>),\n } as unknown as Record<string, unknown>;\n }\n };\n\n const handleInviteAction = (event: Record<string, unknown>) => {\n const eventMember = event.member as Record<string, unknown>;\n const eventUser = event.user as Record<string, unknown>;\n const eventUserId = eventMember?.user_id || (eventMember?.user as Record<string, unknown>)?.id || eventUser?.id;\n if (eventUserId !== currentUserId) return; // Only react to own invite events\n\n const eventCid =\n event.cid ||\n (event.channel as Record<string, unknown>)?.cid ||\n (event.channel_id ? `${event.channel_type}:${event.channel_id}` : undefined);\n if (eventCid === channel.cid) {\n defensiveUpdateState(event);\n setIsPending(checkPending());\n }\n };\n\n const client = channel.getClient();\n const sub1 = client.on('notification.invite_accepted', handleInviteAction);\n const sub2 = client.on('notification.invite_rejected', handleInviteAction);\n const sub3 = client.on('notification.invite_messaging_skipped', handleInviteAction);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n };\n }, [channel, currentUserId]);\n\n return { isPending };\n}\n","import React, { useEffect, useState, useCallback, useMemo } from 'react';\nimport { VList } from 'virtua';\nimport type { Channel, Event, ChannelFilters } from '@ermis-network/ermis-chat-sdk';\nimport { parseSystemMessage, parseSignalMessage } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useChannelListUpdates } from '../hooks/useChannelListUpdates';\nimport { useOnlineUsers } from '../hooks/useOnlineUsers';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport { useChannelRowUpdates } from '../hooks/useChannelRowUpdates';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { Avatar } from './Avatar';\nimport type { ChannelItemProps, ChannelListProps } from '../types';\n\nexport type { ChannelListProps, ChannelItemProps } from '../types';\nimport type { ChannelActionsProps } from '../types';\nimport { TopicModal } from './TopicModal';\nimport { DefaultChannelActions, computeDefaultActions } from './ChannelActions';\nimport { isDirectChannel, hasTopicsEnabled } from '../channelTypeUtils';\nimport { canManageChannel, isPendingMember, isSkippedMember, isFriendChannel } from '../channelRoleUtils';\n\nexport { DefaultChannelActions } from './ChannelActions';\nexport type { ChannelAction, ChannelActionsProps } from '../types';\n\n/**\n * Get a human-readable preview string for the last message,\n * handling regular, system, and signal message types.\n */\nfunction getLastMessagePreview(\n channel: Channel,\n myUserId?: string,\n): { text: string; user: string; timestamp?: string | Date } {\n const lastMsg = channel.state?.latestMessages?.slice(-1)[0];\n if (!lastMsg) return { text: '', user: '' };\n\n const timestamp = lastMsg.created_at;\n\n const msgType = lastMsg.type || 'regular';\n const rawText = lastMsg.text ?? '';\n\n if (msgType === 'system') {\n const userMap = buildUserMap(channel.state);\n return { text: parseSystemMessage(rawText, userMap), user: '', timestamp };\n }\n\n if (msgType === 'signal') {\n const result = parseSignalMessage(rawText, myUserId || '');\n return { text: result?.text || rawText, user: '', timestamp };\n }\n\n // Display 'Sticker' if message is a sticker\n if (msgType === 'sticker' || (lastMsg as Record<string, unknown>).sticker_url) {\n return { text: 'Sticker', user: lastMsg.user?.name || lastMsg.user_id || '', timestamp };\n }\n\n // Regular / other\n let displayText = rawText;\n if (!displayText && lastMsg.attachments && lastMsg.attachments.length > 0) {\n const att = lastMsg.attachments[0];\n const type = att.type || '';\n switch (type) {\n case 'image':\n displayText = '📷 Photo';\n break;\n case 'video':\n displayText = '🎬 Video';\n break;\n case 'voiceRecording':\n displayText = '🎤 Voice message';\n break;\n default:\n displayText = '📎 File';\n break;\n }\n if (lastMsg.attachments.length > 1) {\n displayText += ` +${lastMsg.attachments.length - 1}`;\n }\n }\n\n // Format mentions if necessary\n const lastMsgRecord = lastMsg as Record<string, unknown>;\n const mentionedUsers = lastMsgRecord.mentioned_users as string[] | undefined;\n const mentionedAll = lastMsgRecord.mentioned_all as boolean | undefined;\n\n if (displayText && (mentionedAll || (mentionedUsers && mentionedUsers.length > 0))) {\n const userMap = buildUserMap(channel.state);\n displayText = replaceMentionsForPreview(displayText, lastMsg as any, userMap);\n }\n\n return {\n text: displayText,\n user: lastMsg.user?.name || lastMsg.user_id || '',\n timestamp,\n };\n}\n\n/* ----------------------------------------------------------\n Memoized channel list item (exported for consumer reuse)\n ---------------------------------------------------------- */\nexport const ChannelItem: React.FC<ChannelItemProps> = React.memo(({\n channel,\n isActive,\n hasUnread,\n unreadCount,\n lastMessageText,\n lastMessageUser,\n lastMessageTimestamp,\n onSelect,\n AvatarComponent,\n isBlocked,\n isPending,\n pendingBadgeLabel,\n blockedBadgeLabel,\n isClosedTopic,\n closedTopicIcon,\n PinnedIconComponent,\n ChannelActionsComponent,\n onAddTopic,\n onEditTopic,\n onToggleCloseTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n isOnline,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client.userID;\n\n // Subscribe to channel.updated so that when name/image/description change,\n // we re-render from within (bypasses React.memo which only blocks parent-driven re-renders)\n const [updateCount, forceUpdate] = useState(0);\n useEffect(() => {\n const handleUpdate = () => forceUpdate((c) => c + 1);\n const sub1 = channel.on('channel.updated', handleUpdate);\n const sub2 = channel.on('channel.pinned', handleUpdate);\n const sub3 = channel.on('channel.unpinned', handleUpdate);\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n };\n }, [channel]);\n\n const defaultActions = useMemo(\n () => computeDefaultActions(channel, currentUserId, { onAddTopic, onEditTopic, onToggleCloseTopic, isBlocked, actionLabels, actionIcons }),\n [channel, currentUserId, updateCount, onAddTopic, onEditTopic, onToggleCloseTopic, isBlocked, actionLabels, actionIcons],\n );\n\n const filteredActions = useMemo(() => {\n if (!hiddenActions || hiddenActions.length === 0) return defaultActions;\n return defaultActions.filter(a => !hiddenActions.includes(a.id));\n }, [defaultActions, hiddenActions]);\n const ActionsComponent = ChannelActionsComponent || DefaultChannelActions;\n\n const name = channel.data?.name || channel.cid;\n const image = channel.data?.image as string | undefined;\n const showUnread = hasUnread && !isActive;\n\n const timestampText = useMemo(() => {\n if (!lastMessageTimestamp) return null;\n const d = new Date(lastMessageTimestamp);\n if (isNaN(d.getTime())) return null;\n const today = new Date();\n const isToday = d.toDateString() === today.toDateString();\n return isToday\n ? d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n : d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }, [lastMessageTimestamp]);\n\n const handleClick = useCallback(() => {\n onSelect(channel);\n }, [channel, onSelect]);\n\n const itemClass = [\n 'ermis-channel-list__item',\n isActive ? 'ermis-channel-list__item--active' : '',\n showUnread ? 'ermis-channel-list__item--unread' : '',\n isPending ? 'ermis-channel-list__item--pending' : '',\n ].filter(Boolean).join(' ');\n\n return (\n <div className={itemClass} onClick={handleClick}>\n <div className=\"ermis-channel-list__item-avatar-wrapper\">\n <AvatarComponent image={image} name={name} size={40} disableLightbox />\n {isOnline !== undefined && (\n <span className={`ermis-channel-list__online-dot ermis-channel-list__online-dot--${isOnline ? 'online' : 'offline'}`} />\n )}\n </div>\n <div className=\"ermis-channel-list__item-content\">\n <div className=\"ermis-channel-list__item-top-row\">\n <div className=\"ermis-channel-list__item-name\">{name}</div>\n {channel.data?.is_pinned === true && !isClosedTopic && PinnedIconComponent && (\n <span className=\"ermis-channel-list__pinned-icon\" title=\"Pinned\">\n <PinnedIconComponent />\n </span>\n )}\n {isClosedTopic && (\n <span className=\"ermis-channel-list__closed-icon\">\n {closedTopicIcon || (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n )}\n </span>\n )}\n {!isClosedTopic && timestampText && <div className=\"ermis-channel-list__item-timestamp\">{timestampText}</div>}\n\n {isPending && (\n <span className=\"ermis-channel-list__pending-badge\">{pendingBadgeLabel || 'Invited'}</span>\n )}\n\n {isBlocked && (\n <span className=\"ermis-channel-list__blocked-icon\" title={blockedBadgeLabel || \"Blocked\"}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </span>\n )}\n </div>\n <div className=\"ermis-channel-list__item-bottom-row\">\n {!isClosedTopic && lastMessageText && (\n <div className=\"ermis-channel-list__item-last-message\">\n {lastMessageUser && (\n <span className=\"ermis-channel-list__item-last-message-user\">\n {lastMessageUser}:{' '}\n </span>\n )}\n <span>{lastMessageText}</span>\n </div>\n )}\n\n {!isClosedTopic && (\n <div className=\"ermis-channel-list__item-badges\">\n {showUnread && unreadCount > 0 && (\n <span className=\"ermis-channel-list__unread-badge\">\n {unreadCount > 99 ? '99+' : unreadCount}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n {!isPending && (\n <div className=\"ermis-channel-list__item-actions-wrapper\">\n <ActionsComponent channel={channel} actions={filteredActions} onClose={() => { }} />\n </div>\n )}\n </div>\n );\n});\nChannelItem.displayName = 'ChannelItem';\n\nexport const DefaultPinnedIcon = React.memo(() => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n));\nDefaultPinnedIcon.displayName = 'DefaultPinnedIcon';\n\nconst DefaultLoading = React.memo(({ text }: { text?: string }) => (\n <div className=\"ermis-channel-list__loading\">{text || 'Loading channels...'}</div>\n));\nDefaultLoading.displayName = 'DefaultLoading';\n\nconst DefaultEmpty = React.memo(({ text }: { text?: string }) => (\n <div className=\"ermis-channel-list__empty\">{text || 'No channels found'}</div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\n/* ----------------------------------------------------------\n Virtual Row Component to map channel and defer parsing\n ---------------------------------------------------------- */\ntype ChannelRowProps = {\n channel: Channel;\n isActive: boolean;\n handleSelect: (c: Channel) => void;\n renderChannel?: (c: Channel, active: boolean) => React.ReactNode;\n ChannelItemComponent: React.ComponentType<ChannelItemProps>;\n AvatarComponent: React.ComponentType<any>;\n currentUserId?: string;\n pendingBadgeLabel?: string;\n blockedBadgeLabel?: string;\n closedTopicIcon?: React.ReactNode;\n PinnedIconComponent?: React.ComponentType;\n ChannelActionsComponent?: React.ComponentType<ChannelActionsProps>;\n onAddTopic?: (channel: Channel) => void;\n onEditTopic?: (channel: Channel) => void;\n onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;\n hiddenActions?: string[];\n actionLabels?: import('../types').ChannelActionLabels;\n actionIcons?: import('../types').ChannelActionIcons;\n isOnline?: boolean;\n};\n\nconst ChannelRow: React.FC<ChannelRowProps> = React.memo(({\n channel,\n isActive,\n handleSelect,\n renderChannel,\n ChannelItemComponent,\n AvatarComponent,\n currentUserId,\n pendingBadgeLabel,\n blockedBadgeLabel,\n closedTopicIcon,\n PinnedIconComponent,\n ChannelActionsComponent,\n onAddTopic,\n onEditTopic,\n onToggleCloseTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n isOnline,\n}) => {\n // Use the new custom hook to handle all row-level realtime updates\n const { isBannedInChannel, isBlockedInChannel, updateCount } = useChannelRowUpdates(channel, currentUserId);\n const { isPending } = usePendingState(channel, currentUserId);\n const isSkipped = isSkippedMember(channel.state?.membership?.channel_role as string);\n\n const channelState = channel.state as unknown as Record<string, unknown> | undefined;\n const rawUnreadCount = (channelState?.unreadCount as number) ?? 0;\n\n const isClosedTopic = channel.data?.is_closed_topic === true;\n\n // Render logic continues...\n const unreadCount = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? 0 : rawUnreadCount;\n const hasUnread = unreadCount > 0;\n\n // Derive last message preview computation\n const { text: rawLastMessageText, user: rawLastMessageUser, timestamp: rawLastMessageTimestamp } = useMemo(\n () => getLastMessagePreview(channel, currentUserId),\n // Recompute if latestMessage changes or we get a force update\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [channel, channel.state?.latestMessages, updateCount]\n );\n\n // Hide last message preview when banned, blocked, pending or skipped\n const lastMessageText = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? '' : rawLastMessageText;\n const lastMessageUser = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? '' : rawLastMessageUser;\n const lastMessageTimestamp = (isBannedInChannel || isBlockedInChannel || isPending || isSkipped) ? null : rawLastMessageTimestamp;\n\n if (renderChannel) {\n return (\n <div onClick={() => handleSelect(channel)}>\n {renderChannel(channel, isActive)}\n </div>\n );\n }\n\n return (\n <ChannelItemComponent\n channel={channel}\n isActive={isActive}\n hasUnread={hasUnread}\n unreadCount={unreadCount}\n lastMessageText={lastMessageText}\n lastMessageUser={lastMessageUser}\n lastMessageTimestamp={lastMessageTimestamp}\n onSelect={handleSelect}\n AvatarComponent={AvatarComponent}\n isBlocked={isBlockedInChannel}\n isPending={isPending}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n isClosedTopic={isClosedTopic}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onAddTopic={onAddTopic}\n onEditTopic={onEditTopic}\n onToggleCloseTopic={onToggleCloseTopic}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n isOnline={isOnline}\n />\n );\n});\nChannelRow.displayName = 'ChannelRow';\n\nexport const ChannelTopicGroup = React.memo(({\n channel,\n activeChannel,\n handleSelect,\n renderChannel,\n ChannelItemComponent,\n AvatarComponent,\n GeneralTopicAvatarComponent,\n TopicAvatarComponent,\n currentUserId,\n pendingBadgeLabel,\n blockedBadgeLabel,\n generalTopicLabel,\n closedTopicIcon,\n PinnedIconComponent,\n ChannelActionsComponent,\n onAddTopic,\n onEditTopic,\n onToggleCloseTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n}: any) => {\n const { updateCount } = useChannelRowUpdates(channel, currentUserId);\n const [isExpanded, setIsExpanded] = useState(true);\n const [topicUpdateCount, setTopicUpdateCount] = useState(0);\n\n useEffect(() => {\n const subs: { unsubscribe: () => void }[] = [];\n const handleUpdate = () => setTopicUpdateCount((c) => c + 1);\n const currentTopics = channel.state?.topics || [];\n currentTopics.forEach((t: Channel) => {\n subs.push(t.on('channel.pinned', handleUpdate));\n subs.push(t.on('channel.unpinned', handleUpdate));\n subs.push(t.on('message.new', handleUpdate));\n subs.push(t.on('message.deleted', handleUpdate));\n });\n return () => {\n subs.forEach((s) => s.unsubscribe());\n };\n }, [channel.state?.topics]);\n\n const handleToggle = useCallback(() => setIsExpanded((prev) => !prev), []);\n\n const userRole = channel.state?.members?.[currentUserId]?.channel_role;\n const hasTopicAddPermission = canManageChannel(userRole);\n\n const getTopicTime = (t: Channel) => {\n const lastMsg = t.state?.latestMessages?.slice(-1)[0];\n if (lastMsg?.created_at) return new Date(lastMsg.created_at).getTime();\n if (t.data?.last_message_at) return new Date(t.data.last_message_at as string | Date).getTime();\n if (t.data?.created_at) return new Date(t.data.created_at as string | Date).getTime();\n return 0;\n };\n\n const topics = useMemo(() => {\n const allTopics = channel.state?.topics || [];\n return [...allTopics].sort((a: any, b: any) => {\n const aPinned = a.data?.is_pinned === true;\n const bPinned = b.data?.is_pinned === true;\n if (aPinned && !bPinned) return -1;\n if (!aPinned && bPinned) return 1;\n\n return getTopicTime(b) - getTopicTime(a);\n });\n }, [channel.state?.topics, topicUpdateCount]);\n const name = channel.data?.name || channel.cid;\n const image = channel.data?.image as string | undefined;\n\n const GeneralAvatar = useCallback(() => (\n <div className=\"ermis-channel-list__topic-hashtag\">#</div>\n ), []);\n\n const TopicEmojiAvatar = useCallback(({ image }: any) => {\n let emoji = '💬';\n if (image && typeof image === 'string' && image.startsWith('emoji://')) {\n emoji = image.replace('emoji://', '');\n }\n return <div className=\"ermis-channel-list__topic-hashtag\">{emoji}</div>;\n }, []);\n\n const generalChannelProxy = useMemo(() => {\n return new Proxy(channel, {\n get(target, prop, receiver) {\n if (prop === 'data') {\n return { ...target.data, name: generalTopicLabel || 'general', is_pinned: false };\n }\n const value = Reflect.get(target, prop, receiver);\n return typeof value === 'function' ? value.bind(target) : value;\n }\n });\n }, [channel, generalTopicLabel]);\n\n const defaultActions = useMemo(\n () => computeDefaultActions(channel, currentUserId, { onAddTopic, actionLabels, actionIcons }),\n [channel, currentUserId, updateCount, onAddTopic, actionLabels, actionIcons],\n );\n\n const filteredActions = useMemo(() => {\n if (!hiddenActions || hiddenActions.length === 0) return defaultActions;\n return defaultActions.filter((a: any) => !hiddenActions.includes(a.id));\n }, [defaultActions, hiddenActions]);\n const ActionsComponent = ChannelActionsComponent || DefaultChannelActions;\n\n return (\n <div className=\"ermis-channel-list__topic-group\">\n <div\n className={`ermis-channel-list__topic-header ${isExpanded ? 'ermis-channel-list__topic-header--expanded' : ''}`}\n onClick={handleToggle}\n >\n <AvatarComponent image={image} name={name} size={40} disableLightbox />\n <div className=\"ermis-channel-list__topic-header-name\">{name}</div>\n\n {channel.data?.is_pinned === true && PinnedIconComponent && (\n <span className=\"ermis-channel-list__pinned-icon\" title=\"Pinned\">\n <PinnedIconComponent />\n </span>\n )}\n\n <div className=\"ermis-channel-list__topic-actions-wrapper\">\n <ActionsComponent channel={channel} actions={filteredActions} onClose={() => { }} />\n </div>\n\n <svg\n className=\"ermis-channel-list__accordion-icon\"\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n\n {isExpanded && (\n <div className=\"ermis-channel-list__topic-sublist\">\n <ChannelRow\n channel={generalChannelProxy as any}\n isActive={activeChannel?.cid === channel.cid}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={GeneralTopicAvatarComponent || GeneralAvatar}\n currentUserId={currentUserId}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={() => null}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n />\n {topics.map((topicChannel: any) => (\n <ChannelRow\n key={topicChannel.cid}\n channel={topicChannel}\n isActive={activeChannel?.cid === topicChannel.cid}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={TopicAvatarComponent || TopicEmojiAvatar}\n currentUserId={currentUserId}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onEditTopic={onEditTopic}\n onToggleCloseTopic={onToggleCloseTopic}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n />\n ))}\n </div>\n )}\n </div>\n );\n});\nChannelTopicGroup.displayName = 'ChannelTopicGroup';\n\nexport const ChannelList: React.FC<ChannelListProps> = React.memo(({\n filters = { type: ['messaging', 'team', 'meeting'], include_pinned_messages: true } as unknown as ChannelFilters,\n sort = [],\n options = { message_limit: 25 } as unknown as ChannelListProps['options'],\n renderChannel,\n onChannelSelect,\n className,\n LoadingIndicator = DefaultLoading,\n EmptyStateIndicator = DefaultEmpty,\n AvatarComponent = Avatar,\n ChannelItemComponent = ChannelItem,\n pendingInvitesLabel,\n channelsLabel = 'Channels',\n pendingBadgeLabel,\n loadingLabel,\n emptyStateLabel = 'No channels found',\n blockedBadgeLabel = 'Blocked',\n ChannelTopicGroupComponent,\n GeneralTopicAvatarComponent,\n TopicAvatarComponent,\n generalTopicLabel = 'general',\n onAddTopic,\n TopicEmojiPickerComponent,\n closedTopicIcon,\n PinnedIconComponent = DefaultPinnedIcon,\n ChannelActionsComponent,\n onEditTopic,\n onToggleCloseTopic,\n hiddenActions,\n actionLabels,\n actionIcons,\n showOnlineStatus = true,\n}) => {\n const { client, activeChannel, setActiveChannel } = useChatClient();\n const [channels, setChannels] = useState<Channel[]>([]);\n const [loading, setLoading] = useState(true);\n const [isPendingExpanded, setIsPendingExpanded] = useState(true);\n const [addingTopicForChannel, setAddingTopicForChannel] = useState<Channel | null>(null);\n const [editingTopicForChannel, setEditingTopicForChannel] = useState<Channel | null>(null);\n\n const handleAddTopicClick = useCallback((channel: Channel) => {\n if (onAddTopic) {\n onAddTopic(channel);\n } else {\n setAddingTopicForChannel(channel);\n }\n }, [onAddTopic]);\n\n const handleEditTopicClick = useCallback((channel: Channel) => {\n if (onEditTopic) {\n onEditTopic(channel);\n } else {\n setEditingTopicForChannel(channel);\n }\n }, [onEditTopic]);\n\n const handleToggleCloseTopicClick = useCallback(async (channel: Channel, isClosed: boolean) => {\n if (onToggleCloseTopic) {\n onToggleCloseTopic(channel, isClosed);\n return;\n }\n\n const parentCid = channel.data?.parent_cid as string | undefined;\n if (!parentCid) return;\n\n const parentChannel = client.activeChannels[parentCid];\n if (!parentChannel) return;\n\n try {\n if (isClosed) {\n await parentChannel.reopenTopic(channel.cid);\n } else {\n await parentChannel.closeTopic(channel.cid);\n }\n } catch (err) {\n console.error('Failed to toggle topic close state', err);\n }\n }, [client.activeChannels, onToggleCloseTopic]);\n\n // Group channels into pending and regular\n const { pendingChannels, regularChannels } = useMemo<{ pendingChannels: Channel[], regularChannels: Channel[] }>(() => {\n const pending: Channel[] = [];\n const pinned: Channel[] = [];\n const regular: Channel[] = [];\n\n channels.forEach(ch => {\n const ms = ch.state?.membership as Record<string, unknown> | undefined;\n const isPending = isPendingMember(ms?.channel_role as string);\n const isSkipped = isSkippedMember(ms?.channel_role as string);\n \n if (isSkipped) {\n return; // Filter out completely\n }\n\n if (isPending) {\n pending.push(ch);\n } else if (ch.data?.is_pinned) {\n pinned.push(ch);\n } else {\n regular.push(ch);\n }\n });\n\n return { pendingChannels: pending, regularChannels: [...pinned, ...regular] };\n }, [channels]);\n\n const filtersKey = useMemo(() => JSON.stringify(filters), [filters]);\n\n const loadChannels = useCallback(async () => {\n try {\n setLoading(true);\n const result = await client.queryChannels(filters, sort, options as { message_limit?: number });\n setChannels(result);\n } catch (err) {\n console.error('Failed to load channels:', err);\n } finally {\n setLoading(false);\n }\n }, [client, filtersKey]);\n\n useEffect(() => {\n loadChannels();\n }, [loadChannels]);\n\n // Real-time: List manipulation (move to top, add, delete)\n useChannelListUpdates(channels, setChannels);\n\n // Online status: compute set of online friend user IDs (skip if disabled)\n const onlineUsers = useOnlineUsers(showOnlineStatus ? channels : []);\n\n // Helper: get the \"other\" user ID from a direct channel\n const getOtherUserId = useCallback((channel: Channel): string | undefined => {\n if (!isDirectChannel(channel) || !client.userID) return undefined;\n const members = channel.state?.members;\n if (!members) return undefined;\n for (const memberId of Object.keys(members)) {\n if (memberId !== client.userID) return memberId;\n }\n return undefined;\n }, [client.userID]);\n\n // Helper: compute isOnline for a channel (undefined for non-friend channels)\n const getIsOnline = useCallback((channel: Channel): boolean | undefined => {\n const otherUserId = getOtherUserId(channel);\n if (!otherUserId || !client.userID) return undefined;\n if (!isFriendChannel(channel, otherUserId, client.userID)) return undefined;\n return onlineUsers.has(otherUserId);\n }, [getOtherUserId, onlineUsers, client.userID]);\n\n const handleSelect = useCallback(\n (channel: Channel) => {\n setActiveChannel(channel);\n onChannelSelect?.(channel);\n\n // Mark as read when user selects a channel (skip if banned, blocked, or pending)\n const ms = channel.state?.membership as Record<string, unknown> | undefined;\n const chState = channel.state as unknown as Record<string, unknown> | undefined;\n const isBannedInChannel = Boolean(ms?.banned);\n const isBlockedInChannel = isDirectChannel(channel) && Boolean(ms?.blocked);\n const isPending = isPendingMember(ms?.channel_role as string);\n const isSkipped = isSkippedMember(ms?.channel_role as string);\n\n if (!isBannedInChannel && !isBlockedInChannel && !isPending && !isSkipped && (chState?.unreadCount as number) > 0) {\n channel.markRead().catch(() => { });\n // Optimistically reset unread to update UI immediately\n if (chState) chState.unreadCount = 0;\n setChannels((prev) => [...prev]);\n }\n },\n [setActiveChannel, onChannelSelect, setChannels],\n );\n\n if (loading) return <LoadingIndicator text={loadingLabel} />;\n if (channels.length === 0) return <EmptyStateIndicator text={emptyStateLabel} />;\n\n return (\n <div className={`ermis-channel-list${className ? ` ${className}` : ''}`}>\n {/* VList requires its container to have a height to work. */}\n <VList style={{ height: '100%' }}>\n {pendingChannels.length > 0 && (\n <div\n className=\"ermis-channel-list__accordion-header\"\n onClick={() => setIsPendingExpanded(prev => !prev)}\n >\n <span>\n {typeof pendingInvitesLabel === 'function'\n ? pendingInvitesLabel(pendingChannels.length)\n : pendingInvitesLabel || `Invites (${pendingChannels.length})`}\n </span>\n <svg\n className={`ermis-channel-list__accordion-icon ${isPendingExpanded ? 'ermis-channel-list__accordion-icon--expanded' : ''}`}\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n )}\n {isPendingExpanded && pendingChannels.map((channel: Channel) => {\n const isActive = activeChannel?.cid === channel.cid;\n return (\n <ChannelRow\n key={channel.cid}\n channel={channel}\n isActive={isActive}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n isOnline={getIsOnline(channel)}\n />\n );\n })}\n {pendingChannels.length > 0 && regularChannels.length > 0 && (\n <div className=\"ermis-channel-list__accordion-header ermis-channel-list__accordion-header--static\">\n <span>{channelsLabel}</span>\n </div>\n )}\n {regularChannels.map((channel: Channel) => {\n const isActive = activeChannel?.cid === channel.cid;\n const isTeamWithTopics = hasTopicsEnabled(channel);\n\n if (isTeamWithTopics) {\n const GroupComponent = ChannelTopicGroupComponent || ChannelTopicGroup;\n return (\n <GroupComponent\n key={channel.cid}\n channel={channel}\n activeChannel={activeChannel}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n GeneralTopicAvatarComponent={GeneralTopicAvatarComponent}\n TopicAvatarComponent={TopicAvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n generalTopicLabel={generalTopicLabel}\n onAddTopic={handleAddTopicClick}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onEditTopic={handleEditTopicClick}\n onToggleCloseTopic={handleToggleCloseTopicClick}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n />\n );\n }\n\n return (\n <ChannelRow\n key={channel.cid}\n channel={channel}\n isActive={isActive}\n handleSelect={handleSelect}\n renderChannel={renderChannel}\n ChannelItemComponent={ChannelItemComponent}\n AvatarComponent={AvatarComponent}\n currentUserId={client.userID}\n pendingBadgeLabel={pendingBadgeLabel}\n blockedBadgeLabel={blockedBadgeLabel}\n closedTopicIcon={closedTopicIcon}\n PinnedIconComponent={PinnedIconComponent}\n ChannelActionsComponent={ChannelActionsComponent}\n onAddTopic={handleAddTopicClick}\n onEditTopic={handleEditTopicClick}\n onToggleCloseTopic={handleToggleCloseTopicClick}\n hiddenActions={hiddenActions}\n actionLabels={actionLabels}\n actionIcons={actionIcons}\n isOnline={getIsOnline(channel)}\n />\n );\n })}\n </VList>\n {addingTopicForChannel && (\n <TopicModal\n isOpen={true}\n onClose={() => setAddingTopicForChannel(null)}\n parentChannel={addingTopicForChannel}\n EmojiPickerComponent={TopicEmojiPickerComponent}\n />\n )}\n {editingTopicForChannel && (\n <TopicModal\n isOpen={true}\n onClose={() => setEditingTopicForChannel(null)}\n topic={editingTopicForChannel}\n EmojiPickerComponent={TopicEmojiPickerComponent}\n />\n )}\n </div>\n );\n});\n\nChannelList.displayName = 'ChannelList'; 'ChannelList';\n","import React, { useState, useCallback } from 'react';\nimport type { CreateTopicData, EditTopicData } from '@ermis-network/ermis-chat-sdk';\nimport { Modal } from './Modal';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { TopicModalProps } from '../types';\n\nconst DEFAULT_TOPIC_ICONS = ['💬', '🔥', '🚀', '⭐', '💡', '🎉', '📌', '📁', '🎨', '💻', '📈', '🤝'];\n\nexport const TopicModal: React.FC<TopicModalProps> = React.memo(({\n isOpen,\n onClose,\n onSuccess,\n EmojiPickerComponent,\n parentChannel,\n topic,\n title = topic ? 'Edit Topic' : 'Create Topic',\n nameLabel = 'Topic Name',\n namePlaceholder = 'Enter topic name',\n emojiLabel = 'Topic icon',\n descriptionLabel = 'Description',\n descriptionPlaceholder = 'Enter topic description',\n cancelButtonLabel = 'Cancel',\n saveButtonLabel = topic ? 'Save' : 'Create',\n savingButtonLabel = topic ? 'Saving...' : 'Creating...',\n}) => {\n const { activeChannel, client } = useChatClient();\n \n const originalName = (topic?.data?.name as string) || '';\n const originalImage = (topic?.data?.image as string) || '';\n const originalEmoji = originalImage.startsWith('emoji://') ? originalImage.replace('emoji://', '') : '';\n const originalDescription = (topic?.data?.description as string) || '';\n\n const [name, setName] = useState(originalName);\n const [emoji, setEmoji] = useState(originalEmoji);\n const [description, setDescription] = useState(originalDescription);\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const targetParent = parentChannel || activeChannel;\n\n const handleSave = useCallback(async () => {\n if (!name.trim() || !emoji) return;\n\n // Resolve parent channel (owner of topics)\n let editorParent = targetParent;\n if (topic && topic.data?.parent_cid) {\n editorParent = client.activeChannels[topic.data.parent_cid as string] || editorParent;\n }\n \n if (!editorParent && !topic) return;\n\n setIsSaving(true);\n setError(null);\n\n try {\n if (topic) {\n if (!editorParent) throw new Error(\"Parent channel not found\");\n \n const payload: EditTopicData = {};\n if (name.trim() !== originalName) payload.name = name.trim();\n if (emoji !== originalEmoji) payload.image = emoji ? `emoji://${emoji}` : '';\n if (description.trim() !== originalDescription) payload.description = description.trim();\n\n if (Object.keys(payload).length > 0 && topic.cid) {\n await editorParent.editTopic(topic.cid, payload);\n }\n\n if (onSuccess) {\n onSuccess(topic);\n } else {\n onClose();\n }\n } else {\n if (!editorParent) return;\n const payload: CreateTopicData = {\n name: name.trim(),\n };\n\n if (emoji) {\n payload.image = `emoji://${emoji}`;\n }\n if (description.trim()) {\n payload.description = description.trim();\n }\n\n await editorParent.createTopic(payload);\n\n if (onSuccess) {\n onSuccess(editorParent);\n } else {\n onClose();\n setName('');\n setEmoji('');\n setDescription('');\n }\n }\n } catch (err: any) {\n setError(err?.message || (topic ? 'Failed to save topic' : 'Failed to create topic'));\n } finally {\n setIsSaving(false);\n }\n }, [targetParent, topic, name, emoji, description, originalName, originalEmoji, originalDescription, onSuccess, onClose, client.activeChannels]);\n\n const isValid = name.trim().length > 0 && emoji.length > 0;\n\n const footer = (\n <div className=\"ermis-create-topic__footer\">\n <button className=\"ermis-create-topic__btn ermis-create-topic__btn--cancel\" onClick={onClose} disabled={isSaving}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-topic__btn ermis-create-topic__btn--create\" onClick={handleSave} disabled={isSaving || !isValid}>\n {isSaving ? savingButtonLabel : saveButtonLabel}\n </button>\n </div>\n );\n\n return (\n <Modal isOpen={isOpen} onClose={isSaving ? () => { } : onClose} title={title} maxWidth=\"400px\" footer={footer}>\n <div className=\"ermis-create-topic__body\">\n <div className=\"ermis-create-topic__live-preview\">\n <span className=\"ermis-create-topic__live-preview-emoji\">{emoji || <span style={{opacity: 0.3}}>#</span>}</span>\n <span className=\"ermis-create-topic__live-preview-name\">{name || namePlaceholder}</span>\n </div>\n\n <div className=\"ermis-create-topic__field\">\n <label className=\"ermis-create-topic__label\">{nameLabel} <span className=\"ermis-create-topic__required\">*</span></label>\n <input\n className=\"ermis-create-topic__input\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={namePlaceholder}\n disabled={isSaving}\n maxLength={100}\n autoFocus\n />\n </div>\n\n <div className=\"ermis-create-topic__field\">\n <label className=\"ermis-create-topic__label\">{emojiLabel} <span className=\"ermis-create-topic__required\">*</span></label>\n\n <div className=\"ermis-create-topic__emoji-picker\">\n {EmojiPickerComponent ? (\n <EmojiPickerComponent onSelect={(e: any) => setEmoji(e.native || e.emoji || e.id || e)} />\n ) : (\n <div className=\"ermis-create-topic__default-icons\">\n {DEFAULT_TOPIC_ICONS.map(icon => (\n <button\n key={icon}\n type=\"button\"\n className={`ermis-create-topic__default-icon ${icon === emoji ? 'ermis-create-topic__default-icon--active' : ''}`}\n onClick={() => setEmoji(icon)}\n disabled={isSaving}\n >\n {icon}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n <div className=\"ermis-create-topic__field\">\n <label className=\"ermis-create-topic__label\">{descriptionLabel}</label>\n <textarea\n className=\"ermis-create-topic__input\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={descriptionPlaceholder}\n disabled={isSaving}\n rows={3}\n maxLength={500}\n style={{ resize: 'vertical' }}\n />\n </div>\n\n {error && (\n <div className=\"ermis-create-topic__error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n </div>\n </Modal>\n );\n});\n\nTopicModal.displayName = 'TopicModal';\n","import React, { useState, useCallback, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport type { ChannelAction, ChannelActionLabels, ChannelActionIcons, ChannelActionsProps } from '../types';\nimport { Dropdown } from './Dropdown';\nimport { isDirectChannel, isGroupChannel, isTopicChannel } from '../channelTypeUtils';\nimport { canManageChannel, CHANNEL_ROLES } from '../channelRoleUtils';\n\n/* ----------------------------------------------------------\n SVG Icons for default actions\n ---------------------------------------------------------- */\nconst PinIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4\" /><path d=\"M9 15l-4.5 4.5\" /><path d=\"M14.5 4l5.5 5.5\" /></svg>);\nconst UnpinIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4\" /><path d=\"M9 15l-4.5 4.5\" /><path d=\"M14.5 4l5.5 5.5\" /><line x1=\"3\" y1=\"3\" x2=\"21\" y2=\"21\" /></svg>);\nconst BlockIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\" /><line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" /></svg>);\nconst LeaveIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" /><polyline points=\"16 17 21 12 16 7\" /><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\" /></svg>);\nconst TrashIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><polyline points=\"3 6 5 6 21 6\" /><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" /></svg>);\nconst LockIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 10 0v4\" /></svg>);\nconst UnlockIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 9.9-1\" /></svg>);\nconst CreateTopicIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" /><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" /></svg>);\nconst EditIcon = () => (<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" /><path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" /></svg>);\nconst MoreIcon = () => (<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"1\" /><circle cx=\"19\" cy=\"12\" r=\"1\" /><circle cx=\"5\" cy=\"12\" r=\"1\" /></svg>);\n\n/* ----------------------------------------------------------\n computeDefaultActions\n Derives a list of ChannelAction[] based on channel type\n and the current user's role. Currently actions only log\n to console — real API calls will be wired later.\n ---------------------------------------------------------- */\nexport function computeDefaultActions(\n channel: Channel,\n currentUserId?: string,\n options?: {\n onAddTopic?: (channel: Channel) => void;\n onEditTopic?: (channel: Channel) => void;\n onToggleCloseTopic?: (channel: Channel, isClosed: boolean) => void;\n isBlocked?: boolean;\n actionLabels?: ChannelActionLabels;\n actionIcons?: ChannelActionIcons;\n },\n): ChannelAction[] {\n const actions: ChannelAction[] = [];\n if (!currentUserId) return actions;\n\n const isDirect = isDirectChannel(channel);\n const isTeamOrMeeting = isGroupChannel(channel);\n const isTopic = isTopicChannel(channel);\n const isClosed = channel.data?.is_closed_topic === true;\n\n const ms = channel.state?.members?.[currentUserId] || channel.state?.membership;\n const role = ms?.channel_role;\n const isBlocked = options?.isBlocked !== undefined ? options.isBlocked : (ms as any)?.blocked;\n const isPinned = channel.data?.is_pinned === true;\n\n // Pin / Unpin — available for all channel types\n const actionLabels = options?.actionLabels;\n\n const pinLabel = isPinned\n ? (isTopic ? (actionLabels?.unpinTopic || 'Unpin topic') : (actionLabels?.unpinChannel || 'Unpin channel'))\n : (isTopic ? (actionLabels?.pinTopic || 'Pin topic') : (actionLabels?.pinChannel || 'Pin channel'));\n\n const actionIcons = options?.actionIcons;\n\n const pinIcon = isPinned\n ? (actionIcons?.UnpinIcon || <UnpinIcon />)\n : (actionIcons?.PinIcon || <PinIcon />);\n\n actions.push({\n id: isPinned ? 'unpin' : 'pin',\n label: pinLabel,\n icon: pinIcon,\n onClick: async (ch) => {\n try {\n if (isPinned) {\n await ch.unpin();\n } else {\n await ch.pin();\n }\n } catch (e) {\n console.error('Error toggling pin state', e);\n }\n },\n });\n\n if (isDirect) {\n // Direct channel: Block / Unblock\n actions.push({\n id: isBlocked ? 'unblock' : 'block',\n label: isBlocked ? (actionLabels?.unblockUser || 'Unblock user') : (actionLabels?.blockUser || 'Block user'),\n icon: isBlocked ? (actionIcons?.UnblockIcon || <BlockIcon />) : (actionIcons?.BlockIcon || <BlockIcon />),\n isDanger: !isBlocked,\n onClick: async (ch) => {\n try {\n if (isBlocked) {\n await ch.unblockUser();\n } else {\n await ch.blockUser();\n }\n } catch (e) {\n console.error('Error toggling block state', e);\n }\n },\n });\n } else if (isTopic) {\n // Topic: Edit topic (owner & moder only)\n if (canManageChannel(role)) {\n actions.push({\n id: 'edit_topic',\n label: actionLabels?.editTopic || 'Edit topic',\n icon: actionIcons?.EditTopicIcon || <EditIcon />,\n onClick: (ch) => {\n options?.onEditTopic?.(ch);\n },\n });\n }\n // Topic: Close / Reopen (owner & moder only)\n if (canManageChannel(role)) {\n actions.push({\n id: isClosed ? 'reopen' : 'close',\n label: isClosed ? (actionLabels?.reopenTopic || 'Reopen topic') : (actionLabels?.closeTopic || 'Close topic'),\n icon: isClosed ? (actionIcons?.ReopenTopicIcon || <UnlockIcon />) : (actionIcons?.CloseTopicIcon || <LockIcon />),\n isDanger: !isClosed,\n onClick: (ch) => {\n options?.onToggleCloseTopic?.(ch, isClosed);\n },\n });\n }\n } else if (isTeamOrMeeting) {\n // Team channel: Create Topic (owner & moder, only if topics enabled)\n const hasTopicsEnabled = Boolean(channel.data?.topics_enabled);\n if (hasTopicsEnabled && canManageChannel(role) && options?.onAddTopic) {\n actions.push({\n id: 'create_topic',\n label: actionLabels?.createTopic || 'Create topic',\n icon: actionIcons?.CreateTopicIcon || <CreateTopicIcon />,\n onClick: (ch) => { options.onAddTopic!(ch); },\n });\n }\n if (role === CHANNEL_ROLES.OWNER) {\n actions.push({\n id: 'delete',\n label: actionLabels?.deleteChannel || 'Delete channel',\n icon: actionIcons?.DeleteChannelIcon || <TrashIcon />,\n isDanger: true,\n onClick: async (ch) => {\n try {\n await ch.delete();\n } catch (e) {\n console.error('Error deleting channel', e);\n }\n },\n });\n }\n if (role === CHANNEL_ROLES.MODERATOR || role === CHANNEL_ROLES.MEMBER) {\n actions.push({\n id: 'leave',\n label: actionLabels?.leaveChannel || 'Leave channel',\n icon: actionIcons?.LeaveChannelIcon || <LeaveIcon />,\n isDanger: true,\n onClick: async (ch) => {\n try {\n await ch.removeMembers([currentUserId]);\n } catch (e) {\n console.error('Error leaving channel', e);\n }\n },\n });\n }\n }\n\n return actions;\n}\n\n/* ----------------------------------------------------------\n DefaultChannelActions\n The default UI component that renders the \"more\" trigger\n button and the dropdown menu. Consumer can fully replace\n this via ChannelActionsComponent prop.\n ---------------------------------------------------------- */\nexport const DefaultChannelActions: React.FC<ChannelActionsProps> = React.memo(({ channel, actions, onClose }) => {\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n\n const handleActionsClick = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation();\n setAnchorRect(e.currentTarget.getBoundingClientRect());\n setDropdownOpen(true);\n }, []);\n\n const handleClose = useCallback(() => {\n setDropdownOpen(false);\n setAnchorRect(null);\n onClose();\n }, [onClose]);\n\n if (!actions || actions.length === 0) return null;\n\n return (\n <>\n <button\n type=\"button\"\n className={`ermis-channel-list__actions-trigger ${dropdownOpen ? 'ermis-channel-list__actions-trigger--active' : ''}`}\n onClick={handleActionsClick}\n title=\"More actions\"\n >\n <MoreIcon />\n </button>\n <Dropdown\n isOpen={dropdownOpen}\n anchorRect={anchorRect}\n onClose={handleClose}\n align=\"right\"\n >\n <div className=\"ermis-dropdown__menu\">\n {actions.map((action) => (\n <button\n key={action.id}\n className={`ermis-dropdown__item ${action.isDanger ? 'ermis-dropdown__item--danger' : ''}`}\n onClick={(e) => {\n e.stopPropagation();\n handleClose();\n action.onClick(channel, e);\n }}\n >\n {action.icon}\n <span>{action.label}</span>\n </button>\n ))}\n </div>\n </Dropdown>\n </>\n );\n});\n\nDefaultChannelActions.displayName = 'DefaultChannelActions';\n","import React, { useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\n\n// Global event name used to close any other open dropdowns\nconst CLOSE_ALL_EVENT = 'ermis:close-all-dropdowns';\n\n/** Dispatch a global event to close all open dropdowns */\nexport const closeAllDropdowns = () => {\n document.dispatchEvent(new CustomEvent(CLOSE_ALL_EVENT));\n};\n\nexport interface DropdownProps {\n /** Whether the dropdown is open */\n isOpen: boolean;\n /** Rect from getBoundingClientRect() of the anchor element */\n anchorRect: DOMRect | null;\n /** Callback when dropdown requests to close (e.g., click outside, scroll, Escape) */\n onClose: () => void;\n /** Dropdown menu content */\n children: React.ReactNode;\n /** Horizontal alignment relative to the anchor. Default: 'left' */\n align?: 'left' | 'right';\n /** Optional custom CSS class for the container */\n className?: string;\n /** Optional custom CSS style for the container */\n style?: React.CSSProperties;\n}\n\nexport const Dropdown: React.FC<DropdownProps> = ({\n isOpen,\n anchorRect,\n onClose,\n children,\n align = 'left',\n className = '',\n style: propStyle = {},\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const instanceId = useRef(Math.random().toString(36).slice(2));\n\n // Listen for global close event — only register when open to avoid N listeners\n useEffect(() => {\n if (!isOpen) return;\n\n // Broadcast: close all OTHER open dropdowns\n document.dispatchEvent(new CustomEvent(CLOSE_ALL_EVENT, { detail: instanceId.current }));\n\n const handleGlobalClose = (e: Event) => {\n const detail = (e as CustomEvent).detail;\n if (!detail || detail !== instanceId.current) {\n onClose();\n }\n };\n\n const handleClickOutside = (e: MouseEvent) => {\n // Allow the click to process if it's on a trigger button so it can toggle itself\n // We rely on the trigger stopping propagation or using the global close event.\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n\n const handleScroll = () => onClose();\n\n // Delay click listener to prevent instant close from the opening click\n const tid = setTimeout(() => {\n document.addEventListener('click', handleClickOutside);\n }, 10);\n\n document.addEventListener(CLOSE_ALL_EVENT, handleGlobalClose);\n document.addEventListener('keydown', handleKeyDown);\n document.addEventListener('scroll', handleScroll, true);\n\n return () => {\n clearTimeout(tid);\n document.removeEventListener(CLOSE_ALL_EVENT, handleGlobalClose);\n document.removeEventListener('click', handleClickOutside);\n document.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('scroll', handleScroll, true);\n };\n }, [isOpen, onClose]);\n\n if (!isOpen || !anchorRect) return null;\n\n const spaceBelow = window.innerHeight - anchorRect.bottom;\n const spaceAbove = anchorRect.top;\n const estimatedDropdownHeight = 250;\n\n let verticalStyle: React.CSSProperties = {};\n if (spaceBelow < estimatedDropdownHeight && spaceAbove > spaceBelow) {\n // Open upwards (bottom-aligned to the top of the trigger)\n verticalStyle = { bottom: window.innerHeight - anchorRect.top + 4 };\n } else {\n // Open downwards\n verticalStyle = { top: anchorRect.bottom + 4 };\n }\n\n const style: React.CSSProperties = {\n position: 'fixed',\n zIndex: 99999,\n ...verticalStyle,\n ...(align === 'right'\n ? { right: window.innerWidth - anchorRect.right }\n : { left: anchorRect.left }),\n ...propStyle\n };\n\n const portalTarget = document.querySelector('.ermis-chat') || document.body;\n\n return createPortal(\n <div ref={containerRef} className={`ermis-dropdown ${className}`.trim()} style={style}>\n {children}\n </div>,\n portalTarget\n );\n};\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { ForwardMessageModal } from './ForwardMessageModal';\nimport type { ChannelProps } from '../types';\n\nexport type { ChannelProps } from '../types';\n\nconst DefaultEmpty = React.memo(() => (\n <div className=\"ermis-channel__empty\">Select a channel to start chatting</div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\n/**\n * Channel wrapper component.\n *\n * Customization:\n * - `HeaderComponent` — replace default ChannelHeader with a fully custom component.\n * Receives `{ channel, name, image }` as props.\n * - `EmptyStateIndicator` — custom component when no channel is selected.\n */\nexport const Channel: React.FC<ChannelProps> = React.memo(({\n children,\n className,\n EmptyStateIndicator = DefaultEmpty,\n HeaderComponent,\n ForwardMessageModalComponent = ForwardMessageModal,\n}) => {\n const { activeChannel, client, forwardingMessage, setForwardingMessage } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n\n // Force re-render when channel info is updated via WS\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n useEffect(() => {\n\n console.log('---activeChannel--', activeChannel)\n\n if (!activeChannel) return;\n const sub = activeChannel.on('channel.updated', () => setChannelUpdateCount((c) => c + 1));\n return () => sub.unsubscribe();\n }, [activeChannel]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const headerData = useMemo(() => {\n if (!activeChannel || !HeaderComponent) return null;\n return {\n channel: activeChannel,\n name: (activeChannel.data?.name || activeChannel.cid || '') as string,\n image: activeChannel.data?.image as string | undefined,\n };\n }, [activeChannel, HeaderComponent, channelUpdateCount]);\n\n if (!activeChannel) {\n return <EmptyStateIndicator />;\n }\n\n const bannedClass = isBanned ? ' ermis-channel--banned' : '';\n const blockedClass = isBlocked ? ' ermis-channel--blocked' : '';\n\n return (\n <div className={`ermis-channel${bannedClass}${blockedClass}${className ? ` ${className}` : ''}`}>\n {HeaderComponent && headerData && <HeaderComponent {...headerData} />}\n {children}\n {forwardingMessage && (\n <ForwardMessageModalComponent\n message={forwardingMessage}\n onDismiss={() => setForwardingMessage(null)}\n />\n )}\n </div>\n );\n});\n\nChannel.displayName = 'Channel';\n\n","import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { createForwardMessagePayload } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { Modal } from './Modal';\nimport type { ForwardMessageModalProps, ForwardChannelItemProps, AvatarProps } from '../types';\nimport { isTopicChannel } from '../channelTypeUtils';\n\nexport type { ForwardMessageModalProps, ForwardChannelItemProps } from '../types';\n\n/* ----------------------------------------------------------\n Default channel item row with checkbox\n ---------------------------------------------------------- */\nconst DefaultForwardChannelItem: React.FC<ForwardChannelItemProps> = React.memo(({\n channel,\n selected,\n onToggle,\n AvatarComponent,\n}) => {\n const name = (channel.data?.name || channel.cid) as string;\n const rawImage = channel.data?.image as string | undefined;\n // Parse emoji:// format → extract just the emoji for avatar fallback\n const isEmoji = rawImage?.startsWith('emoji://');\n const image = isEmoji ? undefined : rawImage;\n const emojiIcon = isEmoji ? rawImage!.replace('emoji://', '') : undefined;\n\n return (\n <div\n className={`ermis-forward-modal__channel-item ${selected ? 'ermis-forward-modal__channel-item--selected' : ''}`}\n onClick={() => onToggle(channel)}\n >\n {emojiIcon ? (\n <span className=\"ermis-forward-modal__channel-emoji\" style={{ fontSize: 24, width: 36, textAlign: 'center' }}>{emojiIcon}</span>\n ) : (\n <AvatarComponent image={image} name={name} size={36} />\n )}\n <span className=\"ermis-forward-modal__channel-name\">{name}</span>\n <div className={`ermis-forward-modal__checkbox ${selected ? 'ermis-forward-modal__checkbox--checked' : ''}`}>\n {selected && (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n )}\n </div>\n </div>\n );\n});\nDefaultForwardChannelItem.displayName = 'DefaultForwardChannelItem';\n\n/* ----------------------------------------------------------\n ForwardMessageModal\n ---------------------------------------------------------- */\nexport const ForwardMessageModal: React.FC<ForwardMessageModalProps> = ({\n message,\n onDismiss,\n ChannelItemComponent = DefaultForwardChannelItem,\n SearchInputComponent,\n}) => {\n const { client, activeChannel } = useChatClient();\n const [selectedChannels, setSelectedChannels] = useState<Set<string>>(new Set());\n const [search, setSearch] = useState('');\n const [sending, setSending] = useState(false);\n const [results, setResults] = useState<{ success: string[]; failed: string[] } | null>(null);\n const backdropRef = useRef<HTMLDivElement>(null);\n\n /* ---------- Get channels from client state (exclude topics) ---------- */\n const channels = useMemo(() => {\n return (Object.values(client.activeChannels) as Channel[]).filter(\n (ch) => !isTopicChannel(ch),\n );\n }, [client.activeChannels]);\n\n /* ---------- Filter by search ---------- */\n const filteredChannels = useMemo(() => {\n if (!search.trim()) return channels;\n const q = search.toLowerCase();\n return channels.filter((ch) => {\n const name = ((ch.data?.name || ch.cid) as string).toLowerCase();\n return name.includes(q);\n });\n }, [channels, search]);\n\n /* ---------- Toggle selection ---------- */\n const toggleChannel = useCallback((channel: Channel) => {\n setSelectedChannels((prev) => {\n const next = new Set(prev);\n if (next.has(channel.cid)) {\n next.delete(channel.cid);\n } else {\n next.add(channel.cid);\n }\n return next;\n });\n }, []);\n\n /* ---------- Send forward ---------- */\n const handleSend = useCallback(async () => {\n if (!activeChannel || selectedChannels.size === 0 || sending) return;\n setSending(true);\n const success: string[] = [];\n const failed: string[] = [];\n\n for (const cid of selectedChannels) {\n const targetChannel = channels.find((c) => c.cid === cid);\n if (!targetChannel) continue;\n try {\n const forwardPayload = createForwardMessagePayload(\n message,\n targetChannel.cid as string,\n activeChannel.cid as string,\n );\n\n await activeChannel.forwardMessage(forwardPayload, {\n type: targetChannel.type,\n channelID: targetChannel.id!,\n });\n success.push((targetChannel.data?.name || targetChannel.cid) as string);\n } catch (err) {\n console.error(`Failed to forward to ${cid}`, err);\n failed.push((targetChannel.data?.name || targetChannel.cid) as string);\n }\n }\n\n setResults({ success, failed });\n setSending(false);\n\n // Auto-close after success (short delay)\n if (failed.length === 0) {\n setTimeout(() => onDismiss(), 1200);\n }\n }, [activeChannel, selectedChannels, channels, message, sending, onDismiss]);\n\n /* ---------- Keyboard / backdrop close ---------- */\n useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onDismiss();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [onDismiss]);\n\n const handleBackdropClick = useCallback((e: React.MouseEvent) => {\n if (e.target === backdropRef.current) onDismiss();\n }, [onDismiss]);\n\n /* ---------- Message preview ---------- */\n const previewText = message.text\n ? (message.text.length > 120 ? message.text.slice(0, 120) + '…' : message.text)\n : '';\n const attachmentCount = message.attachments?.length ?? 0;\n\n const footer = (\n <>\n <button className=\"ermis-forward-modal__btn ermis-forward-modal__btn--cancel\" onClick={onDismiss}>\n Cancel\n </button>\n <button\n className=\"ermis-forward-modal__btn ermis-forward-modal__btn--send\"\n onClick={handleSend}\n disabled={selectedChannels.size === 0 || sending || results !== null}\n >\n {sending ? 'Sending…' : `Forward${selectedChannels.size > 0 ? ` (${selectedChannels.size})` : ''}`}\n </button>\n </>\n );\n\n return (\n <Modal isOpen onClose={onDismiss} title=\"Forward Message\" footer={footer}>\n {/* Message preview */}\n <div className=\"ermis-forward-modal__preview\">\n <div className=\"ermis-forward-modal__preview-sender\">\n {message.user?.name || message.user_id || 'Unknown'}\n </div>\n {previewText && (\n <div className=\"ermis-forward-modal__preview-text\">{previewText}</div>\n )}\n {attachmentCount > 0 && (\n <div className=\"ermis-forward-modal__preview-attachments\">\n 📎 {attachmentCount} attachment{attachmentCount > 1 ? 's' : ''}\n </div>\n )}\n </div>\n\n {/* Search */}\n <div className=\"ermis-forward-modal__search-wrapper\">\n {SearchInputComponent ? (\n <SearchInputComponent value={search} onChange={setSearch} />\n ) : (\n <input\n className=\"ermis-forward-modal__search\"\n type=\"text\"\n placeholder=\"Search channels…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n autoFocus\n />\n )}\n </div>\n\n {/* Channel list */}\n <div className=\"ermis-forward-modal__channel-list\">\n {filteredChannels.length === 0 ? (\n <div className=\"ermis-forward-modal__empty\">No channels found</div>\n ) : (\n filteredChannels.map((ch) => (\n <ChannelItemComponent\n key={ch.cid}\n channel={ch}\n selected={selectedChannels.has(ch.cid)}\n onToggle={toggleChannel}\n AvatarComponent={Avatar}\n />\n ))\n )}\n </div>\n\n {/* Results feedback */}\n {results && (\n <div className=\"ermis-forward-modal__results\">\n {results.success.length > 0 && (\n <div className=\"ermis-forward-modal__results-success\">\n ✓ Sent to {results.success.join(', ')}\n </div>\n )}\n {results.failed.length > 0 && (\n <div className=\"ermis-forward-modal__results-failed\">\n ✗ Failed: {results.failed.join(', ')}\n </div>\n )}\n </div>\n )}\n </Modal>\n );\n};\n","import React, { useMemo, useState, useEffect, useContext } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { Avatar } from './Avatar';\nimport type { ChannelHeaderProps } from '../types';\nimport type { OnlineStatus } from '../hooks/useOnlineStatus';\nimport { ErmisCallContext } from '../context/ErmisCallContext';\nimport { hasTopicsEnabled, isDirectChannel } from '../channelTypeUtils';\nimport { isSkippedMember, isFriendChannel } from '../channelRoleUtils';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\n\nexport type { ChannelHeaderProps } from '../types';\n\n/**\n * ChannelHeader displays the active channel's avatar and name.\n *\n * Customization:\n * - `title` / `image` — override the channel name and avatar\n * - `subtitle` — add a subtitle line (e.g. member count)\n * - `AvatarComponent` — replace the avatar\n * - `renderTitle(channel)` — fully custom title rendering\n * - `renderRight(channel)` — render content on the right side\n * - `showOnlineStatus` — show online/offline dot for friend channels (default: true)\n * - `OnlineIndicatorComponent` — replace the default indicator\n *\n * For a fully custom header, use `Channel`'s `HeaderComponent` prop instead.\n */\nexport const ChannelHeader: React.FC<ChannelHeaderProps> = React.memo(({\n className,\n AvatarComponent = Avatar,\n title,\n image,\n subtitle,\n renderRight,\n renderTitle,\n renderAudioCallButton,\n renderVideoCallButton,\n audioCallTitle = 'Audio Call',\n videoCallTitle = 'Video Call',\n CallBadgeComponent,\n showOnlineStatus = true,\n onlineLabel = 'Online',\n offlineLabel = 'Offline',\n OnlineIndicatorComponent,\n}) => {\n const { activeChannel, client, enableCall } = useChatClient();\n const { isPending } = usePendingState(activeChannel, client.userID);\n const callContext = useContext(ErmisCallContext);\n\n const isSkipped = client.userID \n ? isSkippedMember(activeChannel?.state?.members?.[client.userID]?.channel_role as string) || \n isSkippedMember(activeChannel?.state?.membership?.channel_role as string)\n : false;\n\n const actionDisabled = isPending || isSkipped;\n\n // Force re-render when channel.updated WS event fires\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!activeChannel) return;\n const sub = activeChannel.on('channel.updated', () => setChannelUpdateCount(c => c + 1));\n return () => sub.unsubscribe();\n }, [activeChannel]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const channelName = useMemo(() =>\n title || activeChannel?.data?.name || activeChannel?.cid || '',\n [title, activeChannel?.data?.name, activeChannel?.cid, channelUpdateCount],\n );\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const channelImage = useMemo(() =>\n image || (activeChannel?.data?.image as string | undefined),\n [image, activeChannel?.data?.image, channelUpdateCount],\n );\n\n const teamName = useMemo(() => {\n if (!activeChannel) return undefined;\n \n // If it's a topic, derive from parent_cid\n const parentCid = activeChannel.data?.parent_cid as string | undefined;\n if (parentCid && client.activeChannels[parentCid]) {\n return client.activeChannels[parentCid].data?.name || client.activeChannels[parentCid].cid;\n }\n\n // If it's a topics-enabled team channel (the general proxy), the proxy overrides data.name.\n // We can pull the original name from the SDK cache.\n if (hasTopicsEnabled(activeChannel)) {\n const rawChannel = client.activeChannels[activeChannel.cid];\n if (rawChannel && rawChannel.data?.name && rawChannel.data.name !== activeChannel.data?.name) {\n return rawChannel.data.name;\n }\n }\n \n return undefined;\n }, [activeChannel, client.activeChannels]);\n\n // ── Online Status (direct friend channels only) ──\n const currentUserId = client.userID;\n\n // Get the \"other\" user's ID from the direct channel.\n const otherUserId = useMemo(() => {\n if (!activeChannel || !currentUserId || !isDirectChannel(activeChannel)) return undefined;\n const members = activeChannel.state?.members;\n if (!members) return undefined;\n for (const memberId of Object.keys(members)) {\n if (memberId !== currentUserId) return memberId;\n }\n return undefined;\n }, [activeChannel, currentUserId]);\n\n // Check if this is a friend channel (both members are owner).\n const isFriend = useMemo(() => {\n if (!otherUserId || !currentUserId || !activeChannel) return false;\n return isFriendChannel(activeChannel, otherUserId, currentUserId);\n }, [activeChannel, otherUserId, currentUserId]);\n\n // Derive online status from watchers + subscribe to realtime events.\n const [onlineStatus, setOnlineStatus] = useState<OnlineStatus>('unknown');\n\n useEffect(() => {\n if (!showOnlineStatus || !isFriend || !otherUserId || !activeChannel) {\n setOnlineStatus('unknown');\n return;\n }\n\n // Read initial state from watchers.\n setOnlineStatus(activeChannel.state?.watchers?.[otherUserId] ? 'online' : 'offline');\n\n const handleWatchingStart = (event: Event) => {\n if (event.user?.id === otherUserId) {\n setOnlineStatus('online');\n }\n };\n\n const handleWatchingStop = (event: Event) => {\n if (event.user?.id === otherUserId) {\n setOnlineStatus('offline');\n }\n };\n\n const sub1 = activeChannel.on('user.watching.start', handleWatchingStart);\n const sub2 = activeChannel.on('user.watching.stop', handleWatchingStop);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n };\n }, [activeChannel, otherUserId, isFriend, showOnlineStatus]);\n\n const showOnlineDot = showOnlineStatus && onlineStatus !== 'unknown';\n const isOnline = onlineStatus === 'online';\n\n if (!activeChannel) return null;\n\n return (\n <div className={`ermis-channel-header${className ? ` ${className}` : ''}`}>\n {activeChannel.data?.parent_cid ? (\n <div className=\"ermis-channel-header__topic-avatar\">\n {channelImage && typeof channelImage === 'string' && channelImage.startsWith('emoji://') \n ? channelImage.replace('emoji://', '') \n : '#'}\n </div>\n ) : (\n <AvatarComponent image={channelImage} name={teamName || channelName} size={32} />\n )}\n\n <div className=\"ermis-channel-header__info\">\n {renderTitle ? (\n renderTitle(activeChannel)\n ) : (\n <div className=\"ermis-channel-header__title-container\">\n {teamName && (\n <div className=\"ermis-channel-header__team-name\">\n {teamName}\n </div>\n )}\n <div className=\"ermis-channel-header__name\">{channelName}</div>\n </div>\n )}\n {/* Online/Offline indicator for friend direct channels */}\n {showOnlineDot && (\n OnlineIndicatorComponent ? (\n <OnlineIndicatorComponent isOnline={isOnline} />\n ) : (\n <div className={`ermis-channel-header__online-status ermis-channel-header__online-status--${isOnline ? 'online' : 'offline'}`}>\n <span className={`ermis-channel-header__online-dot ermis-channel-header__online-dot--${isOnline ? 'online' : 'offline'}`} />\n <span className=\"ermis-channel-header__online-label\">\n {isOnline ? onlineLabel : offlineLabel}\n </span>\n </div>\n )\n )}\n {/* Consumer-provided subtitle (takes over if set) */}\n {subtitle && !showOnlineDot && (\n <div className=\"ermis-channel-header__subtitle\">{subtitle}</div>\n )}\n </div>\n\n {/* renderRight exposes actionDisabled for consumers to disable UI features natively */}\n <div className=\"ermis-channel-header__actions\">\n {enableCall && callContext && isDirectChannel(activeChannel) && !isPending && !isSkipped && (\n <>\n {renderAudioCallButton ? (\n renderAudioCallButton(() => callContext.createCall('audio', activeChannel.cid || ''), actionDisabled)\n ) : (\n <button\n className=\"ermis-btn ermis-btn--icon\"\n disabled={actionDisabled}\n onClick={() => callContext.createCall('audio', activeChannel.cid || '')}\n title={audioCallTitle}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"></path>\n </svg>\n </button>\n )}\n \n {renderVideoCallButton ? (\n renderVideoCallButton(() => callContext.createCall('video', activeChannel.cid || ''), actionDisabled)\n ) : (\n <button\n className=\"ermis-btn ermis-btn--icon\"\n disabled={actionDisabled}\n onClick={() => callContext.createCall('video', activeChannel.cid || '')}\n title={videoCallTitle}\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\"></polygon>\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\"></rect>\n </svg>\n </button>\n )}\n </>\n )}\n {/* C8: Active call badge */}\n {enableCall && callContext && callContext.callStatus && CallBadgeComponent && (\n <CallBadgeComponent callType={callContext.callType} />\n )}\n {renderRight && renderRight(activeChannel, actionDisabled)}\n </div>\n </div>\n );\n});\n\nChannelHeader.displayName = 'ChannelHeader';\n","import React, { useState, useRef, useCallback, useMemo, useEffect } from 'react';\nimport { VList, type VListHandle } from 'virtua';\nimport type { MessageLabel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { useLoadMessages } from '../hooks/useLoadMessages';\nimport { useScrollToMessage } from '../hooks/useScrollToMessage';\nimport { useChannelMessages } from '../hooks/useChannelMessages';\nimport { useChannelProfile } from '../hooks/useChannelData';\nimport { Avatar } from './Avatar';\nimport { MessageItem } from './MessageItem';\nimport { SystemMessageItem } from './MessageItem';\nimport { isPublicGroupChannel, isDirectChannel } from '../channelTypeUtils';\nimport { canManageChannel, isSkippedMember, isPendingMember } from '../channelRoleUtils';\nimport {\n defaultMessageRenderers,\n type MessageBubbleProps,\n} from './MessageRenderers';\nimport { getDateKey, formatDateLabel, getMessageUserId, formatReadTimestamp } from '../utils';\nimport { QuotedMessagePreview } from './QuotedMessagePreview';\nimport { PinnedMessages } from './PinnedMessages';\nimport { ReadReceipts } from './ReadReceipts';\nimport { TypingIndicator } from './TypingIndicator';\nimport { PendingOverlay } from './PendingOverlay';\nimport { SkippedOverlay } from './SkippedOverlay';\nimport { BannedOverlay } from './BannedOverlay';\nimport { ClosedTopicOverlay } from './ClosedTopicOverlay';\nimport type { MessageListProps } from '../types';\n\n/* ----------------------------------------------------------\n Internal sub-components\n ---------------------------------------------------------- */\nconst DefaultDateSeparator: React.FC<{ label: string }> = React.memo(({ label }) => (\n <div className=\"ermis-message-list__date-separator\">\n <div className=\"ermis-message-list__date-separator-line\" />\n <span className=\"ermis-message-list__date-separator-label\">{label}</span>\n <div className=\"ermis-message-list__date-separator-line\" />\n </div>\n));\n(DefaultDateSeparator as any).displayName = 'DefaultDateSeparator';\n\nconst DefaultJumpToLatest = React.memo(({ onClick, label = '↓ Jump to latest' }: any) => (\n <button className=\"ermis-message-list__jump-latest\" onClick={onClick}>\n {label}\n </button>\n));\nDefaultJumpToLatest.displayName = 'DefaultJumpToLatest';\n\nconst DefaultEmpty = React.memo(({ title = 'No messages yet', subtitle = 'Send a message to start the conversation' }: any) => (\n <div className=\"ermis-message-list__empty\">\n <div className=\"ermis-message-list__empty-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__empty-title\">{title}</span>\n <span className=\"ermis-message-list__empty-subtitle\">{subtitle}</span>\n </div>\n));\nDefaultEmpty.displayName = 'DefaultEmpty';\n\nconst DefaultBubble: React.FC<MessageBubbleProps> = React.memo(({\n isOwnMessage,\n message,\n children,\n}) => (\n <div\n className={`ermis-message-bubble ${isOwnMessage ? 'ermis-message-bubble--own' : 'ermis-message-bubble--other'}`}\n >\n {message?.pinned && (\n <div className={`ermis-message-list__pinned-indicator ${isOwnMessage ? 'ermis-message-list__pinned-indicator--own' : 'ermis-message-list__pinned-indicator--other'}`}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n </div>\n )}\n {children}\n </div>\n));\n(DefaultBubble as any).displayName = 'DefaultBubble';\n\nconst DefaultPendingInviteeNotification = React.memo(({ inviteeName, label }: { inviteeName?: string, label?: string }) => {\n const defaultLabel = inviteeName ? `${inviteeName} needs to accept your invitation to see the messages you've sent` : 'The invited user needs to accept your invitation to see the messages you\\'ve sent';\n return (\n <div className=\"ermis-message-list__pending-invitee\">\n <div className=\"ermis-message-list__pending-invitee-content\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n <span>{label || defaultLabel}</span>\n </div>\n </div>\n );\n});\nDefaultPendingInviteeNotification.displayName = 'DefaultPendingInviteeNotification';\n\n/* ----------------------------------------------------------\n VirtualMessageList\n ---------------------------------------------------------- */\nexport const VirtualMessageList: React.FC<MessageListProps> = React.memo(({\n renderMessage,\n className,\n EmptyStateIndicator = DefaultEmpty,\n AvatarComponent = Avatar,\n MessageBubble = DefaultBubble,\n messageRenderers: customRenderers,\n loadMoreLimit = 25,\n DateSeparatorComponent = DefaultDateSeparator,\n MessageItemComponent = MessageItem,\n SystemMessageItemComponent = SystemMessageItem,\n JumpToLatestButton = DefaultJumpToLatest,\n QuotedMessagePreviewComponent = QuotedMessagePreview,\n MessageActionsBoxComponent,\n showPinnedMessages = true,\n PinnedMessagesComponent = PinnedMessages,\n showReadReceipts = true,\n ReadReceiptsComponent = ReadReceipts,\n ReadReceiptsTooltipComponent,\n readReceiptsMaxAvatars = 5,\n showTypingIndicator = true,\n TypingIndicatorComponent = TypingIndicator,\n MessageReactionsComponent,\n emptyTitle = 'No messages yet',\n emptySubtitle = 'Send a message to start the conversation',\n jumpToLatestLabel = '↓ Jump to latest',\n bannedOverlayTitle = 'You have been banned from this channel',\n bannedOverlaySubtitle = 'You can no longer read or send messages here',\n blockedOverlayTitle = 'You have blocked this user',\n blockedOverlaySubtitle = 'Unblock to continue the conversation',\n pendingOverlayTitle = 'You are invited to this channel',\n pendingOverlaySubtitle = 'Accept the invitation to view messages and interact',\n pendingAcceptLabel = 'Accept',\n pendingRejectLabel = 'Reject',\n pendingSkipLabel = 'Skip',\n skippedOverlayTitle = 'You skipped this conversation',\n skippedOverlaySubtitle = 'Accept the invitation to start chatting',\n skippedAcceptLabel = 'Accept',\n closedTopicOverlayTitle = 'This topic has been closed',\n closedTopicOverlaySubtitle = 'You can no longer read or send messages in this topic.',\n closedTopicReopenLabel = 'Reopen Topic',\n PendingInviteeNotificationComponent = DefaultPendingInviteeNotification,\n pendingInviteeLabel,\n}) => {\n const { client, messages, readState, activeChannel, setActiveChannel, jumpToMessageId, setJumpToMessageId } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n const { isPending } = usePendingState(activeChannel, client.userID);\n \n const isSkipped = client.userID \n ? isSkippedMember(activeChannel?.state?.members?.[client.userID]?.channel_role as string) || \n isSkippedMember(activeChannel?.state?.membership?.channel_role as string)\n : false;\n\n const isClosedTopic = activeChannel?.data?.is_closed_topic === true;\n const parentCid = activeChannel?.data?.parent_cid as string | undefined;\n const parentChannel = parentCid && client ? client.activeChannels[parentCid] : undefined;\n\n const { channelName, channelImage } = useChannelProfile(activeChannel);\n\n const vlistRef = useRef<VListHandle>(null);\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\n const currentUserId = client.userID;\n const currentUserRole = currentUserId ? activeChannel?.state?.members?.[currentUserId]?.channel_role : undefined;\n const canManageTopic = canManageChannel(currentUserRole);\n\n const pendingInviteeName = useMemo(() => {\n if (!activeChannel || !currentUserId) return null;\n if (!isDirectChannel(activeChannel)) return null;\n const membersList = Object.values(activeChannel.state?.members || {});\n if (membersList.length === 2 && !isPending) {\n const otherUser = membersList.find(m => m.user_id !== currentUserId);\n if (otherUser && isPendingMember(otherUser.channel_role)) {\n return otherUser.user?.name || otherUser.user?.id || 'User';\n }\n }\n return null;\n }, [activeChannel, currentUserId, isPending]);\n\n // Ref to scope DOM queries (safe for multiple instances)\n const containerRef = useRef<HTMLDivElement>(null);\n const getVListElement = useCallback((): HTMLElement | null => {\n return containerRef.current?.querySelector('.ermis-message-list__vlist') ?? null;\n }, []);\n\n const handleAcceptInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n const isPublicTeamOrMeeting = isPublicGroupChannel(activeChannel);\n const action = isPublicTeamOrMeeting ? 'join' : 'accept';\n await activeChannel.acceptInvite(action);\n } catch (e: any) {\n console.error('Error accepting invite', e);\n }\n }, [activeChannel]);\n\n const handleRejectInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n await activeChannel.rejectInvite();\n if (setActiveChannel) setActiveChannel(null);\n } catch (e: any) {\n console.error('Error rejecting invite', e);\n }\n }, [activeChannel, setActiveChannel]);\n\n const handleSkipInvite = useCallback(async () => {\n if (!activeChannel) return;\n try {\n await activeChannel.skipInvite();\n if (setActiveChannel) setActiveChannel(null);\n } catch (e: any) {\n console.error('Error skipping invite', e);\n }\n }, [activeChannel, setActiveChannel]);\n\n const scrollToBottom = useCallback((smooth = false, attempts = 0) => {\n const handle = vlistRef.current;\n if (!handle) return;\n\n const count = messagesRef.current.length;\n if (count === 0) return;\n\n // Ensure virtua has measured the viewport via ResizeObserver.\n // If viewportSize is unmeasured (0) or scrollSize is 0, align: 'end' calculates wrong.\n if ((!handle.viewportSize || handle.viewportSize === 0) && attempts < 10) {\n requestAnimationFrame(() => scrollToBottom(smooth, attempts + 1));\n return;\n }\n\n handle.scrollToIndex(count - 1, { align: 'end', smooth });\n }, []);\n\n // Shared guard: skip scroll-triggered loads during jump transitions\n const jumpingRef = useRef(false);\n\n /* ---------- Hooks ---------- */\n const {\n shiftMode,\n hasMore, setHasMore,\n hasNewer, setHasNewer,\n loadingMoreRef, loadingNewerRef,\n handleScroll,\n isAtBottomRef,\n } = useLoadMessages({\n vlistRef,\n messagesRef,\n jumpingRef,\n loadMoreLimit,\n });\n\n const { highlightedId, scrollToMessage, jumpToLatest } = useScrollToMessage({\n vlistRef,\n messagesRef,\n setHasMore,\n setHasNewer,\n getVListElement,\n scrollToBottom,\n jumpingRef,\n });\n\n // React to jumpToMessageId from context (e.g. search panel)\n useEffect(() => {\n if (jumpToMessageId) {\n scrollToMessage(jumpToMessageId);\n setJumpToMessageId(null);\n }\n }, [jumpToMessageId, scrollToMessage, setJumpToMessageId]);\n\n useChannelMessages({\n scrollToBottom,\n jumpingRef,\n isAtBottomRef,\n onChannelSwitch: useCallback(() => {\n setHasMore(true);\n setHasNewer(false);\n loadingMoreRef.current = false;\n loadingNewerRef.current = false;\n }, [setHasMore, setHasNewer]),\n });\n\n const hasOverlay = Boolean(isClosedTopic || isPending || isBanned || isBlocked || isSkipped);\n const prevOverlayRef = useRef(hasOverlay);\n\n useEffect(() => {\n if (prevOverlayRef.current && !hasOverlay) {\n // Transitioned from having an overlay to normal view.\n // Give VList a moment to measure its new DOM size via ResizeObserver, then jump to the bottom.\n setTimeout(() => scrollToBottom(false), 50);\n setTimeout(() => scrollToBottom(false), 200);\n setTimeout(() => scrollToBottom(false), 500);\n }\n prevOverlayRef.current = hasOverlay;\n }, [hasOverlay, scrollToBottom]);\n\n const renderers = useMemo(\n () => ({ ...defaultMessageRenderers, ...customRenderers }),\n [customRenderers],\n );\n\n /* ---------- Compute read-by map (message.id → readers) ---------- */\n const readByMap = useMemo(() => {\n const map: Record<string, Array<{ id: string; name?: string; avatar?: string; last_read?: Date | string }>> = {};\n if (!readState) return map;\n for (const userId of Object.keys(readState)) {\n if (userId === currentUserId) continue; // exclude self\n const entry = readState[userId];\n if (entry.last_read_message_id) {\n if (!map[entry.last_read_message_id]) {\n map[entry.last_read_message_id] = [];\n }\n map[entry.last_read_message_id].push({\n id: userId,\n name: entry.user?.name,\n avatar: entry.user?.avatar,\n last_read: entry.last_read,\n });\n }\n }\n return map;\n }, [readState, currentUserId]);\n\n /* ---------- Memoized message elements ---------- */\n const messageElements = useMemo(() => {\n return messages.map((message, index) => {\n const isOwnMessage =\n message.user_id === currentUserId || message.user?.id === currentUserId;\n const messageType = (message.type || 'regular') as MessageLabel;\n\n // Date separator\n const prevMsg = index > 0 ? messages[index - 1] : null;\n const showDateSeparator =\n !prevMsg || getDateKey(message.created_at) !== getDateKey(prevMsg.created_at);\n const dateSeparator = showDateSeparator ? (\n <DateSeparatorComponent label={formatDateLabel(message.created_at)} />\n ) : null;\n\n if (renderMessage) {\n return (\n <div key={message.id || `msg-${index}`}>\n {dateSeparator}\n <div>{renderMessage(message, isOwnMessage)}</div>\n </div>\n );\n }\n\n if (messageType === 'system') {\n return (\n <div key={message.id || `msg-${index}`}>\n {dateSeparator}\n <SystemMessageItemComponent\n message={message}\n isOwnMessage={isOwnMessage}\n SystemRenderer={renderers.system}\n />\n </div>\n );\n }\n\n // Message grouping\n const prevType = (prevMsg?.type || 'regular') as MessageLabel;\n const isFirstInGroup =\n showDateSeparator ||\n !prevMsg ||\n prevType === 'system' ||\n prevType === 'signal' ||\n getMessageUserId(prevMsg) !== getMessageUserId(message);\n\n const nextMsg = index < messages.length - 1 ? messages[index + 1] : null;\n const nextType = (nextMsg?.type || 'regular') as MessageLabel;\n const nextShowDateSeparator = nextMsg\n ? getDateKey(nextMsg.created_at) !== getDateKey(message.created_at)\n : false;\n\n const isLastInGroup =\n !nextMsg ||\n nextShowDateSeparator ||\n nextType === 'system' ||\n nextType === 'signal' ||\n getMessageUserId(nextMsg) !== getMessageUserId(message);\n\n const MessageRenderer = renderers[messageType] || renderers.regular;\n\n return (\n <div key={message.id || `msg-${index}`}>\n {dateSeparator}\n <MessageItemComponent\n message={message}\n isOwnMessage={isOwnMessage}\n isFirstInGroup={isFirstInGroup}\n isLastInGroup={isLastInGroup}\n isHighlighted={highlightedId === message.id}\n AvatarComponent={AvatarComponent}\n MessageBubble={MessageBubble}\n MessageRenderer={MessageRenderer}\n onClickQuote={scrollToMessage}\n QuotedMessagePreviewComponent={QuotedMessagePreviewComponent}\n MessageActionsBoxComponent={MessageActionsBoxComponent}\n MessageReactionsComponent={MessageReactionsComponent}\n />\n {/* Read receipts — full width, right-aligned */}\n {showReadReceipts && (\n <ReadReceiptsComponent\n readers={readByMap[message.id!] || []}\n maxAvatars={readReceiptsMaxAvatars}\n AvatarComponent={AvatarComponent}\n TooltipComponent={ReadReceiptsTooltipComponent}\n isOwnMessage={isOwnMessage}\n isLastInGroup={isLastInGroup}\n status={message.status}\n />\n )}\n </div>\n );\n });\n }, [\n messages,\n currentUserId,\n highlightedId,\n renderers,\n renderMessage,\n AvatarComponent,\n MessageBubble,\n scrollToMessage,\n DateSeparatorComponent,\n MessageItemComponent,\n SystemMessageItemComponent,\n QuotedMessagePreviewComponent,\n MessageActionsBoxComponent,\n MessageReactionsComponent,\n readByMap,\n showReadReceipts,\n ReadReceiptsComponent,\n ReadReceiptsTooltipComponent,\n readReceiptsMaxAvatars,\n ]);\n\n if (isBanned || isBlocked) {\n return (\n <BannedOverlay\n isBlocked={isBlocked}\n blockedTitle={blockedOverlayTitle}\n bannedTitle={bannedOverlayTitle}\n blockedSubtitle={blockedOverlaySubtitle}\n bannedSubtitle={bannedOverlaySubtitle}\n onUnblock={() => { activeChannel?.unblockUser().catch((e: any) => console.error('Error unblocking user', e)); }}\n />\n );\n }\n\n if (isPending) {\n const isDirect = activeChannel ? isDirectChannel(activeChannel) : false;\n return (\n <PendingOverlay\n channelImage={channelImage}\n channelName={channelName}\n title={pendingOverlayTitle}\n subtitle={pendingOverlaySubtitle}\n rejectLabel={pendingRejectLabel}\n acceptLabel={pendingAcceptLabel}\n onReject={handleRejectInvite}\n onAccept={handleAcceptInvite}\n skipLabel={isDirect ? pendingSkipLabel : undefined}\n onSkip={isDirect ? handleSkipInvite : undefined}\n AvatarComponent={AvatarComponent}\n />\n );\n }\n\n if (isSkipped) {\n return (\n <SkippedOverlay\n channelImage={channelImage}\n channelName={channelName}\n title={skippedOverlayTitle}\n subtitle={skippedOverlaySubtitle}\n acceptLabel={skippedAcceptLabel}\n onAccept={handleAcceptInvite}\n AvatarComponent={AvatarComponent}\n />\n );\n }\n\n if (isClosedTopic) {\n return (\n <ClosedTopicOverlay\n title={closedTopicOverlayTitle}\n subtitle={closedTopicOverlaySubtitle}\n canManageTopic={Boolean(canManageTopic && activeChannel && parentChannel)}\n reopenLabel={closedTopicReopenLabel}\n onReopen={() => { parentChannel?.reopenTopic(activeChannel!.cid).catch((e: any) => console.error('Error reopening topic', e)); }}\n />\n );\n }\n\n return (\n <div ref={containerRef} className={`ermis-message-list${className ? ` ${className}` : ''}`}>\n {showPinnedMessages && <PinnedMessagesComponent onClickMessage={scrollToMessage} AvatarComponent={AvatarComponent} />}\n\n {messages.length === 0 && (\n EmptyStateIndicator === DefaultEmpty\n ? <DefaultEmpty title={emptyTitle} subtitle={emptySubtitle} />\n : <EmptyStateIndicator />\n )}\n\n {pendingInviteeName && (\n <PendingInviteeNotificationComponent \n inviteeName={pendingInviteeName} \n label={typeof pendingInviteeLabel === 'function' ? pendingInviteeLabel(pendingInviteeName) : pendingInviteeLabel} \n />\n )}\n\n <VList\n key={activeChannel?.cid || 'empty'}\n ref={vlistRef}\n shift={shiftMode}\n onScroll={handleScroll}\n className=\"ermis-message-list__vlist\"\n >\n {messageElements}\n </VList>\n\n {/* Typing indicator */}\n {showTypingIndicator && <TypingIndicatorComponent />}\n\n {/* Jump to latest button */}\n {hasNewer && (\n JumpToLatestButton === DefaultJumpToLatest\n ? <DefaultJumpToLatest onClick={jumpToLatest} label={jumpToLatestLabel} />\n : <JumpToLatestButton onClick={jumpToLatest} />\n )}\n </div>\n );\n});\n\nVirtualMessageList.displayName = 'VirtualMessageList';\n","import { useState, useRef, useCallback, useEffect } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { formatMessage } from '@ermis-network/ermis-chat-sdk';\nimport type { VListHandle } from 'virtua';\nimport { useChatClient } from './useChatClient';\n\nconst LOAD_MORE_THRESHOLD = 200;\n\n/** Filter out messages whose id already exists in `existing` (or self-dedup if omitted). */\nexport const dedupMessages = (incoming: any[], existing?: any[]) => {\n const ids = new Set(existing?.map((m) => m.id) ?? []);\n return incoming.filter((m: any) => {\n if (!m.id || ids.has(m.id)) return false;\n ids.add(m.id);\n return true;\n });\n};\n\nexport type UseLoadMessagesOptions = {\n vlistRef: React.RefObject<VListHandle | null>;\n messagesRef: React.MutableRefObject<FormatMessageResponse[]>;\n /** Shared guard ref — skip scroll-triggered loads during jump transitions */\n jumpingRef: React.MutableRefObject<boolean>;\n loadMoreLimit?: number;\n};\n\nexport type UseLoadMessagesReturn = {\n /** VList shift mode — true during prepend, auto-resets to false */\n shiftMode: boolean;\n hasMore: boolean;\n setHasMore: React.Dispatch<React.SetStateAction<boolean>>;\n hasNewer: boolean;\n setHasNewer: React.Dispatch<React.SetStateAction<boolean>>;\n hasMoreRef: React.RefObject<boolean>;\n hasNewerRef: React.RefObject<boolean>;\n loadingMoreRef: React.MutableRefObject<boolean>;\n loadingNewerRef: React.MutableRefObject<boolean>;\n loadMore: () => Promise<void>;\n loadNewer: () => Promise<void>;\n handleScroll: (offset: number) => void;\n isAtBottomRef: React.MutableRefObject<boolean>;\n};\n\nexport function useLoadMessages({\n vlistRef,\n messagesRef,\n jumpingRef,\n loadMoreLimit = 25,\n}: UseLoadMessagesOptions): UseLoadMessagesReturn {\n const { activeChannel, setMessages } = useChatClient();\n const [hasMore, setHasMore] = useState(true);\n const [hasNewer, setHasNewer] = useState(false);\n const [shiftMode, setShiftMode] = useState(false);\n\n // Auto-reset shiftMode after each prepend render\n useEffect(() => {\n if (shiftMode) {\n requestAnimationFrame(() => setShiftMode(false));\n }\n }, [shiftMode]);\n\n // Refs synced from state (avoid handleScroll recreation on state change)\n const hasMoreRef = useRef(true);\n hasMoreRef.current = hasMore;\n const hasNewerRef = useRef(false);\n hasNewerRef.current = hasNewer;\n const isAtBottomRef = useRef(true);\n\n // Concurrency guards\n const loadingMoreRef = useRef(false);\n const loadingNewerRef = useRef(false);\n\n const loadMore = useCallback(async () => {\n if (!activeChannel || loadingMoreRef.current) return;\n\n const currentMessages = messagesRef.current;\n const oldestMessage = currentMessages[0];\n if (!oldestMessage?.id) return;\n\n loadingMoreRef.current = true;\n try {\n const olderRaw = await activeChannel.queryMessagesLessThanId(oldestMessage.id, loadMoreLimit);\n\n if (olderRaw.length === 0) {\n setHasMore(false);\n return;\n }\n\n const olderFormatted = olderRaw.map((msg: any) => formatMessage(msg));\n setShiftMode(true);\n setMessages((prev) => {\n const unique = dedupMessages(olderFormatted, prev);\n if (unique.length === 0) {\n setHasMore(false);\n }\n return [...unique, ...prev];\n });\n } catch (err) {\n console.error('Failed to load more messages:', err);\n } finally {\n loadingMoreRef.current = false;\n }\n }, [activeChannel, loadMoreLimit, setMessages]);\n\n const loadNewer = useCallback(async () => {\n if (!activeChannel || loadingNewerRef.current) return;\n\n const currentMessages = messagesRef.current;\n const newestMessage = currentMessages[currentMessages.length - 1];\n if (!newestMessage?.id) return;\n\n loadingNewerRef.current = true;\n try {\n const newerRaw = await activeChannel.queryMessagesGreaterThanId(newestMessage.id, loadMoreLimit);\n\n if (newerRaw.length === 0) {\n setHasNewer(false);\n return;\n }\n\n const newerFormatted = newerRaw.map((msg: any) => formatMessage(msg));\n setMessages((prev) => {\n const unique = dedupMessages(newerFormatted, prev);\n if (unique.length === 0) {\n setHasNewer(false);\n }\n return [...prev, ...unique];\n });\n } catch (err) {\n console.error('Failed to load newer messages:', err);\n } finally {\n loadingNewerRef.current = false;\n }\n }, [activeChannel, loadMoreLimit, setMessages]);\n\n const handleScroll = useCallback(\n (offset: number) => {\n if (jumpingRef.current) return;\n const handle = vlistRef.current;\n if (!handle) return;\n const { scrollSize, viewportSize } = handle;\n\n const isBottom = Math.ceil(offset + viewportSize) >= scrollSize - 20;\n isAtBottomRef.current = isBottom;\n\n // Skip if content doesn't fill the viewport\n if (scrollSize <= viewportSize) {\n isAtBottomRef.current = true;\n return;\n }\n\n if (offset <= LOAD_MORE_THRESHOLD && hasMoreRef.current) {\n loadMore();\n }\n\n if (offset + viewportSize >= scrollSize - LOAD_MORE_THRESHOLD && hasNewerRef.current) {\n loadNewer();\n }\n },\n [loadMore, loadNewer],\n );\n\n return {\n shiftMode,\n hasMore,\n setHasMore,\n hasNewer,\n setHasNewer,\n hasMoreRef,\n hasNewerRef,\n loadingMoreRef,\n loadingNewerRef,\n loadMore,\n loadNewer,\n handleScroll,\n isAtBottomRef,\n };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { formatMessage } from '@ermis-network/ermis-chat-sdk';\nimport type { VListHandle } from 'virtua';\nimport { dedupMessages } from './useLoadMessages';\nimport { useChatClient } from './useChatClient';\n\nexport type UseScrollToMessageOptions = {\n vlistRef: React.RefObject<VListHandle | null>;\n messagesRef: React.MutableRefObject<FormatMessageResponse[]>;\n setHasMore: React.Dispatch<React.SetStateAction<boolean>>;\n setHasNewer: React.Dispatch<React.SetStateAction<boolean>>;\n /** Getter to access the VList DOM element (scoped to container) */\n getVListElement: () => HTMLElement | null;\n scrollToBottom: (smooth: boolean) => void;\n /** Shared guard ref — blocks scroll-triggered loads during jumps */\n jumpingRef: React.MutableRefObject<boolean>;\n};\n\nexport type UseScrollToMessageReturn = {\n highlightedId: string | null;\n scrollToMessage: (messageId: string) => void;\n jumpToLatest: () => void;\n};\n\nexport function useScrollToMessage({\n vlistRef,\n messagesRef,\n setHasMore,\n setHasNewer,\n getVListElement,\n scrollToBottom,\n jumpingRef,\n}: UseScrollToMessageOptions): UseScrollToMessageReturn {\n const { activeChannel, setMessages } = useChatClient();\n const [highlightedId, setHighlightedId] = useState<string | null>(null);\n const highlightTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Cleanup highlight timer on unmount\n useEffect(() => {\n return () => {\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n };\n }, []);\n\n const highlight = useCallback((messageId: string) => {\n if (highlightTimerRef.current) clearTimeout(highlightTimerRef.current);\n setHighlightedId(messageId);\n highlightTimerRef.current = setTimeout(() => {\n setHighlightedId(null);\n highlightTimerRef.current = null;\n }, 2500);\n }, []);\n\n const scrollToMessage = useCallback(\n async (messageId: string) => {\n // Prevent concurrent calls\n if (jumpingRef.current) return;\n\n // Case 1: message is already in current list\n const idx = messagesRef.current.findIndex((m) => m.id === messageId);\n if (idx !== -1) {\n vlistRef.current?.scrollToIndex(idx, { align: 'center', smooth: true });\n highlight(messageId);\n return;\n }\n\n // Case 2: message NOT in list — fetch around it\n if (!activeChannel) return;\n\n jumpingRef.current = true;\n\n const vlistEl = getVListElement();\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 150ms ease-out';\n vlistEl.style.opacity = '0';\n }\n\n try {\n const rawMessages = await activeChannel.queryMessagesAroundId(messageId, 25);\n if (!rawMessages || rawMessages.length === 0) {\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n return;\n }\n\n const formatted = rawMessages.map((msg: any) => formatMessage(msg));\n const unique = dedupMessages(formatted);\n\n setHasMore(true);\n setHasNewer(true);\n setMessages(unique);\n\n // Wait for VList to render, then jump while hidden, then fade in\n setTimeout(() => {\n const newIdx = unique.findIndex((m: any) => m.id === messageId);\n if (newIdx === -1) {\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n return;\n }\n\n vlistRef.current?.scrollToIndex(newIdx, { align: 'center' });\n\n setTimeout(() => {\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 200ms ease-in';\n vlistEl.style.opacity = '1';\n }\n highlight(messageId);\n setTimeout(() => {\n jumpingRef.current = false;\n }, 500);\n }, 100);\n }, 200);\n } catch (err) {\n console.error('Failed to fetch messages around ID:', err);\n jumpingRef.current = false;\n if (vlistEl) vlistEl.style.opacity = '1';\n }\n },\n [activeChannel, highlight, setMessages, setHasMore, setHasNewer, getVListElement],\n );\n\n const jumpToLatest = useCallback(() => {\n if (!activeChannel) return;\n jumpingRef.current = true;\n\n const vlistEl = getVListElement();\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 150ms ease-out';\n vlistEl.style.opacity = '0';\n }\n\n const latestMsgs = [...activeChannel.state.latestMessages];\n setMessages(latestMsgs);\n setHasNewer(false);\n setHasMore(true);\n\n setTimeout(() => {\n scrollToBottom(false);\n setTimeout(() => {\n if (vlistEl) {\n vlistEl.style.transition = 'opacity 200ms ease-in';\n vlistEl.style.opacity = '1';\n }\n setTimeout(() => {\n jumpingRef.current = false;\n }, 500);\n }, 100);\n }, 200);\n }, [activeChannel, scrollToBottom, getVListElement, setMessages, setHasMore, setHasNewer]);\n\n return { highlightedId, scrollToMessage, jumpToLatest };\n}\n","import { useEffect, useCallback } from 'react';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\nimport { isPendingMember } from '../channelRoleUtils';\n\nexport type UseChannelMessagesOptions = {\n scrollToBottom: (smooth: boolean) => void;\n /** Shared guard ref — blocks scroll-triggered loads during channel switch */\n jumpingRef: React.MutableRefObject<boolean>;\n isAtBottomRef: React.MutableRefObject<boolean>;\n /** Called to reset load-more state when channel switches */\n onChannelSwitch?: () => void;\n};\n\n/**\n * Schedule multiple scroll-to-bottom attempts with increasing delays.\n * Handles content that changes height after initial render (images, embeds).\n */\nconst SCROLL_DELAYS = [50, 200, 500, 1000];\n\n/**\n * Subscribes to channel message events and handles:\n * - message.new → sync + scroll to bottom\n * - message.updated / message.deleted → sync only\n * - Channel switch → reset state + scroll to bottom\n */\nexport function useChannelMessages({\n scrollToBottom,\n jumpingRef,\n isAtBottomRef,\n onChannelSwitch,\n}: UseChannelMessagesOptions): void {\n const { client, activeChannel, syncMessages, setReadState } = useChatClient();\n\n const scheduleScrollToBottom = useCallback(\n (smooth: boolean) => {\n if (smooth) {\n // Trigger smooth scroll exactly once, otherwise browsers will\n // cancel the smooth animation if called multiple times in a row\n setTimeout(() => scrollToBottom(true), 100);\n } else {\n SCROLL_DELAYS.forEach((delay) => {\n setTimeout(() => scrollToBottom(false), delay);\n });\n }\n },\n [scrollToBottom],\n );\n\n useEffect(() => {\n if (!activeChannel) return;\n\n // Reset state for the new channel\n onChannelSwitch?.();\n\n // Manually force isAtBottom to true because we are jumping to the bottom.\n // jumpingRef blocks the resulting scroll event from updating isAtBottomRef,\n // so if it was false in the previous channel, it would stay false!\n isAtBottomRef.current = true;\n\n // Block scroll triggers during channel-switch scroll\n jumpingRef.current = true;\n // Defer scroll outside React lifecycle to avoid virtua flushSync warning\n setTimeout(() => {\n scrollToBottom(false);\n // Wait long enough for scrollToBottom's internal retries and the browser\n // to execute the scroll event\n setTimeout(() => {\n jumpingRef.current = false;\n }, 100);\n }, 0);\n\n const handleNewMessage = (event: Event) => {\n // Capture scroll state BEFORE sync causes re-render\n const wasAtBottom = isAtBottomRef.current;\n\n syncMessages();\n\n const isOwnMessage = event.message?.user?.id === client.userID || event.message?.user_id === client.userID;\n\n if (isOwnMessage || wasAtBottom) {\n scheduleScrollToBottom(true);\n }\n };\n\n const handleMessageChange = (_event: Event) => {\n syncMessages();\n };\n\n const handleMessageRead = (_event: Event) => {\n // SDK already updated channel.state.read — sync into React state\n setReadState({ ...activeChannel.state.read });\n };\n\n const handleUnblocked = (event: Event) => {\n // If the current user's block status was updated (meaning we unblocked someone)\n if (event.member?.user_id === client.userID) {\n // Refetch latest messages to fill in any missed during the block period\n activeChannel\n .query({ messages: { limit: 30 } })\n .then(() => {\n syncMessages();\n scheduleScrollToBottom(false);\n const isPending = isPendingMember(activeChannel.state?.membership?.channel_role as string);\n if (!isPending) {\n activeChannel.markRead().catch(() => {});\n }\n })\n .catch((e) => console.error('Failed to sync messages after unblock', e));\n }\n };\n\n const handleInviteAccepted = (event: Event) => {\n // Make sure the accepted invite corresponds to the actively opened channel\n const eventCid =\n event.cid ||\n event.channel?.cid ||\n ((event as any).channel_id ? `${(event as any).channel_type}:${(event as any).channel_id}` : undefined);\n if (eventCid === activeChannel.cid) {\n activeChannel\n .query({ messages: { limit: 30 } })\n .then(() => {\n syncMessages();\n scheduleScrollToBottom(false);\n activeChannel.markRead().catch(() => {});\n })\n .catch((e) => console.error('Failed to sync messages after accepting invite', e));\n }\n };\n\n const client = activeChannel.getClient();\n const sub1 = activeChannel.on('message.new', handleNewMessage);\n const sub2 = activeChannel.on('message.updated', handleMessageChange);\n const sub3 = activeChannel.on('message.deleted', handleMessageChange);\n const sub4 = activeChannel.on('message.pinned', handleMessageChange);\n const sub5 = activeChannel.on('message.unpinned', handleMessageChange);\n const sub6 = activeChannel.on('message.read', handleMessageRead);\n const sub7 = activeChannel.on('message.deleted_for_me', handleMessageChange);\n const sub8 = activeChannel.on('reaction.new', handleMessageChange);\n const sub9 = activeChannel.on('reaction.deleted', handleMessageChange);\n const sub10 = activeChannel.on('member.unblocked', handleUnblocked);\n const sub11 = client.on('notification.invite_accepted', handleInviteAccepted);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n sub9.unsubscribe();\n sub10.unsubscribe();\n sub11.unsubscribe();\n };\n }, [activeChannel, scrollToBottom, scheduleScrollToBottom, syncMessages, onChannelSwitch, setReadState]);\n}\n","import { useState, useEffect, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\n\nexport const useChannelMembers = (channel: Channel | null | undefined) => {\n const [memberUpdateCount, setMemberUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!channel) return;\n const updateMembers = () => setMemberUpdateCount(c => c + 1);\n\n const sub1 = channel.on('member.added', updateMembers);\n const sub2 = channel.on('member.removed', updateMembers);\n const sub3 = channel.on('member.updated', updateMembers);\n const sub4 = channel.on('member.promoted', updateMembers);\n const sub5 = channel.on('member.demoted', updateMembers);\n const sub6 = channel.on('member.banned', updateMembers);\n const sub7 = channel.on('member.unbanned', updateMembers);\n const sub8 = channel.on('notification.invite_rejected', updateMembers);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n sub3.unsubscribe();\n sub4.unsubscribe();\n sub5.unsubscribe();\n sub6.unsubscribe();\n sub7.unsubscribe();\n sub8.unsubscribe();\n };\n }, [channel]);\n\n const membersArray = useMemo(() => {\n if (!channel?.state?.members) return [];\n return Object.values(channel.state.members) as Array<Record<string, unknown>>;\n }, [channel?.state?.members, memberUpdateCount]);\n\n return { members: membersArray, memberUpdateCount };\n};\n\nexport const useChannelProfile = (channel: Channel | null | undefined) => {\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n useEffect(() => {\n if (!channel) return;\n const updateChannel = () => setChannelUpdateCount(c => c + 1);\n const sub = channel.on('channel.updated', updateChannel);\n return () => sub.unsubscribe();\n }, [channel]);\n\n const channelName = useMemo(() => channel?.data?.name || channel?.cid || 'Unknown Channel', [channel?.data?.name, channel?.cid, channel?.type, channelUpdateCount]);\n const channelImage = useMemo(() => channel?.data?.image as string | undefined, [channel?.data?.image, channelUpdateCount]);\n const channelDescription = useMemo(() => channel?.data?.description as string | undefined, [channel?.data?.description, channelUpdateCount]);\n\n return { channelName, channelImage, channelDescription };\n};\n","import React from 'react';\nimport type { MessageItemProps, SystemMessageItemProps } from '../types';\nimport { QuotedMessagePreview } from './QuotedMessagePreview';\nimport { MessageActionsBox } from './MessageActionsBox';\nimport { MessageReactions } from './MessageReactions';\nimport { MessageQuickReactions } from './MessageQuickReactions';\nimport { useChannelCapabilities } from '../hooks/useChannelCapabilities';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { formatTime } from '../utils';\nimport { isSystemMessage } from '../messageTypeUtils';\n\nexport type { MessageItemProps, SystemMessageItemProps } from '../types';\n\n/* ----------------------------------------------------------\n MessageItem — single regular/signal message row\n ---------------------------------------------------------- */\n/* Inline status icon for own messages (sent / sending / error) */\nconst InlineStatusIcon: React.FC<{ status?: string; isOwnMessage: boolean; isLastInGroup: boolean }> = React.memo(({\n status,\n isOwnMessage,\n isLastInGroup,\n}) => {\n if (!isOwnMessage) return null;\n\n const isError = status === 'error' || status === 'failed_offline';\n if (!isLastInGroup && !isError) return null;\n\n if (isError) {\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--failed\" title=\"Failed to send\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line>\n </svg>\n </span>\n );\n }\n\n if (status === 'sending') {\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--sending\" title=\"Sending...\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <polyline points=\"12 6 12 12 16 14\"></polyline>\n </svg>\n </span>\n );\n }\n\n return (\n <span className=\"ermis-message-status-icon ermis-message-status-icon--sent\" title=\"Sent\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n </span>\n );\n});\nInlineStatusIcon.displayName = 'InlineStatusIcon';\n\nexport const MessageItem: React.FC<MessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n isFirstInGroup,\n isLastInGroup,\n isHighlighted,\n AvatarComponent,\n MessageBubble,\n MessageRenderer,\n onClickQuote,\n QuotedMessagePreviewComponent = QuotedMessagePreview,\n MessageActionsBoxComponent = MessageActionsBox,\n MessageReactionsComponent = MessageReactions,\n forwardedLabel = 'Forwarded',\n editedLabel = 'Edited',\n}) => {\n const { activeChannel, client } = useChatClient();\n const { hasCapability } = useChannelCapabilities();\n \n const canReact = hasCapability('send-reaction');\n\n const userName = message.user?.name || message.user_id;\n const userAvatar = message.user?.avatar;\n\n const quotedMessage = (message as any).quoted_message;\n const isForwarded = !!(message as any).forward_cid;\n const oldTexts = (message as any).old_texts;\n const isEdited = oldTexts && oldTexts.length > 0;\n const hasAttachments = message.attachments && message.attachments.length > 0;\n\n const handleReactionToggle = React.useCallback(async (type: string) => {\n if (!activeChannel || !canReact) return;\n const currentUserId = client?.userID;\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some((r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId));\n\n try {\n if (isOwn) {\n await activeChannel.deleteReaction(message.id!, type);\n } else {\n await activeChannel.sendReaction(message.id!, type);\n }\n } catch (err) {\n console.error('Failed to toggle reaction', err);\n }\n }, [activeChannel, message, client?.userID]);\n\n const statusClass =\n message.status === 'sending'\n ? 'ermis-message--sending'\n : (message.status === 'error' || message.status === 'failed_offline')\n ? 'ermis-message--error'\n : '';\n\n const isNewMessage = React.useMemo(() => {\n if (!message.created_at) return false;\n return Date.now() - new Date(message.created_at).getTime() < 1000;\n }, [message.created_at]);\n\n const itemClass = [\n 'ermis-message-list__item',\n isOwnMessage ? 'ermis-message-list__item--own' : 'ermis-message-list__item--other',\n isFirstInGroup ? 'ermis-message-list__item--group-start' : 'ermis-message-list__item--group-cont',\n isHighlighted ? 'ermis-message-list__item--highlighted' : '',\n isNewMessage ? 'ermis-message-list__item--new' : '',\n statusClass,\n ].filter(Boolean).join(' ');\n\n const contentClass = [\n 'ermis-message-list__item-content',\n hasAttachments ? 'ermis-message-list__item-content--has-attachments' : '',\n ].filter(Boolean).join(' ');\n\n return (\n <div className={itemClass} data-message-id={message.id}>\n {/* Avatar area: show avatar only on first message, otherwise placeholder for alignment */}\n {!isOwnMessage && (\n <div className=\"ermis-message-list__item-avatar\">\n {isFirstInGroup\n ? <AvatarComponent image={userAvatar} name={userName} size={28} />\n : <div style={{ width: 28 }} />\n }\n </div>\n )}\n <div className={contentClass}>\n {!isOwnMessage && isFirstInGroup && (\n <span className=\"ermis-message-list__item-user\">{userName}</span>\n )}\n {/* Quoted message preview */}\n {quotedMessage && onClickQuote && (\n <QuotedMessagePreviewComponent\n quotedMessage={quotedMessage}\n isOwnMessage={isOwnMessage}\n onClick={onClickQuote}\n />\n )}\n <div className=\"ermis-message-list__bubble-wrapper\">\n <MessageQuickReactions message={message} isOwnMessage={isOwnMessage} disabled={!canReact} />\n <MessageBubble message={message} isOwnMessage={isOwnMessage}>\n {isForwarded && (\n <span className=\"ermis-message-list__forwarded-indicator\">{forwardedLabel}</span>\n )}\n <MessageRenderer message={message} isOwnMessage={isOwnMessage} />\n <span className=\"ermis-message-list__item-time\">\n {isEdited && (\n <span\n className=\"ermis-message-list__edited-indicator\"\n // data-tooltip={oldTexts.map((ot: any) => `[${formatTime(ot.created_at)}] ${ot.text}`).join('\\n')}\n >\n {editedLabel}\n </span>\n )}\n {formatTime(message.created_at)}\n <InlineStatusIcon status={message.status} isOwnMessage={isOwnMessage} isLastInGroup={isLastInGroup} />\n </span>\n </MessageBubble>\n\n {/* Actions: hover buttons + dropdown menu */}\n {!isSystemMessage(message) && (\n <MessageActionsBoxComponent\n message={message}\n isOwnMessage={isOwnMessage}\n />\n )}\n\n {/* Message Reactions */}\n {MessageReactionsComponent && (\n <MessageReactionsComponent\n reactionCounts={(message as any).reaction_counts}\n ownReactions={(message as any).own_reactions}\n latestReactions={(message as any).latest_reactions}\n onClickReaction={handleReactionToggle}\n disabled={!canReact}\n />\n )}\n </div>\n </div>\n </div>\n );\n});\nMessageItem.displayName = 'MessageItem';\n\n/* ----------------------------------------------------------\n SystemMessageItem — system/notification message row\n ---------------------------------------------------------- */\nexport const SystemMessageItem: React.FC<SystemMessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n SystemRenderer,\n}) => (\n <div className=\"ermis-message-list__system\">\n <SystemRenderer message={message} isOwnMessage={isOwnMessage} />\n </div>\n));\nSystemMessageItem.displayName = 'SystemMessageItem';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { QuotedMessagePreviewProps } from '../types';\n\nexport type { QuotedMessagePreviewProps } from '../types';\n\nconst MAX_PREVIEW_LENGTH = 100;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\nexport const QuotedMessagePreview: React.FC<QuotedMessagePreviewProps> = React.memo(({\n quotedMessage,\n isOwnMessage,\n onClick,\n}) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const authorName = quotedMessage.user?.name || quotedMessage.user?.id || 'Unknown';\n \n const rawText = quotedMessage.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, quotedMessage as any, userMap), [rawText, quotedMessage, userMap]);\n \n const previewText = formattedText\n ? truncateText(formattedText, MAX_PREVIEW_LENGTH)\n : 'Attachment';\n\n const handleClick = () => {\n onClick(quotedMessage.id);\n };\n\n return (\n <div\n className={`ermis-quoted-message ${isOwnMessage ? 'ermis-quoted-message--own' : ''}`}\n onClick={handleClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleClick();\n }}\n >\n <span className=\"ermis-quoted-message__author\">{authorName}</span>\n <span className=\"ermis-quoted-message__text\">{previewText}</span>\n </div>\n );\n});\n\nQuotedMessagePreview.displayName = 'QuotedMessagePreview';\n","import React, { useCallback } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { useMessageActions } from '../hooks/useMessageActions';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { MessageActionsBoxProps } from '../types';\nimport { Dropdown, closeAllDropdowns } from './Dropdown';\n\n// Aliased for backward compatibility\nexport const closeAllActionBoxes = closeAllDropdowns;\n\nexport const MessageActionsBox: React.FC<MessageActionsBoxProps> = ({\n message,\n isOwnMessage,\n onReply: onReplyProp,\n onForward,\n onPinToggle,\n onEdit,\n onCopy,\n onDelete,\n onDeleteForMe,\n pinLabel = 'Pin',\n unpinLabel = 'Unpin',\n editLabel = 'Edit',\n copyLabel = 'Copy',\n deleteForMeLabel = 'Delete for me',\n deleteForEveryoneLabel = 'Delete for everyone',\n}) => {\n const { setQuotedMessage, setEditingMessage, setForwardingMessage, activeChannel } = useChatClient();\n const [anchorRect, setAnchorRect] = React.useState<DOMRect | null>(null);\n const actions = useMessageActions(message, isOwnMessage);\n\n // Default handlers\n const onReply = onReplyProp ?? ((msg: FormatMessageResponse) => setQuotedMessage(msg));\n const onForwardHandler = onForward ?? ((msg: FormatMessageResponse) => setForwardingMessage(msg));\n const onPinToggleHandler = onPinToggle ?? (async (msg: FormatMessageResponse, isPinned: boolean) => {\n if (!activeChannel) return;\n try {\n if (isPinned) {\n await activeChannel.unpinMessage(msg.id!);\n } else {\n await activeChannel.pinMessage(msg.id!);\n }\n } catch (err) {\n console.error('Failed to toggle pin', err);\n }\n });\n const onEditHandler = onEdit ?? ((msg: FormatMessageResponse) => setEditingMessage(msg));\n\n const onDeleteForEveryoneHandler = onDelete ?? (async (msg: FormatMessageResponse) => {\n if (!activeChannel) return;\n try {\n await activeChannel.deleteMessage(msg.id!);\n } catch (err) {\n console.error('Failed to delete message', err);\n }\n });\n\n const onDeleteForMeHandler = onDeleteForMe ?? (async (msg: FormatMessageResponse) => {\n if (!activeChannel) return;\n try {\n await activeChannel.deleteMessageForMe(msg.id!);\n } catch (err) {\n console.error('Failed to delete message for me', err);\n }\n });\n\n const isOpen = anchorRect !== null;\n const onClose = useCallback(() => setAnchorRect(null), []);\n\n const handleMoreClick = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n setAnchorRect(rect);\n };\n\n const handleCopy = async () => {\n if (onCopy) {\n onCopy(message);\n } else if (message.text) {\n try {\n await navigator.clipboard.writeText(message.text);\n } catch (err) {\n console.error('Failed to copy text:', err);\n }\n }\n onClose();\n };\n\n return (\n <>\n <div className={`ermis-message-list__actions ${isOpen ? 'ermis-message-list__actions--active' : ''}`}>\n {actions.canReply && (\n <button \n className=\"ermis-message-list__actions-trigger\" \n onClick={() => onReply?.(message)} \n title=\"Reply\"\n disabled={!actions.hasCapReply}\n >\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M11.192 15.757c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L9.373 5c-1.368.647-2.525 1.612-3.468 2.895-.943 1.28-1.452 2.673-1.526 4.174-.015.228-.022.463-.022.705 0 1.594.417 2.9 1.25 3.918.835 1.019 1.955 1.53 3.36 1.53 1.048 0 1.903-.311 2.565-.933.66-.622.99-1.465.99-2.53zm10.455 0c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L19.828 5c-1.368.647-2.525 1.612-3.468 2.895-.943 1.28-1.452 2.673-1.526 4.174-.015.228-.022.463-.022.705 0 1.594.417 2.9 1.25 3.918.835 1.019 1.954 1.53 3.36 1.53 1.048 0 1.903-.311 2.565-.933.66-.622.99-1.465.99-2.53z\" />\n </svg>\n </button>\n )}\n {actions.canForward && (\n <button \n className=\"ermis-message-list__actions-trigger\" \n onClick={() => onForwardHandler(message)} \n title=\"Forward\"\n disabled={!actions.hasCapQuote}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 14 20 9 15 4\" />\n <path d=\"M4 20v-7a4 4 0 0 1 4-4h12\" />\n </svg>\n </button>\n )}\n <button\n className={`ermis-message-list__actions-trigger ${isOpen ? 'ermis-message-list__actions-trigger--active' : ''}`}\n onClick={handleMoreClick}\n title=\"More actions\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </button>\n </div>\n\n <Dropdown \n isOpen={isOpen} \n anchorRect={anchorRect} \n onClose={onClose} \n align={isOwnMessage ? 'right' : 'left'}\n >\n <div className=\"ermis-dropdown__menu\">\n {actions.canPin && (\n <button \n className=\"ermis-dropdown__item\" \n onClick={() => { onPinToggleHandler(message, actions.isPinned); onClose(); }}\n disabled={!actions.hasCapPin}\n >\n {actions.isPinned ? unpinLabel : pinLabel}\n </button>\n )}\n {actions.canEdit && (\n <button \n className=\"ermis-dropdown__item\" \n onClick={() => { onEditHandler(message); onClose(); }}\n disabled={!actions.hasCapEdit}\n >\n {editLabel}\n </button>\n )}\n {actions.canCopy && (\n <button className=\"ermis-dropdown__item\" onClick={handleCopy}>\n {copyLabel}\n </button>\n )}\n\n {(actions.canDelete || actions.canDeleteForMe) && <div className=\"ermis-dropdown__divider\" />}\n\n {actions.canDeleteForMe && (\n <button \n className=\"ermis-dropdown__item ermis-dropdown__item--danger\" \n onClick={() => { onDeleteForMeHandler(message); onClose(); }}\n disabled={!actions.hasCapDeleteForMe}\n >\n {deleteForMeLabel}\n </button>\n )}\n {actions.canDelete && (\n <button \n className=\"ermis-dropdown__item ermis-dropdown__item--danger\" \n onClick={() => { onDeleteForEveryoneHandler(message); onClose(); }}\n disabled={!actions.hasCapDelete}\n >\n {deleteForEveryoneLabel}\n </button>\n )}\n </div>\n </Dropdown>\n </>\n );\n};\n","import { useMemo } from 'react';\nimport { useChatClient } from './useChatClient';\nimport { useChannelCapabilities } from './useChannelCapabilities';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { isSignalMessage, isSystemMessage } from '../messageTypeUtils';\n\nexport type MessageActionList = {\n canEdit: boolean;\n canDelete: boolean;\n canDeleteForMe: boolean;\n canReply: boolean;\n canQuote: boolean;\n canForward: boolean;\n canPin: boolean;\n canCopy: boolean;\n isPinned: boolean;\n hasCapEdit: boolean;\n hasCapDelete: boolean;\n hasCapDeleteForMe: boolean;\n hasCapPin: boolean;\n hasCapReply: boolean;\n hasCapQuote: boolean;\n};\n\nexport const useMessageActions = (message: FormatMessageResponse, isOwnMessage: boolean): MessageActionList => {\n const { activeChannel, client } = useChatClient();\n const { isGroupChannel: isTeam, isOwner, hasCapability } = useChannelCapabilities();\n\n // Only depend on the specific message fields we actually read\n const messageType = message.type;\n const isPinnedFlag = message.pinned || !!message.pinned_at;\n\n return useMemo(() => {\n if (!activeChannel) {\n return {\n canEdit: false,\n canDelete: false,\n canDeleteForMe: false,\n canReply: false,\n canQuote: false,\n canForward: false,\n canPin: false,\n canCopy: false,\n isPinned: false,\n hasCapEdit: false,\n hasCapDelete: false,\n hasCapDeleteForMe: false,\n hasCapPin: false,\n hasCapReply: false,\n hasCapQuote: false,\n };\n }\n\n const isSystem = isSystemMessage(message);\n const isSignal = isSignalMessage(message);\n const isPinned = isPinnedFlag;\n\n const canEdit = !isSystem && !isSignal && isOwnMessage;\n\n // Delete for everyone:\n // + Team channel: only the owner can perform this action natively.\n // + Messaging channel: only own messages can be deleted\n const canDeleteForEveryoneTeam = isTeam && isOwner;\n const canDeleteForEveryoneMessaging = !isTeam && isOwnMessage;\n\n const canDelete = !isSystem && (canDeleteForEveryoneTeam || canDeleteForEveryoneMessaging);\n const canDeleteForMe = !isSystem;\n const canReply = !isSystem && !isSignal;\n const canQuote = !isSystem && !isSignal;\n const canForward = !isSystem && !isSignal;\n const canPin = !isSystem && !isSignal;\n const canCopy = !isSystem && !isSignal && Boolean(message.text?.trim());\n\n const hasCapEdit = hasCapability('update-own-message');\n const hasCapDelete = !isTeam || isOwner || (isOwnMessage && hasCapability('delete-own-message'));\n // Apply the delete-own-message capability to the \"delete for me\" action for own messages\n const hasCapDeleteForMe = !isTeam || isOwner || !isOwnMessage || hasCapability('delete-own-message');\n\n const hasCapReply = hasCapability('send-reply');\n const hasCapQuote = hasCapability('quote-message');\n const hasCapPin = hasCapability('pin-message');\n\n return {\n canEdit,\n canDelete,\n canDeleteForMe,\n canReply,\n canQuote,\n canForward,\n canPin,\n canCopy,\n isPinned,\n hasCapEdit,\n hasCapDelete,\n hasCapDeleteForMe,\n hasCapPin,\n hasCapReply,\n hasCapQuote,\n };\n }, [activeChannel, isTeam, isOwner, hasCapability, messageType, message.text, isPinnedFlag, isOwnMessage]); // Use capabilities from hook\n};\n","import { useState, useEffect, useCallback } from 'react';\nimport { useChatClient } from './useChatClient';\nimport { isGroupChannel } from '../channelTypeUtils';\nimport { canManageChannel, CHANNEL_ROLES } from '../channelRoleUtils';\n\nexport const useChannelCapabilities = () => {\n const { activeChannel, client } = useChatClient();\n const [updateTick, setUpdateTick] = useState(0);\n\n // Real-time synchronization for channel adjustments\n useEffect(() => {\n if (!activeChannel) return;\n const handleUpdate = () => setUpdateTick(t => t + 1);\n \n activeChannel.on('channel.updated', handleUpdate);\n return () => {\n activeChannel.off('channel.updated', handleUpdate);\n };\n }, [activeChannel]);\n\n const currentUserId = client?.userID || '';\n const isGroupCh = isGroupChannel(activeChannel);\n const role = (activeChannel?.state as any)?.members?.[currentUserId]?.channel_role;\n \n const isOwner = role === CHANNEL_ROLES.OWNER || activeChannel?.data?.created_by_id === currentUserId;\n const isModerator = role === CHANNEL_ROLES.MODERATOR;\n const isOwnerOrModerator = isOwner || isModerator || canManageChannel(role);\n\n const capabilities: string[] = isGroupCh ? (activeChannel?.data as any)?.member_capabilities || [] : [];\n\n const hasCapability = useCallback((cap: string) => {\n return !isGroupCh || isOwnerOrModerator || capabilities.includes(cap);\n }, [isGroupCh, isOwnerOrModerator, capabilities, updateTick]); // React to updateTick correctly\n\n return {\n isGroupChannel: isGroupCh,\n isOwner,\n isModerator,\n isOwnerOrModerator,\n hasCapability,\n role,\n capabilities\n };\n};\n","export const MESSAGE_TYPES = {\n REGULAR: 'regular',\n SYSTEM: 'system',\n STICKER: 'sticker',\n SIGNAL: 'signal',\n ERROR: 'error',\n} as const;\n\nexport const ATTACHMENT_TYPES = {\n IMAGE: 'image',\n VIDEO: 'video',\n VOICE_RECORDING: 'voiceRecording',\n LINK_PREVIEW: 'linkPreview',\n FILE: 'file',\n AUDIO: 'audio',\n} as const;\n\nexport type MessageType = (typeof MESSAGE_TYPES)[keyof typeof MESSAGE_TYPES] | string;\nexport type AttachmentType = (typeof ATTACHMENT_TYPES)[keyof typeof ATTACHMENT_TYPES] | string;\n\n// Helpers cho message\nexport function isSystemMessage(message: any): boolean {\n return message?.type === MESSAGE_TYPES.SYSTEM;\n}\n\nexport function isStickerMessage(message: any): boolean {\n return message?.type === MESSAGE_TYPES.STICKER;\n}\n\nexport function isRegularMessage(message: any): boolean {\n return !message?.type || message?.type === MESSAGE_TYPES.REGULAR;\n}\n\nexport function isSignalMessage(message: any): boolean {\n return message?.type === MESSAGE_TYPES.SIGNAL;\n}\n\n// Helpers cho attachment\nexport function isImageAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.IMAGE;\n}\n\nexport function isVideoAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.VIDEO;\n}\n\nexport function isVoiceRecordingAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.VOICE_RECORDING;\n}\n\nexport function isLinkPreviewAttachment(attachment: any): boolean {\n return attachment?.type === ATTACHMENT_TYPES.LINK_PREVIEW;\n}\n\nexport function isImage(attachment: any): boolean {\n return Boolean(\n isImageAttachment(attachment) ||\n (!attachment?.type && (attachment?.mime_type?.startsWith('image/') || attachment?.image_url)),\n );\n}\n\nexport function isVideo(attachment: any): boolean {\n return !!(isVideoAttachment(attachment) || (!attachment.type && attachment.mime_type?.startsWith('video/')));\n}\n","import React from 'react';\nimport type { MessageReactionsProps } from '../types';\n\nimport { useChatClient } from '../hooks/useChatClient';\n\nconst defaultReactionEmojiMap: Record<string, string> = {\n like: '👍',\n love: '❤️',\n haha: '😂',\n sad: '😢',\n fire: '🔥',\n};\n\nexport const MessageReactions: React.FC<MessageReactionsProps> = React.memo(({\n reactionCounts,\n ownReactions,\n latestReactions,\n onClickReaction,\n disabled,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n\n if (!reactionCounts || Object.keys(reactionCounts).length === 0) return null;\n\n return (\n <div className={`ermis-message-reactions${disabled ? ' ermis-message-reactions--disabled' : ''}`}>\n {Object.entries(reactionCounts).map(([type, count]) => {\n const isOwn = \n ownReactions?.some((r) => r.type === type) ||\n latestReactions?.some((r) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId));\n \n // Find users who reacted with this type for the tooltip\n const rawUserNames = latestReactions\n ?.filter((r) => r.type === type)\n .map((r: any) => r.user?.name || r.user?.id || r.user_id || 'Someone');\n \n const userNames = Array.from(new Set(rawUserNames || []))\n .map((n: any) => typeof n === 'string' ? n.replace(/‎|\\u200E/gi, '').trim() : n)\n .filter(Boolean);\n\n const tooltip = userNames.length > 0 ? userNames.join(', ') : type;\n const emoji = defaultReactionEmojiMap[type] || type;\n\n return (\n <button\n key={type}\n className={`ermis-message-reactions__item ${\n isOwn ? 'ermis-message-reactions__item--active' : ''\n }`}\n data-tooltip={tooltip}\n onClick={() => onClickReaction?.(type)}\n type=\"button\"\n >\n <span className=\"ermis-message-reactions__emoji\">{emoji}</span>\n <span className=\"ermis-message-reactions__count\">{count}</span>\n </button>\n );\n })}\n </div>\n );\n});\n\nMessageReactions.displayName = 'MessageReactions';\n","import React, { useCallback } from 'react';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\n\nconst QUICK_REACTIONS = ['like', 'love', 'haha', 'sad', 'fire'];\nconst EMOJI_MAP: Record<string, string> = {\n like: '👍',\n love: '❤️',\n haha: '😂',\n sad: '😢',\n fire: '🔥',\n};\n\nexport const MessageQuickReactions: React.FC<{\n message: FormatMessageResponse;\n isOwnMessage: boolean;\n disabled?: boolean;\n}> = React.memo(({ message, isOwnMessage, disabled }) => {\n const { activeChannel, client } = useChatClient();\n const currentUserId = client?.userID;\n\n const handleReactionToggle = useCallback(\n async (type: string) => {\n if (!activeChannel) return;\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some(\n (r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId)\n );\n\n try {\n if (isOwn) {\n await activeChannel.deleteReaction(message.id!, type);\n } else {\n await activeChannel.sendReaction(message.id!, type);\n }\n } catch (err) {\n console.error('Failed to toggle reaction', err);\n }\n },\n [activeChannel, message, currentUserId]\n );\n\n return (\n <div className={`ermis-message-quick-reactions ${isOwnMessage ? 'ermis-message-quick-reactions--own' : ''} ${disabled ? 'ermis-message-quick-reactions--disabled' : ''}`}>\n {QUICK_REACTIONS.map((type) => {\n const isOwn =\n (message as any).own_reactions?.some((r: any) => r.type === type) ||\n (message as any).latest_reactions?.some(\n (r: any) => r.type === type && (r.user?.id === currentUserId || (r as any).user_id === currentUserId)\n );\n\n return (\n <button\n key={type}\n className={`ermis-message-quick-reactions__btn ${\n isOwn ? 'ermis-message-quick-reactions__btn--active' : ''\n }`}\n title={type}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n handleReactionToggle(type);\n }}\n >\n {EMOJI_MAP[type]}\n </button>\n );\n })}\n </div>\n );\n});\n\nMessageQuickReactions.displayName = 'MessageQuickReactions';\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { preloadImage, isImagePreloaded } from '../utils';\nimport type { FormatMessageResponse, Attachment, MessageLabel } from '@ermis-network/ermis-chat-sdk';\nimport { parseSystemMessage, parseSignalMessage, CallType } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { buildUserMap } from '../utils';\nimport { MediaLightbox } from './MediaLightbox';\nimport { getFileIcon } from './ChannelInfo/utils';\nimport type { AttachmentProps, MessageRendererProps, MessageBubbleProps, MediaLightboxItem } from '../types';\n\nexport type { AttachmentProps, MessageRendererProps, MessageBubbleProps } from '../types';\nimport {\n isVoiceRecordingAttachment,\n isLinkPreviewAttachment,\n isImage,\n isVideo\n} from '../messageTypeUtils';\n\n/* ----------------------------------------------------------\n Attachment renderers\n ---------------------------------------------------------- */\nconst ImageAttachment: React.FC<AttachmentProps> = React.memo(({ attachment, onClick }) => {\n const src = attachment.image_url || attachment.thumb_url || attachment.url;\n const thumbSrc = attachment.thumb_url;\n if (!src) return null;\n\n const alreadyCached = isImagePreloaded(src);\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Trigger background preload (no-op if already cached)\n useMemo(() => { preloadImage(src); }, [src]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, src]);\n\n const clickable = Boolean(onClick);\n\n return (\n <div\n className={`ermis-attachment-aspect-box ermis-attachment-aspect-box--4-3${clickable ? ' ermis-attachment--clickable' : ''}`}\n onClick={onClick}\n role={clickable ? 'button' : undefined}\n tabIndex={clickable ? 0 : undefined}\n >\n {/* Blur placeholder: use thumb if available, otherwise shimmer */}\n {!loaded && (\n thumbSrc && thumbSrc !== src ? (\n <img\n className=\"ermis-attachment-blur-preview\"\n src={thumbSrc}\n alt=\"\"\n aria-hidden\n />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n )\n )}\n <img\n ref={imgRef}\n className={`ermis-attachment ermis-attachment--image${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n alt={attachment.file_name || attachment.title || 'image'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n {clickable && (\n <div className=\"ermis-attachment__overlay\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </svg>\n </div>\n )}\n </div>\n );\n}, (prev, next) => {\n const prevSrc = prev.attachment.image_url || prev.attachment.thumb_url || prev.attachment.url;\n const nextSrc = next.attachment.image_url || next.attachment.thumb_url || next.attachment.url;\n return prevSrc === nextSrc && prev.onClick === next.onClick;\n});\n(ImageAttachment as any).displayName = 'ImageAttachment';\n\nconst VideoAttachment: React.FC<AttachmentProps> = React.memo(({ attachment, onClick }) => {\n const src = attachment.asset_url || attachment.url;\n const posterSrc = attachment.image_url || attachment.thumb_url;\n const blurThumb = attachment.thumb_url;\n if (!src) return null;\n\n const alreadyCached = posterSrc ? isImagePreloaded(posterSrc) : true;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (posterSrc) preloadImage(posterSrc);\n }, [posterSrc]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, posterSrc]);\n\n const clickable = Boolean(onClick);\n\n // When clickable (lightbox mode): show poster thumbnail + play icon overlay\n if (clickable) {\n return (\n <div\n className=\"ermis-attachment-aspect-box ermis-attachment-aspect-box--4-3 ermis-attachment--clickable\"\n onClick={onClick}\n role=\"button\"\n tabIndex={0}\n >\n {!loaded && (\n blurThumb && blurThumb !== posterSrc ? (\n <img className=\"ermis-attachment-blur-preview\" src={blurThumb} alt=\"\" aria-hidden />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n )\n )}\n {posterSrc ? (\n <img\n ref={imgRef}\n className={`ermis-attachment ermis-attachment--video-poster${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={posterSrc}\n alt={attachment.file_name || 'video'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n ) : (\n <video\n className={`ermis-attachment ermis-attachment--video${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n preload=\"metadata\"\n onLoadedData={() => setLoaded(true)}\n />\n )}\n <div className=\"ermis-attachment__overlay\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </div>\n </div>\n );\n }\n\n // Default inline video player (no lightbox)\n return (\n <div className=\"ermis-attachment-aspect-box ermis-attachment-aspect-box--4-3\">\n {!loaded && (\n blurThumb && blurThumb !== posterSrc ? (\n <img\n className=\"ermis-attachment-blur-preview\"\n src={blurThumb}\n alt=\"\"\n aria-hidden\n />\n ) : (\n <div className=\"ermis-attachment-shimmer\" />\n )\n )}\n {posterSrc && !loaded && (\n <img\n ref={imgRef}\n src={posterSrc}\n className=\"ermis-attachment--hidden-loader\"\n onLoad={() => setLoaded(true)}\n alt=\"poster-loader\"\n />\n )}\n <video\n className={`ermis-attachment ermis-attachment--video${loaded || !posterSrc ? ' ermis-attachment--loaded' : ''}`}\n src={src}\n poster={posterSrc}\n controls\n preload=\"metadata\"\n onLoadedData={() => {\n if (!posterSrc) setLoaded(true);\n }}\n />\n </div>\n );\n}, (prev, next) => {\n return (prev.attachment.asset_url || prev.attachment.url) ===\n (next.attachment.asset_url || next.attachment.url) && prev.onClick === next.onClick;\n});\n(VideoAttachment as any).displayName = 'VideoAttachment';\n\nconst FileAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const url = attachment.url || attachment.asset_url;\n const name = attachment.file_name || attachment.title || 'File';\n const size = attachment.file_size;\n const mimeType = attachment.mime_type || attachment.type || '';\n const ext = name.split('.').pop()?.toUpperCase() || 'FILE';\n const { client } = useChatClient();\n\n const handleDownload = useCallback(async (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!url) return;\n\n try {\n const blob = await client.downloadMedia(url);\n const urlBlob = window.URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = urlBlob;\n a.download = name;\n document.body.appendChild(a);\n a.click();\n a.remove();\n window.URL.revokeObjectURL(urlBlob);\n } catch {\n window.open(url, '_blank', 'noopener,noreferrer');\n }\n }, [client, url, name]);\n\n return (\n <div className=\"ermis-attachment ermis-attachment--file\">\n <span className=\"ermis-attachment__file-icon\">\n {getFileIcon(mimeType, name)}\n <span className=\"ermis-attachment__file-ext\">{ext}</span>\n </span>\n <span className=\"ermis-attachment__file-info\">\n <span className=\"ermis-attachment__file-name\">{name}</span>\n {size && (\n <span className=\"ermis-attachment__file-size\">\n {typeof size === 'number' ? `${(size / 1024).toFixed(1)} KB` : size}\n </span>\n )}\n </span>\n <button\n className=\"ermis-attachment__file-download\"\n onClick={handleDownload}\n title=\"Download\"\n type=\"button\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n </div>\n );\n}, (prev, next) => {\n return (prev.attachment.url || prev.attachment.asset_url) ===\n (next.attachment.url || next.attachment.asset_url);\n});\n(FileAttachment as any).displayName = 'FileAttachment';\n\nconst VoiceRecordingAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const src = attachment.asset_url || attachment.url;\n if (!src) return null;\n\n const durationSec = attachment.duration ?? 0;\n const mins = Math.floor(durationSec / 60);\n const secs = Math.round(durationSec % 60);\n const durationLabel = `${mins}:${secs.toString().padStart(2, '0')}`;\n\n return (\n <div className=\"ermis-attachment ermis-attachment--voice\">\n <span className=\"ermis-attachment__voice-icon\">🎙️</span>\n <audio src={src} controls preload=\"metadata\" className=\"ermis-attachment__voice-player\" />\n <span className=\"ermis-attachment__voice-duration\">{durationLabel}</span>\n </div>\n );\n}, (prev, next) => {\n return (prev.attachment.asset_url || prev.attachment.url) ===\n (next.attachment.asset_url || next.attachment.url);\n});\n(VoiceRecordingAttachment as any).displayName = 'VoiceRecordingAttachment';\n\nconst LinkPreviewAttachment: React.FC<AttachmentProps> = React.memo(({ attachment }) => {\n const url = attachment.link_url || attachment.og_scrape_url || attachment.title_link || attachment.url;\n const title = attachment.title;\n const description = attachment.text;\n const image = attachment.image_url;\n\n const alreadyCached = image ? isImagePreloaded(image) : false;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (image) preloadImage(image);\n }, [image]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, image]);\n\n if (!title) return null;\n\n return (\n <a\n className=\"ermis-attachment ermis-attachment--link-preview\"\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {image && (\n <div className=\"ermis-attachment__link-image-wrapper\">\n {!loaded && <div className=\"ermis-attachment-shimmer\" />}\n <img\n ref={imgRef}\n className={`ermis-attachment__link-image${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={image}\n alt={title || 'preview'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n </div>\n )}\n <div className=\"ermis-attachment__link-info\">\n {title && <span className=\"ermis-attachment__link-title\">{title}</span>}\n {description && <span className=\"ermis-attachment__link-description\">{description}</span>}\n {url && (\n <span className=\"ermis-attachment__link-url\">\n {new URL(url).hostname}\n </span>\n )}\n </div>\n </a>\n );\n}, (prev, next) => {\n return (prev.attachment.link_url || prev.attachment.og_scrape_url || prev.attachment.url) ===\n (next.attachment.link_url || next.attachment.og_scrape_url || next.attachment.url);\n});\n(LinkPreviewAttachment as any).displayName = 'LinkPreviewAttachment';\n\nexport const MessageAttachment: React.FC<AttachmentProps> = ({ attachment }) => {\n if (isImage(attachment)) return <ImageAttachment attachment={attachment} />;\n if (isVideo(attachment)) return <VideoAttachment attachment={attachment} />;\n if (isVoiceRecordingAttachment(attachment)) return <VoiceRecordingAttachment attachment={attachment} />;\n if (isLinkPreviewAttachment(attachment)) return <LinkPreviewAttachment attachment={attachment} />;\n return <FileAttachment attachment={attachment} />;\n};\n\nexport const AttachmentList: React.FC<{ attachments?: Attachment[] }> = React.memo(({ attachments }) => {\n if (!attachments || attachments.length === 0) return null;\n\n // Group by type\n const media = attachments.filter((a) => isImage(a) || isVideo(a));\n const files = attachments.filter((a) => !isImage(a) && !isVideo(a) && !isVoiceRecordingAttachment(a) && !isLinkPreviewAttachment(a));\n const voices = attachments.filter(isVoiceRecordingAttachment);\n const links = attachments.filter(isLinkPreviewAttachment);\n\n // Lightbox state\n const [lightboxOpen, setLightboxOpen] = useState(false);\n const [lightboxIndex, setLightboxIndex] = useState(0);\n\n // Build lightbox items from media attachments\n const lightboxItems = useMemo<MediaLightboxItem[]>(() => {\n return media.map(att => {\n if (isImage(att)) {\n return {\n type: 'image' as const,\n src: att.image_url || att.thumb_url || att.url || '',\n alt: att.file_name || att.title,\n };\n }\n return {\n type: 'video' as const,\n src: att.asset_url || att.url || '',\n alt: att.file_name || att.title,\n posterSrc: att.image_url || att.thumb_url,\n };\n });\n }, [media]);\n\n const openLightbox = useCallback((index: number) => {\n setLightboxIndex(index);\n setLightboxOpen(true);\n }, []);\n\n const closeLightbox = useCallback(() => {\n setLightboxOpen(false);\n }, []);\n\n const mediaGridClass = media.length === 1\n ? 'ermis-attachment-grid ermis-attachment-grid--single'\n : 'ermis-attachment-grid ermis-attachment-grid--multi';\n\n return (\n <div className=\"ermis-attachment-list\">\n {/* Media group: images + videos in grid */}\n {media.length > 0 && (\n <div className={mediaGridClass}>\n {media.map((att, i) => (\n isImage(att)\n ? <ImageAttachment key={att.id || `img-${i}`} attachment={att} onClick={() => openLightbox(i)} />\n : <VideoAttachment key={att.id || `vid-${i}`} attachment={att} onClick={() => openLightbox(i)} />\n ))}\n </div>\n )}\n {/* File group */}\n {files.map((att, i) => (\n <FileAttachment key={att.id || `file-${i}`} attachment={att} />\n ))}\n {/* Voice recording group */}\n {voices.map((att, i) => (\n <VoiceRecordingAttachment key={att.id || `voice-${i}`} attachment={att} />\n ))}\n {/* Link preview group */}\n {links.map((att, i) => (\n <LinkPreviewAttachment key={att.id || `link-${i}`} attachment={att} />\n ))}\n\n {/* Media Lightbox */}\n {lightboxItems.length > 0 && (\n <MediaLightbox\n items={lightboxItems}\n initialIndex={lightboxIndex}\n isOpen={lightboxOpen}\n onClose={closeLightbox}\n />\n )}\n </div>\n );\n}, (prev, next) => {\n // Skip re-render if same attachment array reference\n if (prev.attachments === next.attachments) return true;\n if (!prev.attachments || !next.attachments) return false;\n if (prev.attachments.length !== next.attachments.length) return false;\n return prev.attachments.every((a, i) => a.id === next.attachments![i].id);\n});\n(AttachmentList as any).displayName = 'AttachmentList';\n\n/* ----------------------------------------------------------\n Message renderers by MessageLabel type\n ---------------------------------------------------------- */\n\n/**\n * Detect URLs and emails in plain text, wrapping them in <a> tags.\n * Returns an array of React nodes (strings and link elements).\n */\nconst URL_REGEX = /(https?:\\/\\/[^\\s<>]+|www\\.[^\\s<>]+|[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,})/g;\n\nfunction linkifyText(text: string, keyPrefix: string): React.ReactNode[] {\n const parts = text.split(URL_REGEX);\n if (parts.length === 1) return [text];\n\n return parts.map((part, i) => {\n if (URL_REGEX.test(part)) {\n // Reset lastIndex since we reuse the regex\n URL_REGEX.lastIndex = 0;\n const isEmail = part.includes('@') && !part.startsWith('http');\n const href = isEmail ? `mailto:${part}` : (part.startsWith('http') ? part : `https://${part}`);\n return (\n <a\n key={`${keyPrefix}-link-${i}`}\n className=\"ermis-text-link\"\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {part}\n </a>\n );\n }\n // Reset lastIndex\n URL_REGEX.lastIndex = 0;\n return part;\n });\n}\n\n/**\n * Parse message text: render @mentions as highlighted spans,\n * and auto-detect URLs/emails in non-mention text parts.\n */\nfunction renderTextWithMentions(\n text: string,\n message: FormatMessageResponse,\n userMap: Record<string, string>,\n): React.ReactNode {\n const mentionedUsers: string[] = (message as any).mentioned_users ?? [];\n const mentionedAll: boolean = (message as any).mentioned_all ?? false;\n\n // If no mentions, just linkify the text\n if (mentionedUsers.length === 0 && !mentionedAll) {\n return linkifyText(text, 'txt');\n }\n\n // Build a list of patterns to replace: @userId → @userName\n const replacements: { pattern: string; label: string }[] = [];\n\n for (const userId of mentionedUsers) {\n replacements.push({\n pattern: `@${userId}`,\n label: `@${userMap[userId] ?? userId}`,\n });\n }\n\n if (mentionedAll) {\n replacements.push({ pattern: '@all', label: '@all' });\n }\n\n // Build a regex that matches any of the mention patterns\n const escaped = replacements.map((r) =>\n r.pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n );\n const regex = new RegExp(`(${escaped.join('|')})`, 'g');\n\n const parts = text.split(regex);\n\n // Map from pattern → label for quick lookup\n const patternToLabel = new Map(replacements.map((r) => [r.pattern, r.label]));\n\n return parts.flatMap((part, i) => {\n const label = patternToLabel.get(part);\n if (label) {\n // Mention — render as span, do NOT linkify\n return (\n <span key={`mention-${i}`} className=\"ermis-mention\">\n {label}\n </span>\n );\n }\n // Non-mention text — linkify URLs/emails\n return linkifyText(part, `p${i}`);\n });\n}\n\n/** Regular message: text with @mentions + attachments */\nexport const RegularMessage: React.FC<MessageRendererProps> = React.memo(({ message }) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n const textContent = message.text\n ? renderTextWithMentions(message.text, message, userMap)\n : null;\n\n const attachmentsToRender = useMemo(() => {\n if (!message.attachments || message.attachments.length === 0) return [];\n\n const text = (message.text || '').trim();\n const URL_REGEX_STRICT = /^(https?:\\/\\/[^\\s<>]+|www\\.[^\\s<>]+)$/;\n const isOnlyUrl = URL_REGEX_STRICT.test(text);\n\n return message.attachments.filter(att => {\n if (isLinkPreviewAttachment(att)) return isOnlyUrl;\n return true;\n });\n }, [message.attachments, message.text]);\n\n const hasAttachments = attachmentsToRender.length > 0;\n\n if (hasAttachments) {\n return (\n <div className=\"ermis-message-content--with-attachments\">\n {textContent && (\n <span className=\"ermis-message-list__item-text\">{textContent}</span>\n )}\n <AttachmentList attachments={attachmentsToRender} />\n </div>\n );\n }\n\n return (\n <>\n {textContent && (\n <span className=\"ermis-message-list__item-text\">{textContent}</span>\n )}\n </>\n );\n}, (prev, next) => {\n return prev.message.id === next.message.id &&\n prev.message.updated_at === next.message.updated_at &&\n prev.message.text === next.message.text &&\n prev.isOwnMessage === next.isOwnMessage;\n});\nRegularMessage.displayName = 'RegularMessage';\n\n/** System message: centered info text, parsed from raw format */\nexport const SystemMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n const parsedText = useMemo(\n () => (message.text ? parseSystemMessage(message.text, userMap) : ''),\n [message.text, userMap],\n );\n\n return (\n <span className=\"ermis-message-list__system-text\">\n {parsedText || message.text}\n </span>\n );\n};\n\n/** Signal message: call events */\nexport const SignalMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const { client } = useChatClient();\n\n const rawText = message.text ?? '';\n const result = rawText ? parseSignalMessage(rawText, client.userID || '') : null;\n\n if (!result) {\n return (\n <span className=\"ermis-message-list__signal-text\">\n {rawText}\n </span>\n );\n }\n\n const isSuccess = !!result.duration;\n const colorModifier = isSuccess ? 'success' : 'missed';\n const isAudio = result.callType === CallType.AUDIO;\n\n return (\n <div className=\"ermis-signal-message\">\n <div className={`ermis-signal-message__icon ermis-signal-message__icon--${colorModifier}`}>\n {isAudio ? (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\" />\n </svg>\n ) : (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"23 7 16 12 23 17 23 7\" />\n <rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\" ry=\"2\" />\n </svg>\n )}\n </div>\n <div className=\"ermis-signal-message__body\">\n <span className={`ermis-signal-message__text ermis-signal-message__text--${colorModifier}`}>\n {result.text}\n </span>\n {result.duration && (\n <span className=\"ermis-signal-message__duration\">{result.duration}</span>\n )}\n </div>\n </div>\n );\n};\n\n/** Poll message */\nexport const PollMessage: React.FC<MessageRendererProps> = ({ message }) => (\n <div className=\"ermis-message-poll\">\n <span className=\"ermis-message-poll__icon\">📊</span>\n <span className=\"ermis-message-poll__text\">{message.text || 'Poll'}</span>\n </div>\n);\n\n/** Sticker message */\nexport const StickerMessage: React.FC<MessageRendererProps> = ({ message }) => {\n const stickerUrl = (message as any).sticker_url;\n\n const alreadyCached = stickerUrl ? isImagePreloaded(stickerUrl) : false;\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => {\n if (stickerUrl) preloadImage(stickerUrl);\n }, [stickerUrl]);\n\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, stickerUrl]);\n\n if (stickerUrl) {\n return (\n <div className=\"ermis-message-sticker-wrapper\">\n {!loaded && <div className=\"ermis-attachment-shimmer\" />}\n <img\n ref={imgRef}\n className={`ermis-message-sticker${loaded ? ' ermis-attachment--loaded' : ''}`}\n src={stickerUrl}\n alt=\"sticker\"\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n />\n </div>\n );\n }\n return <span className=\"ermis-message-list__item-text\">{message.text}</span>;\n};\n\n/** Error message */\nexport const ErrorMessage: React.FC<MessageRendererProps> = ({ message }) => (\n <span className=\"ermis-message-error\">{message.text || 'Message failed'}</span>\n);\n\n/**\n * Map from MessageLabel → component.\n * Consumer can override individual renderers via the `messageRenderers` prop.\n */\nexport const defaultMessageRenderers: Record<\n MessageLabel,\n React.ComponentType<MessageRendererProps>\n> = {\n regular: RegularMessage,\n system: SystemMessage,\n signal: SignalMessage,\n poll: PollMessage,\n sticker: StickerMessage,\n error: ErrorMessage,\n};\n","import React from 'react';\nimport type { MediaTab } from '../../types';\n\nexport function getFileIcon(contentType: string, fileName: string): React.ReactNode {\n const ext = fileName.split('.').pop()?.toLowerCase() || '';\n\n if (contentType.includes('pdf') || ext === 'pdf') {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\" />\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\" />\n <polyline points=\"10 9 9 9 8 9\" />\n </svg>\n );\n }\n\n if (contentType.includes('zip') || contentType.includes('rar') || contentType.includes('archive') || ['zip', 'rar', '7z', 'tar', 'gz'].includes(ext)) {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 8v13H3V3h13\" />\n <path d=\"M16 3v5h5\" />\n <path d=\"M10 12h4M10 16h4M10 8h1\" />\n </svg>\n );\n }\n\n // Default file icon\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n );\n}\n\nexport const ROLE_WEIGHTS: Record<string, number> = {\n owner: 4,\n moder: 3,\n member: 2,\n pending: 1,\n};\n\nexport const MESSAGING_TABS: MediaTab[] = ['media', 'links', 'files'];\nexport const ALL_TABS: MediaTab[] = ['members', 'media', 'links', 'files'];\n\nexport const PENDING_STYLE = { opacity: 0.7, transition: 'opacity 0.15s ease' } as const;\nexport const READY_STYLE = { opacity: 1, transition: 'opacity 0.15s ease' } as const;\n","import React, { useState, useEffect, useMemo, useCallback } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { isStickerMessage } from '../messageTypeUtils';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { PinnedMessageItemProps, PinnedMessagesProps } from '../types';\n\n/* ----------------------------------------------------------\n Default PinnedMessageItem\n ---------------------------------------------------------- */\nconst DefaultPinnedMessageItem: React.FC<PinnedMessageItemProps> = React.memo(({\n message,\n isOwnMessage,\n onClickMessage,\n onUnpin,\n AvatarComponent,\n}) => {\n const { activeChannel } = useChatClient();\n const userName = message.user?.name || message.user_id || 'Unknown';\n const userAvatar = message.user?.avatar;\n const hasAttachments = message.attachments && message.attachments.length > 0;\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel?.state]);\n\n let previewText = message.text || '';\n const isSticker = isStickerMessage(message);\n\n if (!previewText && hasAttachments) {\n const firstAttach = message.attachments![0];\n previewText = firstAttach.title || `${firstAttach.type || 'file'}`;\n } else if (isSticker) {\n previewText = 'Sticker';\n }\n\n // Convert @userId → @UserName in preview text\n if (previewText) {\n previewText = replaceMentionsForPreview(previewText, message, userMap);\n }\n\n // Attachment icon prefix\n let attachIcon = '';\n if (hasAttachments) {\n const type = message.attachments![0].type;\n if (type === 'image') attachIcon = '📷 ';\n else if (type === 'video') attachIcon = '🎥 ';\n else if (type === 'audio') attachIcon = '🎵 ';\n else attachIcon = '📄 ';\n } else if (isSticker) {\n attachIcon = '😀 ';\n }\n\n return (\n <div\n className={`ermis-pinned-messages__item ${isOwnMessage ? 'ermis-pinned-messages__item--own' : ''}`}\n onClick={() => onClickMessage?.(message.id)}\n role=\"button\"\n tabIndex={0}\n >\n <AvatarComponent image={userAvatar} name={userName} size={28} />\n <div className=\"ermis-pinned-messages__item-content\">\n <span className=\"ermis-pinned-messages__item-user\">{userName}</span>\n <span className=\"ermis-pinned-messages__item-text\">{attachIcon}{previewText || 'Attachment'}</span>\n </div>\n <button\n className=\"ermis-pinned-messages__unpin-btn\"\n onClick={(e) => { e.stopPropagation(); onUnpin?.(message.id); }}\n title=\"Unpin message\"\n aria-label=\"Unpin message\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"2\" y1=\"2\" x2=\"22\" y2=\"22\" />\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n </button>\n </div>\n );\n});\nDefaultPinnedMessageItem.displayName = 'DefaultPinnedMessageItem';\n\n/* ----------------------------------------------------------\n PinnedMessages component\n ---------------------------------------------------------- */\nexport const PinnedMessages: React.FC<PinnedMessagesProps> = React.memo(({\n className,\n AvatarComponent = Avatar,\n PinnedMessageItemComponent = DefaultPinnedMessageItem,\n onClickMessage,\n maxCollapsed = 1,\n}) => {\n const { activeChannel, client, messages } = useChatClient();\n const [expanded, setExpanded] = useState(false);\n const currentUserId = client.userID;\n\n // Reset expanded state when switching channels\n useEffect(() => {\n setExpanded(false);\n }, [activeChannel]);\n\n const pinnedMessages = useMemo<FormatMessageResponse[]>(() => {\n if (!activeChannel) return [];\n const pinned = (activeChannel.state as any)?.pinnedMessages;\n return Array.isArray(pinned) ? pinned : [];\n }, [activeChannel, messages]);\n\n const toggleExpanded = useCallback(() => {\n setExpanded((prev) => !prev);\n }, []);\n\n const handleUnpin = useCallback(async (messageId: string) => {\n if (!activeChannel) return;\n try {\n await activeChannel.unpinMessage(messageId);\n } catch (err) {\n console.error('Failed to unpin message', err);\n }\n }, [activeChannel]);\n\n if (pinnedMessages.length === 0) return null;\n\n const displayedMessages = expanded\n ? pinnedMessages\n : pinnedMessages.slice(0, maxCollapsed);\n\n const hasMore = pinnedMessages.length > maxCollapsed;\n\n return (\n <div className={`ermis-pinned-messages${expanded ? ' ermis-pinned-messages--expanded' : ''}${className ? ` ${className}` : ''}`}>\n {/* Header bar */}\n <div className=\"ermis-pinned-messages__header\" onClick={toggleExpanded}>\n <svg className=\"ermis-pinned-messages__icon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z\" />\n </svg>\n <span className=\"ermis-pinned-messages__label\">\n {pinnedMessages.length} pinned message{pinnedMessages.length > 1 ? 's' : ''}\n </span>\n {hasMore && (\n <button\n className=\"ermis-pinned-messages__toggle\"\n onClick={(e) => { e.stopPropagation(); toggleExpanded(); }}\n >\n {expanded ? 'Collapse' : 'See all'}\n </button>\n )}\n </div>\n\n {/* Pinned message list */}\n <div className=\"ermis-pinned-messages__list\">\n {displayedMessages.map((msg) => (\n <PinnedMessageItemComponent\n key={msg.id}\n message={msg}\n isOwnMessage={msg.user_id === currentUserId || msg.user?.id === currentUserId}\n onClickMessage={onClickMessage}\n onUnpin={handleUnpin}\n AvatarComponent={AvatarComponent}\n />\n ))}\n </div>\n </div>\n );\n});\n\nPinnedMessages.displayName = 'PinnedMessages';\n","import React from 'react';\nimport type { ReadReceiptsProps, ReadReceiptsTooltipProps } from '../types';\nimport { Avatar } from './Avatar';\nimport { formatReadTimestamp } from '../utils';\n\nexport type { ReadReceiptsProps, ReadReceiptsTooltipProps } from '../types';\n\n/* ----------------------------------------------------------\n Default Tooltip — shown on hover\n ---------------------------------------------------------- */\nconst DefaultReadReceiptsTooltip: React.FC<ReadReceiptsTooltipProps> = React.memo(({\n readers,\n AvatarComponent,\n}) => (\n <div className=\"ermis-read-receipts__tooltip-wrapper\">\n <div className=\"ermis-read-receipts__tooltip\">\n {readers.map((reader) => (\n <div key={reader.id} className=\"ermis-read-receipts__tooltip-item\">\n <AvatarComponent\n image={reader.avatar}\n name={reader.name || reader.id}\n size={20}\n />\n <div className=\"ermis-read-receipts__tooltip-info\">\n <span className=\"ermis-read-receipts__tooltip-name\">{reader.name || reader.id}</span>\n <span className=\"ermis-read-receipts__tooltip-time\">{formatReadTimestamp(reader.last_read)}</span>\n </div>\n </div>\n ))}\n </div>\n </div>\n));\nDefaultReadReceiptsTooltip.displayName = 'DefaultReadReceiptsTooltip';\n\n/* ----------------------------------------------------------\n ReadReceipts — main component\n ---------------------------------------------------------- */\nexport const ReadReceipts: React.FC<ReadReceiptsProps> = React.memo(({\n readers,\n maxAvatars = 5,\n AvatarComponent = Avatar,\n TooltipComponent = DefaultReadReceiptsTooltip,\n showTooltip = true,\n}) => {\n // Only render when there are actual readers (avatar-based display)\n // Sent/Sending/Error status icons are now rendered inline inside the message bubble\n if (!readers || readers.length === 0) {\n return null;\n }\n\n const visible = readers.slice(0, maxAvatars);\n const overflow = readers.length - maxAvatars;\n\n return (\n <div className=\"ermis-read-receipts\">\n <div className=\"ermis-read-receipts__avatars\">\n {visible.map((reader) => (\n <AvatarComponent\n key={reader.id}\n image={reader.avatar}\n name={reader.name || reader.id}\n size={16}\n className=\"ermis-read-receipts__avatar\"\n />\n ))}\n {overflow > 0 && (\n <span className=\"ermis-read-receipts__overflow\">+{overflow}</span>\n )}\n {showTooltip && (\n <TooltipComponent\n readers={readers}\n AvatarComponent={AvatarComponent}\n />\n )}\n </div>\n </div>\n );\n});\n\nReadReceipts.displayName = 'ReadReceipts';\n","import React from 'react';\nimport { useTypingIndicator, type TypingUser } from '../hooks/useTypingIndicator';\n\nexport type TypingIndicatorProps = {\n /** Custom render function for the typing text */\n renderText?: (users: TypingUser[]) => React.ReactNode;\n};\n\n/**\n * Displays a \"X is typing...\" indicator below the message list.\n * Automatically subscribes to typing events via the useTypingIndicator hook.\n */\nexport const TypingIndicator: React.FC<TypingIndicatorProps> = React.memo(({ renderText }) => {\n const { typingUsers } = useTypingIndicator();\n\n const isActive = typingUsers.length > 0;\n\n const text = isActive\n ? (renderText ? renderText(typingUsers) : formatTypingText(typingUsers))\n : null;\n\n return (\n <div className={`ermis-typing-indicator${isActive ? ' ermis-typing-indicator--active' : ''}`}>\n {isActive && (\n <>\n <div className=\"ermis-typing-indicator__dots\">\n <span className=\"ermis-typing-indicator__dot\" />\n <span className=\"ermis-typing-indicator__dot\" />\n <span className=\"ermis-typing-indicator__dot\" />\n </div>\n <span className=\"ermis-typing-indicator__text\">{text}</span>\n </>\n )}\n </div>\n );\n});\n\nTypingIndicator.displayName = 'TypingIndicator';\n\n/**\n * Format typing text based on number of users:\n * - 1 user: \"Alice is typing...\"\n * - 2 users: \"Alice and Bob are typing...\"\n * - 3+ users: \"Alice, Bob and 2 others are typing...\"\n */\nfunction formatTypingText(users: TypingUser[]): string {\n const names = users.map((u) => u.name || u.id);\n\n if (names.length === 1) {\n return `${names[0]} is typing...`;\n }\n if (names.length === 2) {\n return `${names[0]} and ${names[1]} are typing...`;\n }\n const remaining = names.length - 2;\n return `${names[0]}, ${names[1]} and ${remaining} other${remaining > 1 ? 's' : ''} are typing...`;\n}\n","import { useState, useEffect, useRef } from 'react';\nimport type { Event } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from './useChatClient';\n\nexport type TypingUser = {\n id: string;\n name?: string;\n};\n\n/**\n * Hook that subscribes to typing events on the active channel\n * and returns the list of currently‑typing users (excluding the current user).\n *\n * Stale entries are auto‑cleaned every 7 seconds, consistent with\n * the SDK's `channel.state.clean()` behaviour.\n */\nexport function useTypingIndicator() {\n const { activeChannel, client } = useChatClient();\n const [typingUsers, setTypingUsers] = useState<TypingUser[]>([]);\n const currentUserId = client.userID;\n\n // Keep a mutable map so event handlers can read/write without\n // creating stale‑closure issues.\n const typingMapRef = useRef<Map<string, { user: TypingUser; timestamp: number }>>(new Map());\n\n useEffect(() => {\n if (!activeChannel) {\n setTypingUsers([]);\n typingMapRef.current.clear();\n return;\n }\n\n // Reset when channel switches\n typingMapRef.current.clear();\n setTypingUsers([]);\n\n const syncState = () => {\n const users = Array.from(typingMapRef.current.values()).map((v) => v.user);\n setTypingUsers(users);\n };\n\n const handleTypingStart = (event: Event) => {\n const userId = event.user?.id;\n if (!userId || userId === currentUserId) return;\n\n typingMapRef.current.set(userId, {\n user: { id: userId, name: event.user?.name },\n timestamp: Date.now(),\n });\n syncState();\n };\n\n const handleTypingStop = (event: Event) => {\n const userId = event.user?.id;\n if (!userId) return;\n\n typingMapRef.current.delete(userId);\n syncState();\n };\n\n const sub1 = activeChannel.on('typing.start', handleTypingStart);\n const sub2 = activeChannel.on('typing.stop', handleTypingStop);\n\n // Auto‑clean stale entries every 7 seconds\n const cleanupInterval = setInterval(() => {\n const now = Date.now();\n let changed = false;\n for (const [uid, entry] of typingMapRef.current.entries()) {\n if (now - entry.timestamp > 7000) {\n typingMapRef.current.delete(uid);\n changed = true;\n }\n }\n if (changed) syncState();\n }, 3000);\n\n return () => {\n sub1.unsubscribe();\n sub2.unsubscribe();\n clearInterval(cleanupInterval);\n typingMapRef.current.clear();\n };\n }, [activeChannel, currentUserId]);\n\n return { typingUsers };\n}\n","import React from 'react';\nimport type { AvatarProps } from '../types';\n\nexport type PendingOverlayProps = {\n channelImage?: string;\n channelName?: string;\n title: string;\n subtitle: string;\n acceptLabel: string;\n rejectLabel: string;\n onAccept: () => void;\n onReject: () => void;\n /** Label for the skip button (direct messaging channels) */\n skipLabel?: string;\n /** Handler for the skip action (direct messaging channels) */\n onSkip?: () => void;\n AvatarComponent: React.ComponentType<AvatarProps>;\n};\n\nexport const PendingOverlay: React.FC<PendingOverlayProps> = React.memo(({\n channelImage,\n channelName,\n title,\n subtitle,\n acceptLabel,\n rejectLabel,\n onAccept,\n onReject,\n skipLabel,\n onSkip,\n AvatarComponent,\n}) => (\n <div className=\"ermis-message-list__pending-overlay\">\n <div className=\"ermis-message-list__pending-card\">\n <AvatarComponent image={channelImage} name={channelName} size={64} className=\"ermis-message-list__pending-avatar\" />\n <span className=\"ermis-message-list__pending-overlay-title\">{title}</span>\n <div className=\"ermis-message-list__pending-channel-name\">{channelName}</div>\n <span className=\"ermis-message-list__pending-overlay-subtitle\">{subtitle}</span>\n <div className=\"ermis-message-list__pending-actions\">\n {onSkip ? (\n <button className=\"ermis-message-list__reject-btn\" onClick={onSkip}>{skipLabel || 'Skip'}</button>\n ) : (\n <button className=\"ermis-message-list__reject-btn\" onClick={onReject}>{rejectLabel}</button>\n )}\n <button className=\"ermis-message-list__accept-btn\" onClick={onAccept}>{acceptLabel}</button>\n </div>\n </div>\n </div>\n));\n\nPendingOverlay.displayName = 'PendingOverlay';\n","import React from 'react';\nimport type { AvatarProps } from '../types';\n\nexport type SkippedOverlayProps = {\n channelImage?: string;\n channelName?: string;\n title: string;\n subtitle: string;\n acceptLabel: string;\n onAccept: () => void;\n AvatarComponent: React.ComponentType<AvatarProps>;\n};\n\nexport const SkippedOverlay: React.FC<SkippedOverlayProps> = React.memo(({\n channelImage,\n channelName,\n title,\n subtitle,\n acceptLabel,\n onAccept,\n AvatarComponent,\n}) => (\n <div className=\"ermis-message-list__pending-overlay\">\n <div className=\"ermis-message-list__pending-card\">\n <AvatarComponent image={channelImage} name={channelName} size={64} className=\"ermis-message-list__pending-avatar\" />\n <span className=\"ermis-message-list__pending-overlay-title\">{title}</span>\n <div className=\"ermis-message-list__pending-channel-name\">{channelName}</div>\n <span className=\"ermis-message-list__pending-overlay-subtitle\">{subtitle}</span>\n <div className=\"ermis-message-list__pending-actions\">\n <button className=\"ermis-message-list__accept-btn\" onClick={onAccept}>{acceptLabel}</button>\n </div>\n </div>\n </div>\n));\n\nSkippedOverlay.displayName = 'SkippedOverlay';\n","import React from 'react';\n\nexport type BannedOverlayProps = {\n isBlocked?: boolean;\n blockedTitle: string;\n bannedTitle: string;\n blockedSubtitle: string;\n bannedSubtitle: string;\n onUnblock?: () => void;\n};\n\nexport const BannedOverlay: React.FC<BannedOverlayProps> = React.memo(({\n isBlocked,\n blockedTitle,\n bannedTitle,\n blockedSubtitle,\n bannedSubtitle,\n onUnblock,\n}) => (\n <div className=\"ermis-message-list__banned-overlay\">\n <div className=\"ermis-message-list__banned-overlay-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__banned-overlay-title\">{isBlocked ? blockedTitle : bannedTitle}</span>\n <span className=\"ermis-message-list__banned-overlay-subtitle\">{isBlocked ? blockedSubtitle : bannedSubtitle}</span>\n {isBlocked && onUnblock && (\n <button\n className=\"ermis-message-list__unblock-btn\"\n onClick={onUnblock}\n >\n Unblock\n </button>\n )}\n </div>\n));\n\nBannedOverlay.displayName = 'BannedOverlay';\n","import React from 'react';\n\nexport type ClosedTopicOverlayProps = {\n title: string;\n subtitle: string;\n canManageTopic: boolean;\n reopenLabel: string;\n onReopen?: () => void;\n};\n\nexport const ClosedTopicOverlay: React.FC<ClosedTopicOverlayProps> = React.memo(({\n title,\n subtitle,\n canManageTopic,\n reopenLabel,\n onReopen,\n}) => (\n <div className=\"ermis-message-list__closed-overlay\">\n <div className=\"ermis-message-list__closed-overlay-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n </div>\n <span className=\"ermis-message-list__closed-overlay-title\">{title}</span>\n <span className=\"ermis-message-list__closed-overlay-subtitle\">{subtitle}</span>\n {canManageTopic && onReopen && (\n <button\n className=\"ermis-message-list__reopen-btn\"\n onClick={onReopen}\n >\n {reopenLabel}\n </button>\n )}\n </div>\n));\n\nClosedTopicOverlay.displayName = 'ClosedTopicOverlay';\n","import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { useBannedState } from '../hooks/useBannedState';\nimport { useBlockedState } from '../hooks/useBlockedState';\nimport { usePendingState } from '../hooks/usePendingState';\nimport { useMentions } from '../hooks/useMentions';\nimport { useFileUpload } from '../hooks/useFileUpload';\nimport { useEmojiPicker } from '../hooks/useEmojiPicker';\nimport { useMessageSend } from '../hooks/useMessageSend';\nimport { DefaultSendButton, DefaultAttachButton, DefaultEmojiButton } from './MessageInputDefaults';\nimport { MentionSuggestions } from './MentionSuggestions';\nimport { FilesPreview } from './FilesPreview';\nimport { ReplyPreview } from './ReplyPreview';\nimport { EditPreview } from './EditPreview';\nimport { buildUserMap, replaceMentionsForPreview, moveCaretToEnd } from '../utils';\nimport { getMentionHtml } from '../hooks/useMentions';\nimport { useChannelCapabilities } from '../hooks/useChannelCapabilities';\nimport { CHANNEL_ROLES } from '../channelRoleUtils';\nimport type { MentionMember, MessageInputProps, FilePreviewItem } from '../types';\n\nexport type { MessageInputProps, SendButtonProps, AttachButtonProps, EmojiPickerProps, EmojiButtonProps } from '../types';\n\nexport const MessageInput: React.FC<MessageInputProps> = React.memo(({\n placeholder = 'Type a message...',\n onSend,\n className,\n SendButton = DefaultSendButton,\n AttachButton = DefaultAttachButton,\n FilesPreviewComponent = FilesPreview,\n MentionSuggestionsComponent = MentionSuggestions,\n disableAttachments = false,\n disableMentions = false,\n renderAbove,\n onBeforeSend,\n EmojiPickerComponent,\n EmojiButtonComponent = DefaultEmojiButton,\n ReplyPreviewComponent = ReplyPreview,\n EditPreviewComponent = EditPreview,\n bannedLabel = 'You have been banned from this channel',\n blockedLabel = 'You have blocked this user. Unblock to send messages.',\n linksDisabledLabel = 'Message blocked: Sending links is disabled for members.',\n keywordBlockedLabel = (match: string) => `Message blocked: Contains restricted word \"${match}\".`,\n sendDisabledLabel = 'Sending messages is disabled in this channel.',\n slowModeLabel = (cooldown: number) => (\n <>Slow mode is active. You can send another message in <strong>{cooldown}s</strong>.</>\n ),\n closedTopicLabel = 'This topic is closed.',\n}) => {\n const { client, activeChannel, syncMessages, quotedMessage, setQuotedMessage, editingMessage, setEditingMessage } = useChatClient();\n const { isBanned } = useBannedState(activeChannel, client.userID);\n const { isBlocked } = useBlockedState(activeChannel, client.userID);\n const { isPending } = usePendingState(activeChannel, client.userID);\n const editableRef = React.useRef<HTMLDivElement>(null);\n const [hasContent, setHasContent] = useState(false);\n\n const { role, isGroupChannel: isTeamChannel, hasCapability } = useChannelCapabilities();\n const isClosedTopic = activeChannel?.data?.is_closed_topic === true;\n\n // Slow Mode Logic\n const [memberMessageCooldown, setMemberMessageCooldown] = useState(Number(activeChannel?.data?.member_message_cooldown) || 0);\n\n useEffect(() => {\n if (!activeChannel) return;\n setMemberMessageCooldown(Number(activeChannel.data?.member_message_cooldown) || 0);\n const handleUpdate = (event: Record<string, unknown>) => {\n const channelData = (event?.channel as Record<string, unknown>) || activeChannel.data;\n setMemberMessageCooldown(Number(channelData?.member_message_cooldown) || 0);\n };\n activeChannel.on('channel.updated', handleUpdate);\n return () => {\n activeChannel.off('channel.updated', handleUpdate);\n };\n }, [activeChannel]);\n\n const isSlowModeApplied = isTeamChannel && role === CHANNEL_ROLES.MEMBER && memberMessageCooldown > 0;\n\n const [cooldownEnd, setCooldownEnd] = useState<number | null>(null);\n const [cooldown, setCooldown] = useState(0);\n const lastMsgSentAtRef = useRef<number>(0);\n\n // Initialize cooldown state periodically or on change\n useEffect(() => {\n if (!isSlowModeApplied) {\n setCooldownEnd(null);\n setCooldown(0);\n return;\n }\n\n let lastMsgSentAt = lastMsgSentAtRef.current || 0;\n const messages = activeChannel?.state?.messages || [];\n\n // Iterate from newest to oldest to find actual highest timestamp\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].user?.id === client.userID) {\n const msgTime = new Date(messages[i].created_at).getTime();\n if (msgTime && !isNaN(msgTime) && msgTime > lastMsgSentAt) {\n lastMsgSentAt = msgTime;\n }\n break;\n }\n }\n\n if (lastMsgSentAt) {\n const cdEnd = lastMsgSentAt + memberMessageCooldown;\n if (cdEnd > Date.now()) {\n setCooldownEnd(cdEnd);\n } else {\n setCooldownEnd(null);\n setCooldown(0);\n }\n } else {\n setCooldownEnd(null);\n setCooldown(0);\n }\n }, [isSlowModeApplied, activeChannel, memberMessageCooldown, client.userID]);\n\n // Tick the countdown visualization\n useEffect(() => {\n if (!cooldownEnd || cooldownEnd <= Date.now()) {\n setCooldown(0);\n return;\n }\n const updateCd = () => {\n const remaining = cooldownEnd - Date.now();\n if (remaining <= 0) {\n setCooldown(0);\n } else {\n setCooldown(Math.ceil(remaining / 1000));\n }\n };\n updateCd();\n const timer = setInterval(updateCd, 1000);\n return () => clearInterval(timer);\n }, [cooldownEnd]);\n\n const isSlowModeBlocked = isSlowModeApplied && cooldown > 0 && !editingMessage;\n\n const canSendMessage = hasCapability('send-message');\n const canSendLinks = hasCapability('send-links');\n\n const [keywordError, setKeywordError] = useState<string | null>(null);\n\n // Auto-clear link restriction banner if admin suddenly restores the capability\n useEffect(() => {\n if (keywordError?.includes('links') && canSendLinks) {\n setKeywordError(null);\n }\n }, [canSendLinks, keywordError]);\n\n const localOnBeforeSend = useCallback(async (text: string, attachments: FilePreviewItem[]) => {\n // Permission validation: Send Links\n if (!canSendLinks && text) {\n // Basic URL matching config\n const urlRegex = /(https?:\\/\\/[^\\s]+)|(www\\.[^\\s]+)|([a-zA-Z0-9-]+\\.[a-zA-Z]{2,}(\\/[^\\s]*)?)/i;\n if (urlRegex.test(text)) {\n setKeywordError(linksDisabledLabel);\n return false;\n }\n }\n\n // Custom Keyword validation\n const words = (activeChannel?.data?.filter_words as string[]) || [];\n if (words.length > 0 && text) {\n const lowerText = text.toLowerCase();\n const match = words.find(w => lowerText.includes(w.toLowerCase()));\n if (match) {\n setKeywordError(keywordBlockedLabel(match));\n // We could also visually shake the input box here\n return false;\n }\n }\n setKeywordError(null);\n if (onBeforeSend) {\n return await onBeforeSend(text, attachments);\n }\n return true;\n }, [activeChannel, onBeforeSend, canSendLinks]);\n\n const handleMessageSent = useCallback((text: string) => {\n if (isSlowModeApplied) {\n lastMsgSentAtRef.current = Date.now();\n setCooldownEnd(Date.now() + memberMessageCooldown);\n }\n onSend?.(text);\n }, [isSlowModeApplied, memberMessageCooldown, onSend]);\n\n // Auto-focus when channel changes or when reply/edit is selected\n useEffect(() => {\n if (activeChannel && editableRef.current) {\n editableRef.current.focus();\n }\n }, [activeChannel, quotedMessage, editingMessage]);\n\n\n /* ---------- Hooks ---------- */\n const {\n files, setFiles, fileInputRef,\n handleFilesSelected, handleRemoveFile, handleAttachClick, cleanupFiles,\n } = useFileUpload({ activeChannel, editableRef, setHasContent });\n\n // Pre-fill text and legacy attachments when editingMessage is set\n useEffect(() => {\n if (editingMessage && editableRef.current) {\n // 1. Prefill text content\n const rawText = editingMessage.text || '';\n\n // Extract user map locally since we have `activeChannel.state.members`\n const userMap = buildUserMap(activeChannel?.state);\n\n const htmlText = rawText\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\\n/g, '<br>');\n\n editableRef.current.innerHTML = replaceMentionsForPreview(\n htmlText,\n editingMessage,\n userMap,\n getMentionHtml\n );\n\n // Move cursor to the end\n moveCaretToEnd(editableRef.current);\n\n // The API does not support attachment modifications during edits.\n // Flush any active files and only allow text/mention modifications.\n setFiles([]);\n setHasContent(!!editingMessage.text);\n }\n }, [editingMessage, setFiles]);\n\n // Cleanup blob URLs on unmount\n useEffect(() => {\n return () => cleanupFiles();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const {\n emojiPickerOpen,\n handleEmojiSelect,\n handleEmojiClose,\n toggleEmojiPicker,\n } = useEmojiPicker({ editableRef, setHasContent });\n\n // Build member list from channel state (only for team channels)\n const members = useMemo<MentionMember[]>(() => {\n if (!isTeamChannel) return [];\n const list: MentionMember[] = [];\n const stateMembers = activeChannel?.state?.members as Record<string, unknown> | undefined;\n if (stateMembers && typeof stateMembers === 'object') {\n for (const [id, memberVal] of Object.entries(stateMembers)) {\n const member = memberVal as Record<string, any>;\n list.push({\n id,\n name: member?.user?.name || member?.user_id || id,\n avatar: member?.user?.avatar,\n });\n }\n }\n return list;\n }, [activeChannel, isTeamChannel]);\n\n const {\n showSuggestions, filteredMembers, highlightIndex,\n handleInput: mentionHandleInput,\n handleKeyDown: mentionHandleKeyDown,\n selectMention, buildPayload, reset,\n } = useMentions({\n members,\n currentUserId: client.userID,\n editableRef,\n });\n\n const cancelEdit = useCallback(() => {\n setEditingMessage(null);\n cleanupFiles();\n setFiles([]);\n setHasContent(false);\n reset();\n if (editableRef.current) {\n editableRef.current.innerHTML = '';\n }\n }, [setEditingMessage, cleanupFiles, setFiles, setHasContent, reset]);\n\n const { sending, handleSend } = useMessageSend({\n activeChannel,\n editableRef,\n files,\n setFiles,\n hasContent,\n setHasContent,\n isTeamChannel,\n buildPayload,\n reset,\n syncMessages,\n onSend: handleMessageSent,\n onBeforeSend: localOnBeforeSend,\n quotedMessage,\n clearQuotedMessage: () => setQuotedMessage(null),\n editingMessage,\n clearEditingMessage: () => setEditingMessage(null),\n });\n\n useEffect(() => {\n reset();\n handleEmojiClose();\n setFiles((prev) => {\n prev.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n return [];\n });\n setHasContent(false);\n\n // Stop typing indicator on channel switch / unmount\n return () => {\n activeChannel?.stopTyping();\n };\n }, [activeChannel, reset, handleEmojiClose, setFiles]);\n\n /* ---------- Input event handlers ---------- */\n const handleInput = useCallback(() => {\n const el = editableRef.current;\n const content = el?.textContent?.trim() ?? '';\n setHasContent(content.length > 0 || files.length > 0);\n setKeywordError(null); // clear keyword error if user modifies input\n if (isTeamChannel && !disableMentions) {\n mentionHandleInput();\n }\n // Send typing indicator (SDK throttles to 1 event per 2s)\n activeChannel?.keystroke();\n }, [isTeamChannel, disableMentions, mentionHandleInput, files.length, activeChannel]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n // Prevent reacting to \"Enter\" when constructing characters with an IME (e.g. Vietnamese telex)\n if (e.nativeEvent.isComposing) return;\n\n if (e.key === 'Escape') {\n if (editingMessage) {\n cancelEdit();\n return;\n }\n if (quotedMessage) {\n setQuotedMessage(null);\n return;\n }\n }\n if (isTeamChannel && !disableMentions) {\n const consumed = mentionHandleKeyDown(e);\n if (consumed) return;\n }\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n if (!isSlowModeBlocked) {\n handleSend();\n }\n }\n },\n [isTeamChannel, disableMentions, mentionHandleKeyDown, handleSend, editingMessage, quotedMessage, setEditingMessage, setQuotedMessage, reset],\n );\n\n const handlePaste = useCallback((e: React.ClipboardEvent) => {\n e.preventDefault();\n const plainText = e.clipboardData.getData('text/plain');\n document.execCommand('insertText', false, plainText);\n }, []);\n\n if (!activeChannel) return null;\n\n // Don't show input for pending invitations at all\n if (isPending) return null;\n\n // Show banned banner instead of input\n if (isBanned) {\n return (\n <div className={`ermis-message-input ermis-message-input--banned${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__banned-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n <span>{bannedLabel}</span>\n </div>\n </div>\n );\n }\n\n // Show blocked banner instead of input (messaging channels only)\n if (isBlocked) {\n return (\n <div className={`ermis-message-input ermis-message-input--blocked${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__blocked-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n <span>{blockedLabel}</span>\n </div>\n </div>\n );\n }\n\n // Show closed topic banner instead of input\n if (isClosedTopic) {\n return (\n <div className={`ermis-message-input ermis-message-input--closed${className ? ` ${className}` : ''}`}>\n <div className=\"ermis-message-input__closed-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n <span>{closedTopicLabel}</span>\n </div>\n </div>\n );\n }\n\n const isStillUploading = files.some((f) => f.status === 'uploading');\n\n return (\n <div className={`ermis-message-input${className ? ` ${className}` : ''}`}>\n {/* Reply preview */}\n {quotedMessage && !editingMessage && (\n <ReplyPreviewComponent\n message={quotedMessage}\n onDismiss={() => setQuotedMessage(null)}\n />\n )}\n\n {/* Edit preview */}\n {editingMessage && (\n <EditPreviewComponent\n message={editingMessage}\n onDismiss={cancelEdit}\n />\n )}\n\n {/* Custom content above input */}\n {renderAbove?.()}\n\n {/* File previews */}\n {!disableAttachments && <FilesPreviewComponent files={files} onRemove={handleRemoveFile} />}\n\n {/* Keyword Error Banner */}\n {keywordError && (\n <div className=\"ermis-message-input__keyword-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line></svg>\n {keywordError}\n </div>\n )}\n\n {/* Permission Disabled Banner */}\n {!canSendMessage && !editingMessage && (\n <div className=\"ermis-message-input__permission-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>\n {sendDisabledLabel}\n </div>\n )}\n\n {/* Slow Mode Cooldown Banner */}\n {canSendMessage && isSlowModeBlocked && !keywordError && (\n <div className=\"ermis-message-input__slow-mode-banner\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><polyline points=\"12 6 12 12 16 14\"></polyline></svg>\n {typeof slowModeLabel === 'function' ? slowModeLabel(cooldown) : slowModeLabel}\n </div>\n )}\n\n {/* Text input + send row */}\n <div className={`ermis-message-input__row${(!canSendMessage || isSlowModeBlocked || keywordError) ? ' ermis-message-input__row--banners-active' : ''}`}>\n <div className=\"ermis-message-input__editable-wrapper\">\n {canSendMessage && isTeamChannel && !disableMentions && showSuggestions && (\n <MentionSuggestionsComponent\n members={filteredMembers}\n highlightIndex={highlightIndex}\n onSelect={selectMention}\n />\n )}\n\n {/* Attach button */}\n {!disableAttachments && (\n <AttachButton disabled={sending || !!editingMessage || isSlowModeBlocked || !canSendMessage} onClick={handleAttachClick} />\n )}\n\n {/* Hidden file input */}\n {!disableAttachments && (\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"ermis-message-input__file-input\"\n onChange={(e) => {\n handleFilesSelected(e.target.files);\n e.target.value = '';\n }}\n disabled={!!editingMessage || isSlowModeBlocked || !canSendMessage}\n />\n )}\n\n <div\n ref={editableRef}\n className=\"ermis-message-input__editable\"\n contentEditable={!sending && !isSlowModeBlocked && canSendMessage}\n role=\"textbox\"\n aria-placeholder={placeholder}\n data-placeholder={placeholder}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n suppressContentEditableWarning\n />\n\n {/* Emoji button — shown only when EmojiPickerComponent is provided */}\n {EmojiPickerComponent && (\n <EmojiButtonComponent active={emojiPickerOpen} onClick={isSlowModeBlocked ? () => { } : toggleEmojiPicker} />\n )}\n </div>\n <SendButton disabled={!hasContent || sending || isStillUploading || isSlowModeBlocked} onClick={handleSend} />\n </div>\n\n {/* Emoji picker — positioned above input */}\n {EmojiPickerComponent && emojiPickerOpen && (\n <div className=\"ermis-message-input__emoji-picker\">\n <EmojiPickerComponent onSelect={handleEmojiSelect} onClose={handleEmojiClose} />\n </div>\n )}\n </div>\n );\n});\n\nMessageInput.displayName = 'MessageInput';\n","import { useState, useCallback, useRef, useDeferredValue, useMemo } from 'react';\nimport { moveCaretAfterNode } from '../utils';\nimport type {\n MentionMember,\n MentionPayload,\n UseMentionsOptions,\n UseMentionsReturn,\n} from '../types';\n\nexport type { MentionMember, MentionPayload, UseMentionsOptions, UseMentionsReturn } from '../types';\n\nexport const MENTION_SPAN_CLASS = 'ermis-message-input__mention-span';\n\n/**\n * Returns the raw HTML string for a mention span, useful for initializing contenteditable divs.\n */\nexport function getMentionHtml(userId: string, displayName: string): string {\n const safeName = displayName.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n return `<span class=\"${MENTION_SPAN_CLASS}\" data-mention-id=\"${userId}\" contenteditable=\"false\">@${safeName}</span> `;\n}\n\n/**\n * Insert an atomic mention <span> at the current cursor position inside a\n * contenteditable element, followed by a trailing space.\n */\nfunction insertMentionAtCursor(\n editableEl: HTMLElement,\n userId: string,\n displayName: string,\n) {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n\n const range = sel.getRangeAt(0);\n\n const { startContainer, startOffset } = range;\n if (startContainer.nodeType === Node.TEXT_NODE) {\n const textBefore = startContainer.textContent?.slice(0, startOffset) ?? '';\n const atIndex = textBefore.lastIndexOf('@');\n if (atIndex !== -1) {\n range.setStart(startContainer, atIndex);\n range.deleteContents();\n }\n }\n\n const span = document.createElement('span');\n span.className = MENTION_SPAN_CLASS;\n span.setAttribute('data-mention-id', userId);\n span.contentEditable = 'false';\n span.textContent = `@${displayName}`;\n\n range.insertNode(span);\n\n const space = document.createTextNode('\\u00A0');\n span.after(space);\n moveCaretAfterNode(space);\n\n editableEl.dispatchEvent(new Event('input', { bubbles: true }));\n}\n\n/**\n * Parse the DOM of a contenteditable div to produce a mention payload.\n */\nfunction buildPayloadFromDOM(editableEl: HTMLElement): MentionPayload {\n let text = '';\n let mentionedAll = false;\n const mentionedUsers: string[] = [];\n\n function walk(node: Node) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent ?? '';\n return;\n }\n\n if (node instanceof HTMLElement) {\n const mentionId = node.getAttribute('data-mention-id');\n if (mentionId && node.classList.contains(MENTION_SPAN_CLASS)) {\n if (mentionId === '__all__') {\n mentionedAll = true;\n text += '@all';\n } else {\n if (!mentionedUsers.includes(mentionId)) {\n mentionedUsers.push(mentionId);\n }\n text += `@${mentionId}`;\n }\n return;\n }\n\n if (node.tagName === 'BR') {\n text += '\\n';\n return;\n }\n\n if (node.tagName === 'DIV' && text.length > 0 && !text.endsWith('\\n')) {\n text += '\\n';\n }\n }\n\n node.childNodes.forEach(walk);\n }\n\n walk(editableEl);\n text = text.replace(/\\u00A0/g, ' ').trim();\n\n return { text, mentioned_all: mentionedAll, mentioned_users: mentionedUsers };\n}\n\n/**\n * Scan the DOM for currently present mention spans and return their IDs.\n */\nfunction getActiveMentionIds(editableEl: HTMLElement): Set<string> {\n const ids = new Set<string>();\n const spans = editableEl.querySelectorAll(`.${MENTION_SPAN_CLASS}`);\n spans.forEach((span) => {\n const id = span.getAttribute('data-mention-id');\n if (id) ids.add(id);\n });\n return ids;\n}\n\nexport function useMentions({\n members,\n currentUserId,\n editableRef,\n}: UseMentionsOptions): UseMentionsReturn {\n const [showSuggestions, setShowSuggestions] = useState(false);\n const [query, setQuery] = useState('');\n const [highlightIndex, setHighlightIndex] = useState(0);\n const [activeMentionIds, setActiveMentionIds] = useState<Set<string>>(new Set());\n\n const deferredQuery = useDeferredValue(query);\n\n // All item: special entry\n const allItem: MentionMember = useMemo(\n () => ({ id: '__all__', name: 'all' }),\n [],\n );\n\n // Filter members based on deferred query, exclude self and already-mentioned\n const filteredMembers = useMemo(() => {\n const q = deferredQuery.toLowerCase();\n\n // Start with @all if not already selected\n const result: MentionMember[] = [];\n if (!activeMentionIds.has('__all__')) {\n if (!q || 'all'.includes(q)) {\n result.push(allItem);\n }\n }\n\n for (const m of members) {\n if (m.id === currentUserId) continue; // skip self\n if (activeMentionIds.has(m.id)) continue; // skip already mentioned\n if (q && !m.name.toLowerCase().includes(q)) continue; // filter by query\n result.push(m);\n }\n\n return result;\n }, [members, deferredQuery, activeMentionIds, currentUserId, allItem]);\n\n // Detect @ trigger from cursor position\n const detectTrigger = useCallback((): { triggered: boolean; query: string } => {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) {\n return { triggered: false, query: '' };\n }\n\n const { anchorNode, anchorOffset } = sel;\n if (!anchorNode || anchorNode.nodeType !== Node.TEXT_NODE) {\n return { triggered: false, query: '' };\n }\n\n const textBefore = anchorNode.textContent?.slice(0, anchorOffset) ?? '';\n\n // Find the last @ that is preceded by a space or is at the start\n const match = textBefore.match(/(^|[\\s\\u00A0])@(\\S*)$/);\n if (!match) {\n return { triggered: false, query: '' };\n }\n\n return { triggered: true, query: match[2] };\n }, []);\n\n const handleInput = useCallback(() => {\n const el = editableRef.current;\n if (!el) return;\n\n // Update active mention IDs by scanning DOM\n setActiveMentionIds(getActiveMentionIds(el));\n\n // Detect @ trigger\n const result = detectTrigger();\n if (result.triggered) {\n setShowSuggestions(true);\n setQuery(result.query);\n setHighlightIndex(0);\n } else {\n setShowSuggestions(false);\n setQuery('');\n }\n }, [editableRef, detectTrigger]);\n\n const selectMention = useCallback(\n (member: MentionMember) => {\n const el = editableRef.current;\n if (!el) return;\n\n insertMentionAtCursor(el, member.id, member.name);\n\n // Update tracking\n setActiveMentionIds((prev) => new Set(prev).add(member.id));\n setShowSuggestions(false);\n setQuery('');\n\n // Re-focus the editable\n el.focus();\n },\n [editableRef],\n );\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent): boolean => {\n if (!showSuggestions || filteredMembers.length === 0) return false;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n setHighlightIndex((prev) =>\n prev < filteredMembers.length - 1 ? prev + 1 : 0,\n );\n return true;\n\n case 'ArrowUp':\n e.preventDefault();\n setHighlightIndex((prev) =>\n prev > 0 ? prev - 1 : filteredMembers.length - 1,\n );\n return true;\n\n case 'Enter':\n e.preventDefault();\n if (filteredMembers[highlightIndex]) {\n selectMention(filteredMembers[highlightIndex]);\n }\n return true;\n\n case 'Escape':\n e.preventDefault();\n setShowSuggestions(false);\n return true;\n\n default:\n return false;\n }\n },\n [showSuggestions, filteredMembers, highlightIndex, selectMention],\n );\n\n const buildPayload = useCallback((): MentionPayload => {\n const el = editableRef.current;\n if (!el) return { text: '', mentioned_all: false, mentioned_users: [] };\n return buildPayloadFromDOM(el);\n }, [editableRef]);\n\n const reset = useCallback(() => {\n setShowSuggestions(false);\n setQuery('');\n setHighlightIndex(0);\n setActiveMentionIds(new Set());\n const el = editableRef.current;\n if (el) {\n el.innerHTML = '';\n }\n }, [editableRef]);\n\n return {\n showSuggestions,\n filteredMembers,\n highlightIndex,\n handleInput,\n handleKeyDown,\n selectMention,\n buildPayload,\n reset,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { isHeicFile, isVideoFile, normalizeFileName } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport type { FilePreviewItem } from '../types';\n\nlet _fileIdCounter = 0;\nfunction nextFileId(): string {\n return `file-${Date.now()}-${++_fileIdCounter}`;\n}\n\nexport type UseFileUploadOptions = {\n activeChannel: Channel | null;\n editableRef: React.RefObject<HTMLDivElement | null>;\n setHasContent: (value: boolean) => void;\n};\n\nexport function useFileUpload({ activeChannel, editableRef, setHasContent }: UseFileUploadOptions) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [files, setFiles] = useState<FilePreviewItem[]>([]);\n\n /**\n * Upload a single file immediately:\n * 1. Normalize file name\n * 2. Call sendFile API\n * 3. For video: generate + upload thumbnail\n * 4. Update file item state with uploaded URL\n */\n const uploadSingleFile = useCallback(async (item: FilePreviewItem) => {\n if (!activeChannel) return;\n\n try {\n const file = item.file!;\n const normalizedName = normalizeFileName(file.name);\n const fileToUpload = normalizedName !== file.name\n ? new File([file], normalizedName, { type: file.type, lastModified: file.lastModified })\n : file;\n\n const response = await activeChannel.sendFile(fileToUpload, fileToUpload.name, fileToUpload.type);\n const uploadedUrl = response.file;\n\n let thumbUrl = '';\n if (isVideoFile(file)) {\n try {\n const thumbBlob = await activeChannel.getThumbBlobVideo(file);\n if (thumbBlob) {\n const thumbFile = new File([thumbBlob], `thumb_${normalizedName}.jpg`, { type: 'image/jpeg' });\n const thumbResp = await activeChannel.sendFile(thumbFile, thumbFile.name, 'image/jpeg');\n thumbUrl = thumbResp.file;\n }\n } catch {\n // Thumbnail failure is non-critical\n }\n }\n\n setFiles((prev) =>\n prev.map((f) =>\n f.id === item.id\n ? { ...f, status: 'done' as const, uploadedUrl, thumbUrl, normalizedFile: fileToUpload }\n : f,\n ),\n );\n } catch (err: any) {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === item.id\n ? { ...f, status: 'error' as const, error: err?.message || 'Upload failed' }\n : f,\n ),\n );\n }\n }, [activeChannel]);\n\n const handleFilesSelected = useCallback((selectedFiles: FileList | null) => {\n if (!selectedFiles || selectedFiles.length === 0) return;\n\n const newItems: FilePreviewItem[] = Array.from(selectedFiles).map((file) => {\n const isPreviewable =\n (file.type.startsWith('image/') && !isHeicFile(file)) ||\n file.type.startsWith('video/');\n return {\n id: nextFileId(),\n file,\n previewUrl: isPreviewable ? URL.createObjectURL(file) : undefined,\n status: 'uploading' as const,\n };\n });\n\n setFiles((prev) => [...prev, ...newItems]);\n setHasContent(true);\n\n newItems.forEach((item) => uploadSingleFile(item));\n }, [uploadSingleFile, setHasContent]);\n\n const handleRemoveFile = useCallback((id: string) => {\n setFiles((prev) => {\n const item = prev.find((f) => f.id === id);\n if (item?.previewUrl) URL.revokeObjectURL(item.previewUrl);\n const remaining = prev.filter((f) => f.id !== id);\n const el = editableRef.current;\n const textContent = el?.textContent?.trim() ?? '';\n if (remaining.length === 0 && textContent.length === 0) {\n setHasContent(false);\n }\n return remaining;\n });\n }, [editableRef, setHasContent]);\n\n const handleAttachClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n // Cleanup blob URLs\n const cleanupFiles = useCallback(() => {\n files.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n }, [files]);\n\n return {\n files,\n setFiles,\n fileInputRef,\n handleFilesSelected,\n handleRemoveFile,\n handleAttachClick,\n cleanupFiles,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { moveCaretToEnd } from '../utils';\n\nexport type UseEmojiPickerOptions = {\n editableRef: React.RefObject<HTMLDivElement | null>;\n setHasContent: (value: boolean) => void;\n};\n\nexport function useEmojiPicker({ editableRef, setHasContent }: UseEmojiPickerOptions) {\n const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);\n const savedRangeRef = useRef<Range | null>(null);\n\n const handleEmojiSelect = useCallback((emoji: string) => {\n const el = editableRef.current;\n if (!el) return;\n\n // Restore saved cursor position, or move to end\n el.focus();\n const sel = window.getSelection();\n if (sel && savedRangeRef.current) {\n sel.removeAllRanges();\n sel.addRange(savedRangeRef.current);\n savedRangeRef.current = null;\n } else {\n moveCaretToEnd(el);\n }\n\n document.execCommand('insertText', false, emoji + ' ');\n setHasContent(true);\n setEmojiPickerOpen(false);\n }, [editableRef, setHasContent]);\n\n const handleEmojiClose = useCallback(() => {\n setEmojiPickerOpen(false);\n savedRangeRef.current = null;\n }, []);\n\n const toggleEmojiPicker = useCallback(() => {\n // Save current cursor position before picker steals focus\n const sel = window.getSelection();\n if (sel && sel.rangeCount > 0) {\n savedRangeRef.current = sel.getRangeAt(0).cloneRange();\n }\n setEmojiPickerOpen((prev) => !prev);\n }, []);\n\n return {\n emojiPickerOpen,\n handleEmojiSelect,\n handleEmojiClose,\n toggleEmojiPicker,\n };\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { buildAttachmentPayload } from '@ermis-network/ermis-chat-sdk';\nimport type { Channel, FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\nimport type { FilePreviewItem } from '../types';\n\nexport type UseMessageSendOptions = {\n activeChannel: Channel | null;\n editableRef: React.RefObject<HTMLDivElement | null>;\n files: FilePreviewItem[];\n setFiles: React.Dispatch<React.SetStateAction<FilePreviewItem[]>>;\n hasContent: boolean;\n setHasContent: (value: boolean) => void;\n isTeamChannel: boolean;\n buildPayload: () => { text: string; mentioned_all: boolean; mentioned_users: string[] };\n reset: () => void;\n syncMessages: () => void;\n onSend?: (text: string) => void;\n onBeforeSend?: (text: string, attachments: FilePreviewItem[]) => boolean | Promise<boolean>;\n /** Message being replied to */\n quotedMessage?: FormatMessageResponse | null;\n /** Clear quoted message after send */\n clearQuotedMessage?: () => void;\n /** Message being edited */\n editingMessage?: FormatMessageResponse | null;\n /** Clear edited message after send */\n clearEditingMessage?: () => void;\n};\n\nexport function useMessageSend({\n activeChannel,\n editableRef,\n files,\n setFiles,\n hasContent,\n setHasContent,\n isTeamChannel,\n buildPayload,\n reset,\n syncMessages,\n onSend,\n onBeforeSend,\n quotedMessage,\n clearQuotedMessage,\n editingMessage,\n clearEditingMessage,\n}: UseMessageSendOptions) {\n const [sending, setSending] = useState(false);\n const isProcessingRef = useRef(false);\n\n const handleSend = useCallback(async () => {\n if (!activeChannel || !hasContent || sending || isProcessingRef.current) return;\n\n // Wait for all files to finish uploading\n const stillUploading = files.some((f) => f.status === 'uploading');\n if (stillUploading) return;\n\n isProcessingRef.current = true;\n\n const payload = buildPayload();\n const text = payload.text.trim();\n const uploadedFiles = files.filter((f) => f.status === 'done');\n\n if (!text && uploadedFiles.length === 0) return;\n\n // onBeforeSend hook — return false to cancel\n if (onBeforeSend) {\n const proceed = await onBeforeSend(text, uploadedFiles);\n if (!proceed) {\n isProcessingRef.current = false;\n return;\n }\n }\n\n try {\n setSending(true);\n\n // Build attachment payloads from already-uploaded files (only applied on new messages)\n const attachments = uploadedFiles.map((f) => {\n if (f.originalAttachment) {\n return f.originalAttachment;\n }\n const fileObj = f.normalizedFile || f.file!;\n return buildAttachmentPayload(fileObj, f.uploadedUrl!, f.thumbUrl);\n });\n\n // Build message\n const message: Record<string, any> = { text };\n\n // The API does not accept attachment arrays during standard text editing\n if (!editingMessage && attachments.length > 0) {\n message.attachments = attachments;\n }\n\n if (isTeamChannel) {\n message.mentioned_all = payload.mentioned_all;\n message.mentioned_users = payload.mentioned_users;\n }\n let sendPromise;\n\n if (editingMessage?.id) {\n sendPromise = activeChannel.editMessage(editingMessage.id, message as any);\n } else {\n if (quotedMessage?.id) {\n message.quoted_message_id = quotedMessage.id;\n }\n sendPromise = activeChannel.sendMessage(message as any);\n }\n\n // --- 0. OPTIMISTIC UI UPDATE ---\n // Instantly injects the `status: 'sending'` message scaffold from SDK into the React map\n syncMessages();\n\n // --- 1. CLEAR UI IMMEDIATELY (FIRE AND FORGET) ---\n // Clear successful files\n files.forEach((f) => {\n if (f.previewUrl) URL.revokeObjectURL(f.previewUrl);\n });\n\n const errorFiles = files.filter((f) => f.status === 'error');\n setFiles(errorFiles);\n setHasContent(errorFiles.length > 0);\n\n reset();\n clearQuotedMessage?.();\n clearEditingMessage?.();\n onSend?.(payload.text);\n // Stop typing indicator immediately on send\n activeChannel?.stopTyping();\n\n // --- 2. DELEGATE TO WEBSOCKET ---\n // The API call runs in background. We do not block the UI for resolution.\n // Message lists will automatically update when the backend blasts the `message.new` WS event.\n sendPromise.catch((err: Error) => {\n console.error('Failed to send message over API:', err);\n // Sync React to render the SDK's internal 'status: failed' UI state\n syncMessages();\n });\n } catch (err) {\n console.error('Failed to process message send:', err);\n } finally {\n isProcessingRef.current = false;\n setSending(false);\n requestAnimationFrame(() => {\n editableRef.current?.focus();\n });\n }\n }, [\n activeChannel,\n hasContent,\n sending,\n buildPayload,\n reset,\n onSend,\n isTeamChannel,\n files,\n onBeforeSend,\n syncMessages,\n editableRef,\n setFiles,\n setHasContent,\n ]);\n\n return { sending, handleSend };\n}\n","import React from 'react';\n\n/* ----------------------------------------------------------\n Default sub-components for MessageInput\n ---------------------------------------------------------- */\n\nexport const DefaultSendButton: React.FC<{ disabled: boolean; onClick: () => void }> = React.memo(({\n disabled,\n onClick,\n}) => (\n <button\n className=\"ermis-message-input__send-btn\"\n onClick={onClick}\n disabled={disabled}\n >\n Send\n </button>\n));\nDefaultSendButton.displayName = 'DefaultSendButton';\n\nexport const DefaultAttachButton: React.FC<{ disabled: boolean; onClick: () => void }> = React.memo(({\n disabled,\n onClick,\n}) => (\n <button\n className=\"ermis-message-input__attach-btn\"\n onClick={onClick}\n type=\"button\"\n aria-label=\"Attach files\"\n disabled={disabled}\n >\n 📎\n </button>\n));\nDefaultAttachButton.displayName = 'DefaultAttachButton';\n\nexport const DefaultEmojiButton: React.FC<{ active: boolean; onClick: () => void }> = React.memo(({\n active,\n onClick,\n}) => (\n <button\n className={`ermis-message-input__emoji-btn${active ? ' ermis-message-input__emoji-btn--active' : ''}`}\n onClick={onClick}\n type=\"button\"\n aria-label=\"Emoji\"\n >\n 😀\n </button>\n));\nDefaultEmojiButton.displayName = 'DefaultEmojiButton';\n","import React, { useEffect, useRef } from 'react';\nimport { VList, VListHandle } from 'virtua';\nimport { Avatar } from './Avatar';\nimport type { MentionSuggestionsProps } from '../types';\n\nexport type { MentionSuggestionsProps } from '../types';\n\n// Estimated item height\nconst ITEM_HEIGHT = 42; \n\nexport const MentionSuggestions: React.FC<MentionSuggestionsProps> = React.memo(({\n members,\n highlightIndex,\n onSelect,\n}) => {\n const listRef = useRef<VListHandle>(null);\n\n // Auto-scroll highlighted item into view\n useEffect(() => {\n // VList uses scrollToIndex\n listRef.current?.scrollToIndex(highlightIndex);\n }, [highlightIndex]);\n\n if (members.length === 0) return null;\n\n // Calculate dynamic height based on item count, cap at 200px\n const listHeight = Math.min(members.length * ITEM_HEIGHT, 200);\n\n return (\n <div className=\"ermis-mention-suggestions\" style={{ overflow: 'hidden' }}>\n <VList ref={listRef} style={{ height: listHeight }}>\n {members.map((member, index) => (\n <div\n key={member.id}\n className={`ermis-mention-suggestions__item${\n index === highlightIndex ? ' ermis-mention-suggestions__item--highlighted' : ''\n }`}\n onMouseDown={(e) => {\n // Use mousedown (not click) to fire before blur\n e.preventDefault();\n onSelect(member);\n }}\n >\n {member.id === '__all__' ? (\n <div className=\"ermis-mention-suggestions__all-icon\">@</div>\n ) : (\n <Avatar image={member.avatar} name={member.name} size={24} />\n )}\n <span className=\"ermis-mention-suggestions__name\">\n {member.id === '__all__' ? 'all' : member.name}\n </span>\n </div>\n ))}\n </VList>\n </div>\n );\n});\n\nMentionSuggestions.displayName = 'MentionSuggestions';\n","import React from 'react';\nimport { isHeicFile } from '@ermis-network/ermis-chat-sdk';\nimport type { FilesPreviewProps } from '../types';\n\nexport type { FilePreviewItem, FilesPreviewProps } from '../types';\n/**\n * Format file size into human-readable string.\n */\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Get a display icon for non-previewable file types.\n */\nfunction getFileIcon(mimeType: string): string {\n if (mimeType.startsWith('audio/')) return '🎵';\n if (mimeType.startsWith('video/')) return '🎬';\n if (mimeType.includes('pdf')) return '📄';\n if (mimeType.includes('zip') || mimeType.includes('rar') || mimeType.includes('tar')) return '📦';\n return '📎';\n}\n\n/**\n * FilesPreview — renders selected files with thumbnails and remove buttons.\n * Shown above the text input area in MessageInput.\n */\nexport const FilesPreview: React.FC<FilesPreviewProps> = React.memo(({ files, onRemove }) => {\n if (files.length === 0) return null;\n\n return (\n <div className=\"ermis-files-preview\">\n {files.map((item) => {\n const fileType = item.file?.type || item.originalAttachment?.mime_type || '';\n const fileName = item.file?.name || item.originalAttachment?.title || 'Unknown file';\n const fileSize = item.file?.size || item.originalAttachment?.file_size || 0;\n\n const isHeic = item.file ? isHeicFile(item.file) : (fileType === 'image/heic' || fileType === 'image/heif');\n const isImage = fileType.startsWith('image/') && !isHeic;\n const isVideo = fileType.startsWith('video/');\n const isUploading = item.status === 'uploading';\n const hasError = item.status === 'error';\n\n const previewUrl = item.previewUrl || item.originalAttachment?.image_url || item.originalAttachment?.asset_url;\n\n return (\n <div\n key={item.id}\n className={`ermis-files-preview__item${hasError ? ' ermis-files-preview__item--error' : ''}`}\n >\n {/* Remove button */}\n <button\n className=\"ermis-files-preview__remove\"\n onClick={() => onRemove(item.id)}\n aria-label=\"Remove file\"\n type=\"button\"\n >\n ✕\n </button>\n\n {/* Preview content */}\n {isImage && previewUrl ? (\n <img\n className=\"ermis-files-preview__thumb\"\n src={previewUrl}\n alt={fileName}\n />\n ) : isVideo && previewUrl ? (\n <video\n className=\"ermis-files-preview__thumb\"\n src={previewUrl}\n muted\n />\n ) : (\n <div className=\"ermis-files-preview__file-icon\">\n <span>{getFileIcon(fileType)}</span>\n </div>\n )}\n\n {/* File info */}\n <div className=\"ermis-files-preview__info\">\n <span className=\"ermis-files-preview__name\">{fileName}</span>\n <span className=\"ermis-files-preview__size\">{formatFileSize(Number(fileSize))}</span>\n </div>\n\n {/* Upload status overlay */}\n {isUploading && (\n <div className=\"ermis-files-preview__uploading\">\n <span className=\"ermis-files-preview__spinner\" />\n </div>\n )}\n\n {/* Error overlay */}\n {hasError && (\n <div className=\"ermis-files-preview__error-badge\" title={item.error}>\n ⚠\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n});\n\nFilesPreview.displayName = 'FilesPreview';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport { isStickerMessage } from '../messageTypeUtils';\nimport type { ReplyPreviewProps } from '../types';\n\nconst MAX_PREVIEW_LENGTH = 120;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\n/** Get a human-readable summary of attachments */\nfunction getAttachmentSummary(attachments: any[]): string {\n if (!attachments || attachments.length === 0) return '';\n\n const types: Record<string, number> = {};\n for (const att of attachments) {\n const type = att.type || 'file';\n types[type] = (types[type] || 0) + 1;\n }\n\n const labels: string[] = [];\n const typeLabels: Record<string, string> = {\n image: '🖼️ Image',\n video: '🎬 Video',\n audio: '🎵 Audio',\n file: '📎 File',\n voiceRecording: '🎤 Voice',\n };\n\n for (const [type, count] of Object.entries(types)) {\n const label = typeLabels[type] || `📎 ${type}`;\n labels.push(count > 1 ? `${label} (${count})` : label);\n }\n\n return labels.join(', ');\n}\nexport const ReplyPreview: React.FC<ReplyPreviewProps> = React.memo(({\n message,\n onDismiss,\n replyingToLabel = 'Replying to',\n}) => {\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const userName = message.user?.name || message.user_id || 'Unknown';\n \n const rawText = message.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, message, userMap), [rawText, message, userMap]);\n const hasText = !!formattedText.trim();\n const hasAttachments = message.attachments && message.attachments.length > 0;\n const isSticker = isStickerMessage(message);\n const attachmentSummary = hasAttachments ? getAttachmentSummary(message.attachments!) : '';\n\n // Build preview content\n let previewContent: React.ReactNode = null;\n if (isSticker) {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n 😀 Sticker\n </span>\n );\n } else {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n {hasText && truncateText(formattedText, MAX_PREVIEW_LENGTH)}\n {hasText && hasAttachments && ' · '}\n {hasAttachments && attachmentSummary}\n </span>\n );\n }\n\n return (\n <div className=\"ermis-message-input__reply-preview\">\n <div className=\"ermis-message-input__reply-preview-body\">\n <span className=\"ermis-message-input__reply-preview-label\">{replyingToLabel}</span>\n <span className=\"ermis-message-input__reply-preview-user\">{userName}</span>\n {previewContent}\n </div>\n <button\n className=\"ermis-message-input__reply-preview-dismiss\"\n onClick={onDismiss}\n title=\"Cancel reply\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n );\n});\n\nReplyPreview.displayName = 'ReplyPreview';\n","import React, { useMemo } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap } from '../utils';\nimport { isStickerMessage } from '../messageTypeUtils';\nimport type { FormatMessageResponse } from '@ermis-network/ermis-chat-sdk';\n\nconst MAX_PREVIEW_LENGTH = 120;\n\nfunction truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trimEnd() + '…';\n}\n\n/** Get a human-readable summary of attachments */\nfunction getAttachmentSummary(attachments: any[]): string {\n if (!attachments || attachments.length === 0) return '';\n\n const types: Record<string, number> = {};\n for (const att of attachments) {\n const type = att.type || 'file';\n types[type] = (types[type] || 0) + 1;\n }\n\n const labels: string[] = [];\n const typeLabels: Record<string, string> = {\n image: '🖼️ Image',\n video: '🎬 Video',\n audio: '🎵 Audio',\n file: '📎 File',\n voiceRecording: '🎤 Voice',\n };\n\n for (const [type, count] of Object.entries(types)) {\n const label = typeLabels[type] || `📎 ${type}`;\n labels.push(count > 1 ? `${label} (${count})` : label);\n }\n\n return labels.join(', ');\n}\nexport const EditPreview: React.FC<{\n message: FormatMessageResponse;\n onDismiss: () => void;\n}> = React.memo(({\n message,\n onDismiss,\n editingMessageLabel = 'Editing message',\n}: any) => {\n console.log('--message--', message)\n const { activeChannel } = useChatClient();\n\n const userMap = useMemo<Record<string, string>>(() => {\n return buildUserMap(activeChannel?.state);\n }, [activeChannel]);\n\n const userName = message.user?.name || message.user_id || 'Unknown';\n\n const rawText = message.text || '';\n const formattedText = useMemo(() => replaceMentionsForPreview(rawText, message, userMap), [rawText, message, userMap]);\n const hasText = !!formattedText.trim();\n const hasAttachments = message.attachments && message.attachments.length > 0;\n const isSticker = isStickerMessage(message);\n const attachmentSummary = hasAttachments ? getAttachmentSummary(message.attachments!) : '';\n\n // Build preview content\n let previewContent: React.ReactNode = null;\n if (isSticker) {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n 😀 Sticker\n </span>\n );\n } else {\n previewContent = (\n <span className=\"ermis-message-input__reply-preview-text\">\n {hasText && truncateText(formattedText, MAX_PREVIEW_LENGTH)}\n {hasText && hasAttachments && ' · '}\n {hasAttachments && attachmentSummary}\n </span>\n );\n }\n\n return (\n <div className=\"ermis-message-input__reply-preview\">\n <div className=\"ermis-message-input__reply-preview-body\">\n <span className=\"ermis-message-input__reply-preview-label\">{editingMessageLabel}</span>\n <span className=\"ermis-message-input__reply-preview-user\">{userName}</span>\n {previewContent}\n </div>\n <button\n className=\"ermis-message-input__reply-preview-dismiss\"\n onClick={onDismiss}\n title=\"Cancel edit\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n );\n});\n\nEditPreview.displayName = 'EditPreview';\n","import React, { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport { useBannedState } from '../../hooks/useBannedState';\nimport { useBlockedState } from '../../hooks/useBlockedState';\nimport { Avatar } from '../Avatar';\nimport { DefaultChannelInfoTabs } from './ChannelInfoTabs';\nimport { AddMemberModal } from './AddMemberModal';\nimport { EditChannelModal } from './EditChannelModal';\nimport { TopicModal } from '../TopicModal';\nimport { MessageSearchPanel } from './MessageSearchPanel';\nimport { ChannelSettingsPanel } from './ChannelSettingsPanel';\nimport type {\n ChannelInfoProps,\n ChannelInfoHeaderProps,\n ChannelInfoCoverProps,\n ChannelInfoActionsProps,\n} from '../../types';\nimport { useChannelMembers, useChannelProfile } from '../../hooks/useChannelData';\nimport { isGroupChannel, isTopicChannel } from '../../channelTypeUtils';\nimport { canManageChannel, CHANNEL_ROLES } from '../../channelRoleUtils';\n\nexport const DefaultChannelInfoHeader: React.FC<ChannelInfoHeaderProps> = React.memo(({ title, onClose }) => {\n return (\n <div className=\"ermis-channel-info__header\">\n <h3 className=\"ermis-channel-info__title\">{title}</h3>\n {onClose && (\n <button className=\"ermis-channel-info__close\" onClick={onClose} aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n )}\n </div>\n );\n});\nDefaultChannelInfoHeader.displayName = 'DefaultChannelInfoHeader';\n\nexport const DefaultChannelInfoCover: React.FC<ChannelInfoCoverProps> = React.memo(({ channelName, channelImage, channelDescription, AvatarComponent, canEdit, onEditClick, isPublic, isTeamChannel, parentChannelName, isTopic }) => {\n const renderAvatar = () => {\n if (isTopic && channelImage && channelImage.startsWith('emoji://')) {\n const emoji = channelImage.replace('emoji://', '');\n return (\n <div className=\"ermis-channel-info__topic-emoji-avatar\">\n {emoji}\n </div>\n );\n }\n return <AvatarComponent image={channelImage} name={channelName} size={80} className=\"ermis-channel-info__avatar\" />;\n };\n\n return (\n <div className=\"ermis-channel-info__cover\">\n {renderAvatar()}\n <div className=\"ermis-channel-info__name-row\">\n <h2 className=\"ermis-channel-info__name\">{channelName}</h2>\n {canEdit && onEditClick && (\n <button className=\"ermis-channel-info__cover-edit-btn\" onClick={onEditClick} aria-label=\"Edit channel\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" />\n </svg>\n </button>\n )}\n </div>\n {parentChannelName && (\n <div className=\"ermis-channel-info__parent-name\">\n {parentChannelName}\n </div>\n )}\n {isTeamChannel && (\n <span className={`ermis-channel-info__type-badge ${isPublic ? 'ermis-channel-info__type-badge--public' : 'ermis-channel-info__type-badge--private'}`}>\n {isPublic ? (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\" />\n <path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\" />\n </svg>\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n )}\n {isPublic ? 'Public' : 'Private'}\n </span>\n )}\n {channelDescription && (\n <p className=\"ermis-channel-info__description\">{channelDescription}</p>\n )}\n </div>\n );\n});\nDefaultChannelInfoCover.displayName = 'DefaultChannelInfoCover';\n\nexport const DefaultChannelInfoActions: React.FC<ChannelInfoActionsProps> = React.memo(({\n onSearchClick, onSettingsClick, onLeaveChannel, onDeleteChannel,\n onBlockUser, onUnblockUser, onCloseTopic, onReopenTopic,\n isTeamChannel, isTopic, isClosedTopic, isBlocked, currentUserRole,\n searchLabel = 'Search', settingsLabel = 'Settings', deleteLabel = 'Delete', leaveLabel = 'Leave',\n blockLabel = 'Block', unblockLabel = 'Unblock', closeTopicLabel = 'Close Topic', reopenTopicLabel = 'Reopen Topic'\n}) => {\n return (\n <div className=\"ermis-channel-info__actions\">\n <button className=\"ermis-channel-info__action-btn\" onClick={onSearchClick} disabled={isBlocked}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n </svg>\n </div>\n <span>{searchLabel}</span>\n </button>\n {isTeamChannel && canManageChannel(currentUserRole) && (\n <button className=\"ermis-channel-info__action-btn\" onClick={onSettingsClick}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"></path>\n </svg>\n </div>\n <span>{settingsLabel}</span>\n </button>\n )}\n {isTeamChannel && (\n currentUserRole === CHANNEL_ROLES.OWNER ? (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onDeleteChannel}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\"></polyline>\n <path d=\"M19 6V20a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path>\n </svg>\n </div>\n <span>{deleteLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onLeaveChannel}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"></path>\n <polyline points=\"16 17 21 12 16 7\"></polyline>\n <line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"></line>\n </svg>\n </div>\n <span>{leaveLabel}</span>\n </button>\n )\n )}\n {/* Topics: Close/Reopen Topic for owner/moder */}\n {isTopic && canManageChannel(currentUserRole) && (\n isClosedTopic ? (\n <button className=\"ermis-channel-info__action-btn\" onClick={onReopenTopic}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 9.9-1\" />\n </svg>\n </div>\n <span>{reopenTopicLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onCloseTopic}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n </div>\n <span>{closeTopicLabel}</span>\n </button>\n )\n )}\n {/* Block/Unblock — messaging (1-1) channels only */}\n {!isTeamChannel && !isTopic && (\n isBlocked ? (\n <button className=\"ermis-channel-info__action-btn\" onClick={onUnblockUser}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span>{unblockLabel}</span>\n </button>\n ) : (\n <button className=\"ermis-channel-info__action-btn ermis-channel-info__action-btn--danger\" onClick={onBlockUser}>\n <div className=\"ermis-channel-info__action-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\" />\n </svg>\n </div>\n <span>{blockLabel}</span>\n </button>\n )\n )}\n </div>\n );\n});\nDefaultChannelInfoActions.displayName = 'DefaultChannelInfoActions';\n\nexport const ChannelInfo: React.FC<ChannelInfoProps> = React.memo((props) => {\n const {\n channel: channelProp,\n className = '',\n AvatarComponent = Avatar,\n onClose,\n title: titleProp,\n HeaderComponent = DefaultChannelInfoHeader,\n CoverComponent = DefaultChannelInfoCover,\n ActionsComponent = DefaultChannelInfoActions,\n TabsComponent = DefaultChannelInfoTabs,\n AddMemberModalComponent,\n EditChannelModalComponent,\n actionsSearchLabel,\n actionsSettingsLabel,\n actionsDeleteLabel,\n actionsLeaveLabel,\n MemberItemComponent,\n MediaItemComponent,\n LinkItemComponent,\n FileItemComponent,\n EmptyStateComponent,\n LoadingComponent,\n onSearchClick,\n onLeaveChannel: onLeaveChannelProp,\n onDeleteChannel: onDeleteChannelProp,\n onAddMemberClick,\n onRemoveMember: onRemoveMemberProp,\n onBanMember: onBanMemberProp,\n onUnbanMember: onUnbanMemberProp,\n onPromoteMember: onPromoteMemberProp,\n onDemoteMember: onDemoteMemberProp,\n // Add Member customization\n addMemberModalTitle,\n addMemberSearchPlaceholder,\n addMemberLoadingText,\n addMemberEmptyText,\n addMemberAddLabel,\n addMemberAddingLabel,\n addMemberAddedLabel,\n addMemberButtonLabel,\n AddMemberButtonComponent,\n // Edit Channel customization\n onEditChannel: onEditChannelProp,\n editChannelModalTitle,\n editChannelNameLabel,\n editChannelDescriptionLabel,\n editChannelNamePlaceholder,\n editChannelDescriptionPlaceholder,\n editChannelPublicLabel,\n editChannelSaveLabel,\n editChannelCancelLabel,\n editChannelSavingLabel,\n editChannelChangeAvatarLabel,\n editChannelImageAccept,\n editChannelMaxImageSize,\n editChannelMaxImageSizeError,\n // Block/Unblock customization (messaging channels)\n onBlockUser: onBlockUserProp,\n onUnblockUser: onUnblockUserProp,\n actionsBlockLabel,\n actionsUnblockLabel,\n actionsCloseTopicLabel,\n actionsReopenTopicLabel,\n // Settings panel customizations\n settingsWorkspaceTopicsTitle,\n settingsTopicsFeatureName,\n settingsTopicsFeatureDescription,\n } = props;\n\n const { activeChannel, client } = useChatClient();\n const channel = channelProp || activeChannel;\n const { isBanned } = useBannedState(channel, client?.userID);\n const { isBlocked } = useBlockedState(channel, client?.userID);\n\n const currentUserId = client?.userID;\n const currentUserRole = currentUserId ? channel?.state?.members?.[currentUserId]?.channel_role : undefined;\n const isTeamChannel = isGroupChannel(channel);\n const isTopic = isTopicChannel(channel);\n const isClosedTopic = channel?.data?.is_closed_topic === true;\n const title = titleProp !== undefined ? titleProp : (isTopic ? 'Topic Info' : 'Channel Info');\n\n const parentCid = channel?.data?.parent_cid as string | undefined;\n const parentChannel = parentCid && client ? client.activeChannels[parentCid] : undefined;\n let parentChannelName = parentChannel?.data?.name || (parentCid ? 'Unknown' : undefined);\n\n const handleDeleteChannel = useCallback(async () => {\n if (onDeleteChannelProp) return onDeleteChannelProp();\n if (!channel) return;\n try {\n await channel.delete();\n } catch (e) {\n console.error(\"Error deleting channel\", e);\n }\n }, [channel, onDeleteChannelProp]);\n\n const handleLeaveChannel = useCallback(async () => {\n if (onLeaveChannelProp) return onLeaveChannelProp();\n if (!channel || !currentUserId) return;\n try {\n await channel.removeMembers([currentUserId]);\n } catch (e) {\n console.error(\"Error leaving channel\", e);\n }\n }, [channel, currentUserId, onLeaveChannelProp]);\n\n const handleRemoveMember = useCallback(async (memberId: string) => {\n if (onRemoveMemberProp) return onRemoveMemberProp(memberId);\n if (!channel) return;\n try {\n await channel.removeMembers([memberId]);\n } catch (e) {\n console.error(\"Error removing member\", e);\n }\n }, [channel, onRemoveMemberProp]);\n\n const handleBanMember = useCallback(async (memberId: string) => {\n if (onBanMemberProp) return onBanMemberProp(memberId);\n if (!channel) return;\n try { await channel.banMembers([memberId]); } catch (e) { console.error(\"Error banning member\", e); }\n }, [channel, onBanMemberProp]);\n\n const handleUnbanMember = useCallback(async (memberId: string) => {\n if (onUnbanMemberProp) return onUnbanMemberProp(memberId);\n if (!channel) return;\n try { await channel.unbanMembers([memberId]); } catch (e) { console.error(\"Error unbanning member\", e); }\n }, [channel, onUnbanMemberProp]);\n\n const handlePromoteMember = useCallback(async (memberId: string) => {\n if (onPromoteMemberProp) return onPromoteMemberProp(memberId);\n if (!channel) return;\n try { await channel.addModerators([memberId]); } catch (e) { console.error(\"Error promoting member\", e); }\n }, [channel, onPromoteMemberProp]);\n\n const handleDemoteMember = useCallback(async (memberId: string) => {\n if (onDemoteMemberProp) return onDemoteMemberProp(memberId);\n if (!channel) return;\n try { await channel.demoteModerators([memberId]); } catch (e) { console.error(\"Error demoting member\", e); }\n }, [channel, onDemoteMemberProp]);\n\n const handleBlockUser = useCallback(async () => {\n if (onBlockUserProp) return onBlockUserProp();\n if (!channel) return;\n try { await channel.blockUser(); } catch (e) { console.error('Error blocking user', e); }\n }, [channel, onBlockUserProp]);\n\n const handleUnblockUser = useCallback(async () => {\n if (onUnblockUserProp) return onUnblockUserProp();\n if (!channel) return;\n try { await channel.unblockUser(); } catch (e) { console.error('Error unblocking user', e); }\n }, [channel, onUnblockUserProp]);\n\n const handleCloseTopic = useCallback(async () => {\n if (!channel || !parentChannel) return;\n try { await parentChannel.closeTopic(channel.cid); } catch (e) { console.error('Error closing topic', e); }\n }, [channel, parentChannel]);\n\n const handleReopenTopic = useCallback(async () => {\n if (!channel || !parentChannel) return;\n try { await parentChannel.reopenTopic(channel.cid); } catch (e) { console.error('Error reopening topic', e); }\n }, [channel, parentChannel]);\n\n const { members } = useChannelMembers(channel);\n const { channelName: profileChannelName, channelImage, channelDescription } = useChannelProfile(channel);\n\n let finalChannelName = profileChannelName;\n let finalParentChannelName = parentChannelName;\n\n // If this is the proxy 'general' channel, show the team name as the main name and hide the parent name.\n if (isGroupChannel(channel) && channel?.data?.name === 'general' && channel.cid) {\n const realChannelName = client?.activeChannels[channel.cid]?.data?.name;\n if (realChannelName && realChannelName !== 'general') {\n finalChannelName = realChannelName;\n finalParentChannelName = undefined;\n }\n }\n\n const [showAddMemberModal, setShowAddMemberModal] = useState(false);\n const [showEditChannelModal, setShowEditChannelModal] = useState(false);\n const [showEditTopicModal, setShowEditTopicModal] = useState(false);\n const [showSearchPanel, setShowSearchPanel] = useState(false);\n const [showSettingsPanel, setShowSettingsPanel] = useState(false);\n\n // Permission: only owner or moderator can edit channel info (banned users cannot)\n const canEditChannel = (isTeamChannel || isTopic) && !isBanned && canManageChannel(currentUserRole);\n\n const handleEditChannelClick = useCallback(() => {\n if (isTopic) {\n setShowEditTopicModal(true);\n } else {\n setShowEditChannelModal(true);\n }\n }, [isTopic]);\n\n const handleAddMemberClick = useCallback(() => {\n if (onAddMemberClick) return onAddMemberClick();\n setShowAddMemberModal(true);\n }, [onAddMemberClick]);\n\n\n\n if (!channel) return null;\n\n return (\n <div className={`ermis-channel-info ${className}`.trim()}>\n <HeaderComponent title={title} onClose={onClose} />\n\n <CoverComponent\n channelName={finalChannelName}\n channelImage={channelImage}\n channelDescription={channelDescription}\n AvatarComponent={AvatarComponent}\n canEdit={canEditChannel}\n onEditClick={handleEditChannelClick}\n isPublic={Boolean(channel?.data?.public)}\n isTeamChannel={isTeamChannel}\n parentChannelName={finalParentChannelName}\n isTopic={isTopic}\n />\n\n {isBanned && (\n <div className=\"ermis-channel-info__banned-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <line x1=\"4.93\" y1=\"4.93\" x2=\"19.07\" y2=\"19.07\"></line>\n </svg>\n <span className=\"ermis-channel-info__banned-banner-text\">You have been banned from this channel</span>\n </div>\n )}\n {!isBanned && (\n <>\n <ActionsComponent\n onSearchClick={() => setShowSearchPanel(true)}\n onSettingsClick={() => setShowSettingsPanel(true)}\n onLeaveChannel={handleLeaveChannel}\n onDeleteChannel={handleDeleteChannel}\n onBlockUser={handleBlockUser}\n onUnblockUser={handleUnblockUser}\n onCloseTopic={handleCloseTopic}\n onReopenTopic={handleReopenTopic}\n isTeamChannel={isTeamChannel}\n isTopic={isTopic}\n isClosedTopic={isClosedTopic}\n isBlocked={isBlocked}\n currentUserRole={currentUserRole}\n searchLabel={actionsSearchLabel}\n settingsLabel={actionsSettingsLabel}\n deleteLabel={actionsDeleteLabel}\n leaveLabel={actionsLeaveLabel}\n blockLabel={actionsBlockLabel}\n unblockLabel={actionsUnblockLabel}\n closeTopicLabel={actionsCloseTopicLabel}\n reopenTopicLabel={actionsReopenTopicLabel}\n />\n\n <TabsComponent\n channel={channel}\n members={members as any}\n AvatarComponent={AvatarComponent}\n currentUserId={currentUserId}\n currentUserRole={currentUserRole}\n onAddMemberClick={isTeamChannel ? handleAddMemberClick : undefined}\n onRemoveMember={handleRemoveMember}\n onBanMember={handleBanMember}\n onUnbanMember={handleUnbanMember}\n onPromoteMember={handlePromoteMember}\n onDemoteMember={handleDemoteMember}\n addMemberButtonLabel={addMemberButtonLabel}\n AddMemberButtonComponent={AddMemberButtonComponent}\n MemberItemComponent={MemberItemComponent}\n MediaItemComponent={MediaItemComponent}\n LinkItemComponent={LinkItemComponent}\n FileItemComponent={FileItemComponent}\n EmptyStateComponent={EmptyStateComponent}\n LoadingComponent={LoadingComponent}\n />\n\n {showAddMemberModal && (() => {\n const ModalComp = AddMemberModalComponent || AddMemberModal;\n return (\n <ModalComp\n channel={channel}\n currentMembers={members as any}\n onClose={() => setShowAddMemberModal(false)}\n AvatarComponent={AvatarComponent}\n title={addMemberModalTitle}\n searchPlaceholder={addMemberSearchPlaceholder}\n loadingText={addMemberLoadingText}\n emptyText={addMemberEmptyText}\n addLabel={addMemberAddLabel}\n addingLabel={addMemberAddingLabel}\n addedLabel={addMemberAddedLabel}\n />\n );\n })()}\n\n {showEditChannelModal && (() => {\n const EditComp = EditChannelModalComponent || EditChannelModal;\n return (\n <EditComp\n channel={channel}\n onClose={() => setShowEditChannelModal(false)}\n onSave={onEditChannelProp}\n AvatarComponent={AvatarComponent}\n title={editChannelModalTitle}\n nameLabel={editChannelNameLabel}\n descriptionLabel={editChannelDescriptionLabel}\n namePlaceholder={editChannelNamePlaceholder}\n descriptionPlaceholder={editChannelDescriptionPlaceholder}\n publicLabel={editChannelPublicLabel}\n saveLabel={editChannelSaveLabel}\n cancelLabel={editChannelCancelLabel}\n savingLabel={editChannelSavingLabel}\n changeAvatarLabel={editChannelChangeAvatarLabel}\n imageAccept={editChannelImageAccept}\n maxImageSize={editChannelMaxImageSize}\n maxImageSizeError={editChannelMaxImageSizeError}\n />\n );\n })()}\n\n {showEditTopicModal && (() => {\n return (\n <TopicModal\n isOpen={true}\n onClose={() => setShowEditTopicModal(false)}\n topic={channel}\n />\n );\n })()}\n </>\n )}\n\n {/* Search Panel — slides over entire ChannelInfo body */}\n {channel && showSearchPanel && (\n <MessageSearchPanel\n isOpen={showSearchPanel}\n onClose={() => setShowSearchPanel(false)}\n channel={channel}\n AvatarComponent={AvatarComponent}\n />\n )}\n\n {/* Settings Panel — slides over entire ChannelInfo body */}\n {channel && showSettingsPanel && (\n <ChannelSettingsPanel\n isOpen={showSettingsPanel}\n onClose={() => setShowSettingsPanel(false)}\n channel={channel}\n workspaceTopicsTitle={settingsWorkspaceTopicsTitle}\n topicsFeatureName={settingsTopicsFeatureName}\n topicsFeatureDescription={settingsTopicsFeatureDescription}\n />\n )}\n </div>\n );\n});\n\nChannelInfo.displayName = 'ChannelInfo';\n","import React, { useState, useEffect, useMemo, useCallback, useDeferredValue } from 'react';\nimport { VList } from 'virtua';\nimport { ROLE_WEIGHTS, MESSAGING_TABS, ALL_TABS, PENDING_STYLE, READY_STYLE } from './utils';\nimport { useBannedState } from '../../hooks/useBannedState';\nimport { useBlockedState } from '../../hooks/useBlockedState';\nimport { MediaGridItem, MediaRow } from './MediaGridItem';\nimport { LinkListItem } from './LinkListItem';\nimport { FileListItem } from './FileListItem';\nimport { MemberListItem } from './MemberListItem';\nimport { TabEmptyState, TabLoadingState } from './States';\nimport { MediaLightbox } from '../MediaLightbox';\nimport type { ChannelInfoTabsProps, MediaTab, AttachmentItem, MediaLightboxItem } from '../../types';\nimport { isDirectChannel } from '../../channelTypeUtils';\nimport {\n CHANNEL_ROLES,\n canRemoveTargetMember,\n canBanTargetMember,\n canPromoteTargetMember,\n canDemoteTargetMember\n} from '../../channelRoleUtils';\n\nexport const DefaultChannelInfoTabs: React.FC<ChannelInfoTabsProps> = React.memo(({\n channel,\n members,\n AvatarComponent,\n currentUserId,\n currentUserRole,\n onAddMemberClick,\n onRemoveMember,\n onBanMember,\n onUnbanMember,\n onPromoteMember,\n onDemoteMember,\n addMemberButtonLabel = 'Add Member',\n AddMemberButtonComponent,\n MemberItemComponent,\n MediaItemComponent,\n LinkItemComponent,\n FileItemComponent,\n EmptyStateComponent,\n LoadingComponent,\n}) => {\n const isMessaging = isDirectChannel(channel);\n const isTopic = Boolean(channel?.data?.parent_cid);\n \n const { isBanned } = useBannedState(channel, currentUserId);\n const { isBlocked } = useBlockedState(channel, currentUserId);\n\n const availableTabs: MediaTab[] = useMemo(() => {\n let tabs = isMessaging ? MESSAGING_TABS : ALL_TABS;\n if (isTopic) {\n tabs = tabs.filter(t => t !== 'members');\n }\n return tabs;\n }, [isMessaging, isTopic]);\n\n const [activeTab, setActiveTab] = useState<MediaTab>(availableTabs[0]);\n const contentTab = useDeferredValue(activeTab);\n const isPending = activeTab !== contentTab;\n\n // Always reset to the first available tab when the user switches channels\n useEffect(() => {\n setActiveTab(availableTabs[0]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [channel?.cid, availableTabs]);\n\n // Resolve sub-components with defaults\n const MemberItem = MemberItemComponent || MemberListItem;\n const MediaItem = MediaItemComponent || MediaGridItem;\n const LinkItem = LinkItemComponent || LinkListItem;\n const FileItem = FileItemComponent || FileListItem;\n const EmptyState = EmptyStateComponent || TabEmptyState;\n const Loading = LoadingComponent || TabLoadingState;\n\n const [allAttachments, setAllAttachments] = useState<AttachmentItem[]>([]);\n const [loading, setLoading] = useState(true);\n\n const sortedMembers = useMemo(() => {\n return [...members].sort((a, b) => {\n const aWeight = ROLE_WEIGHTS[a.channel_role || CHANNEL_ROLES.MEMBER] || 0;\n const bWeight = ROLE_WEIGHTS[b.channel_role || CHANNEL_ROLES.MEMBER] || 0;\n return bWeight - aWeight;\n });\n }, [members]);\n\n // Categorize attachments by type\n const mediaItems = useMemo(() =>\n allAttachments.filter(a => a.attachment_type === 'image' || a.attachment_type === 'video'),\n [allAttachments]\n );\n\n const linkItems = useMemo(() =>\n allAttachments.filter(a => a.attachment_type === 'linkPreview'),\n [allAttachments]\n );\n\n const fileItems = useMemo(() =>\n allAttachments.filter(a => a.attachment_type === 'file' || a.attachment_type === 'voiceRecording'),\n [allAttachments]\n );\n\n useEffect(() => {\n let active = true;\n\n // Don't fetch media/files if user is banned or blocked\n if (isBanned || isBlocked) {\n setAllAttachments([]);\n setLoading(false);\n return;\n }\n\n const fetchMedia = async () => {\n setLoading(true);\n try {\n const response: any = await channel.queryAttachmentMessages();\n\n if (active) {\n const items = response?.attachments || [];\n setAllAttachments(items);\n }\n } catch (err) {\n console.error(\"Failed to query media for channel info\", err);\n if (active) setAllAttachments([]);\n } finally {\n if (active) setLoading(false);\n }\n };\n\n fetchMedia();\n\n return () => { active = false; };\n }, [channel, isBanned, isBlocked]);\n\n const tabCounts = useMemo<Record<MediaTab, number>>(() => ({\n members: members.length,\n media: mediaItems.length,\n links: linkItems.length,\n files: fileItems.length,\n }), [members.length, mediaItems.length, linkItems.length, fileItems.length]);\n\n const handleOpenUrl = useCallback((url: string) => {\n window.open(url, '_blank', 'noopener,noreferrer');\n }, []);\n\n // Lightbox state for media tab\n const [lightboxOpen, setLightboxOpen] = useState(false);\n const [lightboxIndex, setLightboxIndex] = useState(0);\n\n const lightboxItems = useMemo<MediaLightboxItem[]>(() => {\n return mediaItems.map(item => ({\n type: (item.attachment_type === 'video' ? 'video' : 'image') as 'image' | 'video',\n src: item.url,\n alt: item.file_name,\n posterSrc: item.thumb_url || undefined,\n }));\n }, [mediaItems]);\n\n const handleMediaClick = useCallback((url: string) => {\n const idx = mediaItems.findIndex(item => item.url === url);\n if (idx >= 0) {\n setLightboxIndex(idx);\n setLightboxOpen(true);\n }\n }, [mediaItems]);\n\n const closeLightbox = useCallback(() => {\n setLightboxOpen(false);\n }, []);\n\n // Group media into rows of 3 for grid layout inside VList\n const mediaRows = useMemo(() => {\n const rows: AttachmentItem[][] = [];\n for (let i = 0; i < mediaItems.length; i += 3) {\n rows.push(mediaItems.slice(i, i + 3));\n }\n return rows;\n }, [mediaItems]);\n\n // Build VList children based on contentTab (deferred)\n const vlistChildren = useMemo(() => {\n switch (contentTab) {\n case 'members': {\n const items: React.ReactNode[] = [];\n if (onAddMemberClick) {\n if (AddMemberButtonComponent) {\n items.push(\n <div key=\"__add-member__\" className=\"ermis-channel-info__add-member-wrap\">\n <AddMemberButtonComponent onClick={onAddMemberClick} label={addMemberButtonLabel} />\n </div>\n );\n } else {\n items.push(\n <div key=\"__add-member__\" className=\"ermis-channel-info__add-member-wrap\">\n <button className=\"ermis-channel-info__add-member-btn\" onClick={onAddMemberClick}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\"></path>\n <circle cx=\"8.5\" cy=\"7\" r=\"4\"></circle>\n <line x1=\"20\" y1=\"8\" x2=\"20\" y2=\"14\"></line>\n <line x1=\"23\" y1=\"11\" x2=\"17\" y2=\"11\"></line>\n </svg>\n {addMemberButtonLabel}\n </button>\n </div>\n );\n }\n }\n sortedMembers.forEach(member => {\n const role = member.channel_role || CHANNEL_ROLES.MEMBER;\n const isTargetRemovable = canRemoveTargetMember(currentUserRole, role);\n\n const canRemove = Boolean(\n isTargetRemovable &&\n member.user_id !== currentUserId\n );\n\n const canBan = Boolean(\n canBanTargetMember(currentUserRole, role) &&\n member.user_id !== currentUserId &&\n !member.banned\n );\n\n const canUnban = Boolean(\n canBanTargetMember(currentUserRole, role) &&\n member.user_id !== currentUserId &&\n member.banned\n );\n\n const canPromote = canPromoteTargetMember(currentUserRole, role) && member.user_id !== currentUserId;\n\n const canDemote = canDemoteTargetMember(currentUserRole, role) && member.user_id !== currentUserId;\n\n items.push(\n <MemberItem\n key={member?.user_id}\n member={member}\n AvatarComponent={AvatarComponent}\n onRemove={onRemoveMember}\n canRemove={canRemove}\n onBan={onBanMember}\n canBan={canBan}\n onUnban={onUnbanMember}\n canUnban={canUnban}\n onPromote={onPromoteMember}\n canPromote={canPromote}\n onDemote={onDemoteMember}\n canDemote={canDemote}\n />\n );\n });\n return items;\n }\n case 'media':\n if (MediaItem === MediaGridItem) {\n // Default: use grid rows\n return mediaRows.map((row, rowIdx) => (\n <MediaRow key={row[0]?.id || rowIdx} row={row} onClick={handleMediaClick} />\n ));\n }\n // Custom: render each item individually\n return mediaItems.map((item, idx) => (\n <MediaItem key={item.id || idx} item={item} onClick={handleMediaClick} />\n ));\n case 'links':\n return linkItems.map((item, idx) => (\n <LinkItem key={item.id || idx} item={item} />\n ));\n case 'files':\n return fileItems.map((item, idx) => (\n <FileItem key={item.id || idx} item={item} onClick={handleOpenUrl} />\n ));\n default:\n return [];\n }\n }, [contentTab, sortedMembers, mediaRows, mediaItems, linkItems, fileItems, onAddMemberClick, AvatarComponent, handleMediaClick, handleOpenUrl, MemberItem, MediaItem, LinkItem, FileItem]);\n\n // Check if content is empty for the content tab (deferred)\n const isTabEmpty = vlistChildren.length === 0 && !(loading && contentTab !== 'members');\n const emptyLabel = contentTab === 'members' ? 'members' : contentTab;\n\n return (\n <div className=\"ermis-channel-info__section ermis-channel-info__media-section\">\n <div className=\"ermis-channel-info__media-tabs\">\n {availableTabs.map(tab => (\n <button\n key={tab}\n className={`ermis-channel-info__media-tab ${activeTab === tab ? 'ermis-channel-info__media-tab--active' : ''}`}\n onClick={() => setActiveTab(tab)}\n >\n <span className=\"ermis-channel-info__media-tab-label\">\n {tab.charAt(0).toUpperCase() + tab.slice(1)}\n </span>\n {tabCounts[tab] > 0 && (\n <span className=\"ermis-channel-info__media-tab-count\">{tabCounts[tab]}</span>\n )}\n </button>\n ))}\n </div>\n\n <div\n className=\"ermis-channel-info__media-content\"\n style={isPending ? PENDING_STYLE : READY_STYLE}\n >\n {loading && contentTab !== 'members' ? <Loading /> : isTabEmpty ? <EmptyState label={emptyLabel} /> : (\n <VList style={{ height: '100%' }}>\n {vlistChildren}\n </VList>\n )}\n </div>\n\n {/* Media Lightbox */}\n {lightboxItems.length > 0 && (\n <MediaLightbox\n items={lightboxItems}\n initialIndex={lightboxIndex}\n isOpen={lightboxOpen}\n onClose={closeLightbox}\n />\n )}\n </div>\n );\n});\n","import React, { useState, useMemo } from 'react';\nimport { preloadImage, isImagePreloaded } from '../../utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const MediaGridItem: React.FC<{\n item: AttachmentItem;\n onClick: (url: string) => void;\n}> = React.memo(({ item, onClick }) => {\n const src = item.thumb_url || item.url;\n const alreadyCached = isImagePreloaded(src);\n const [loaded, setLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n // Trigger background preload (no-op if already cached)\n useMemo(() => { preloadImage(src); }, [src]);\n\n // Fallback checks for browser cache when JS preload didn't catch it\n React.useEffect(() => {\n if (!loaded && imgRef.current?.complete) {\n setLoaded(true);\n }\n }, [loaded, src]);\n\n const isVideo = item.attachment_type === 'video';\n\n return (\n <div\n className=\"ermis-channel-info__media-item\"\n onClick={() => onClick(item.url)}\n title={item.file_name}\n >\n {/* Shimmer placeholder while loading */}\n {!loaded && <div className=\"ermis-channel-info__media-shimmer\" />}\n\n {isVideo ? (\n <div className=\"ermis-channel-info__media-video-thumb\">\n {item.thumb_url ? (\n <img\n ref={imgRef}\n src={item.thumb_url}\n alt={item.file_name || 'video'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n ) : (\n <video\n src={item.url}\n preload=\"metadata\"\n onLoadedData={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n )}\n <div className=\"ermis-channel-info__media-play-icon\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </div>\n </div>\n ) : (\n <img\n ref={imgRef}\n src={src}\n alt={item.file_name || 'media'}\n loading=\"lazy\"\n onLoad={() => setLoaded(true)}\n style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n )}\n </div>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(MediaGridItem as any).displayName = 'MediaGridItem';\n\nexport const MediaRow = React.memo(({ row, onClick }: { row: AttachmentItem[], onClick: (url: string) => void }) => {\n return (\n <div className=\"ermis-channel-info__media-grid-row\">\n {row.map(item => (\n <MediaGridItem key={item.id} item={item} onClick={onClick} />\n ))}\n {row.length < 3 && Array.from({ length: 3 - row.length }).map((_, i) => (\n <div key={`empty-${i}`} className=\"ermis-channel-info__media-item ermis-channel-info__media-item--empty\" />\n ))}\n </div>\n );\n}, (prev, next) => {\n if (prev.row.length !== next.row.length) return false;\n return prev.row.every((item, i) => item.id === next.row[i].id);\n});\n(MediaRow as any).displayName = 'MediaRow';\n","import React, { useState, useMemo } from 'react';\nimport { formatRelativeDate, extractDomain, isImagePreloaded, preloadImage } from '../../utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const LinkListItem: React.FC<{ item: AttachmentItem }> = React.memo(({ item }) => {\n const displayUrl = item.og_scrape_url || item.title_link || item.url;\n const domain = extractDomain(displayUrl);\n\n // Preload link preview image if available\n const imgSrc = item.image_url;\n const alreadyCached = imgSrc ? isImagePreloaded(imgSrc) : true;\n const [imgLoaded, setImgLoaded] = useState(alreadyCached);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n useMemo(() => { if (imgSrc) preloadImage(imgSrc); }, [imgSrc]);\n\n React.useEffect(() => {\n if (!imgLoaded && imgRef.current?.complete) {\n setImgLoaded(true);\n }\n }, [imgLoaded, imgSrc]);\n\n return (\n <a\n className=\"ermis-channel-info__link-item\"\n href={displayUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <div className=\"ermis-channel-info__link-icon\">\n {imgSrc ? (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {!imgLoaded && <div className=\"ermis-channel-info__media-shimmer\" style={{ borderRadius: '8px' }} />}\n <img\n ref={imgRef}\n src={imgSrc}\n alt=\"\"\n className=\"ermis-channel-info__link-preview-img\"\n loading=\"lazy\"\n onLoad={() => setImgLoaded(true)}\n style={{ opacity: imgLoaded ? 1 : 0, transition: 'opacity 0.3s ease-in-out' }}\n />\n </div>\n ) : (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n )}\n </div>\n <div className=\"ermis-channel-info__link-content\">\n <span className=\"ermis-channel-info__link-title\">\n {item.title || item.file_name || domain}\n </span>\n <span className=\"ermis-channel-info__link-domain\">{domain}</span>\n </div>\n <span className=\"ermis-channel-info__link-date\">{formatRelativeDate(item.created_at)}</span>\n </a>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(LinkListItem as any).displayName = 'LinkListItem';\n","import React from 'react';\nimport { formatFileSize, formatRelativeDate, getDisplayName } from '../../utils';\nimport { getFileIcon } from './utils';\nimport type { AttachmentItem } from '../../types';\n\nexport const FileListItem: React.FC<{\n item: AttachmentItem;\n onClick: (url: string) => void;\n}> = React.memo(({ item, onClick }) => {\n const displayName = getDisplayName(item.file_name);\n const ext = item.file_name.split('.').pop()?.toUpperCase() || 'FILE';\n\n return (\n <div\n className=\"ermis-channel-info__file-item\"\n onClick={() => onClick(item.url)}\n >\n <div className=\"ermis-channel-info__file-icon\">\n {getFileIcon(item.content_type, item.file_name)}\n <span className=\"ermis-channel-info__file-ext\">{ext}</span>\n </div>\n <div className=\"ermis-channel-info__file-info\">\n <span className=\"ermis-channel-info__file-name\" title={item.file_name}>\n {displayName}\n </span>\n <div className=\"ermis-channel-info__file-meta\">\n <span>{formatFileSize(item.content_length)}</span>\n <span className=\"ermis-channel-info__file-meta-dot\">·</span>\n <span>{formatRelativeDate(item.created_at)}</span>\n </div>\n </div>\n <button\n className=\"ermis-channel-info__file-download\"\n onClick={(e) => {\n e.stopPropagation();\n onClick(item.url);\n }}\n aria-label=\"Download\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n </div>\n );\n}, (prev, next) => prev.item.id === next.item.id);\n(FileListItem as any).displayName = 'FileListItem';\n","import React, { useState } from 'react';\nimport { Dropdown } from '../Dropdown';\nimport type { ChannelInfoMemberItemProps } from '../../types';\nimport { CHANNEL_ROLES } from '../../channelRoleUtils';\n\nexport const MemberListItem = React.memo(({\n member, AvatarComponent, \n onRemove, canRemove, \n onBan, canBan, \n onUnban, canUnban, \n onPromote, canPromote, \n onDemote, canDemote \n}: ChannelInfoMemberItemProps) => {\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n const isOpen = anchorRect !== null;\n\n if (!member) return null;\n const role = member.channel_role || CHANNEL_ROLES.MEMBER;\n const hasActions = canRemove || canBan || canUnban || canPromote || canDemote;\n\n return (\n <div className=\"ermis-channel-info__member-item\">\n <AvatarComponent image={member.user?.avatar} name={member.user?.name || member.user?.id} size={36} />\n <div className=\"ermis-channel-info__member-info\">\n <span className=\"ermis-channel-info__member-name\">{member.user?.name || member.user?.id}</span>\n <span className={`ermis-channel-info__member-role ermis-channel-info__member-role--${role.toLowerCase()}`}>\n {role.charAt(0).toUpperCase() + role.slice(1)}\n </span>\n </div>\n \n {hasActions && (\n <>\n <button\n className=\"ermis-channel-info__member-actions-btn\"\n onClick={(e) => {\n e.stopPropagation();\n setAnchorRect(e.currentTarget.getBoundingClientRect());\n }}\n aria-label=\"Member actions\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n </svg>\n </button>\n \n <Dropdown\n isOpen={isOpen}\n anchorRect={anchorRect}\n onClose={() => setAnchorRect(null)}\n align=\"right\"\n >\n <div className=\"ermis-dropdown__menu\">\n {canPromote && onPromote && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onPromote(member.user?.id || member.user_id); setAnchorRect(null); }}>Promote to Moder</button>\n )}\n {canDemote && onDemote && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onDemote(member.user?.id || member.user_id); setAnchorRect(null); }}>Demote to Member</button>\n )}\n {canBan && onBan && (\n <button className=\"ermis-dropdown__item ermis-dropdown__item--danger\" onClick={() => { onBan(member.user?.id || member.user_id); setAnchorRect(null); }}>Ban Member</button>\n )}\n {canUnban && onUnban && (\n <button className=\"ermis-dropdown__item\" onClick={() => { onUnban(member.user?.id || member.user_id); setAnchorRect(null); }}>Unban Member</button>\n )}\n {canRemove && onRemove && (\n <button className=\"ermis-dropdown__item ermis-dropdown__item--danger\" onClick={() => { onRemove(member.user?.id || member.user_id); setAnchorRect(null); }}>Remove from Channel</button>\n )}\n </div>\n </Dropdown>\n </>\n )}\n </div>\n );\n}, (prev, next) => {\n return prev.member?.user_id === next.member?.user_id &&\n prev.member?.channel_role === next.member?.channel_role &&\n prev.member?.banned === next.member?.banned &&\n prev.canRemove === next.canRemove &&\n prev.canBan === next.canBan &&\n prev.canUnban === next.canUnban &&\n prev.canPromote === next.canPromote &&\n prev.canDemote === next.canDemote;\n});\n(MemberListItem as any).displayName = 'MemberListItem';\n","import React from 'react';\n\nexport const TabEmptyState: React.FC<{ label: string }> = React.memo(({ label }) => (\n <div className=\"ermis-channel-info__media-empty\">\n <div className=\"ermis-channel-info__media-empty-icon\">\n {label === 'media' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n </svg>\n )}\n {label === 'links' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\n </svg>\n )}\n {label === 'files' && (\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n )}\n </div>\n <span>No {label} shared yet</span>\n </div>\n));\n(TabEmptyState as any).displayName = 'TabEmptyState';\n\nexport const TabLoadingState: React.FC = React.memo(() => (\n <div className=\"ermis-channel-info__media-loading\">\n <div className=\"ermis-channel-info__media-spinner\" />\n </div>\n));\n(TabLoadingState as any).displayName = 'TabLoadingState';\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { Modal } from '../Modal';\nimport { UserPicker } from '../UserPicker';\nimport { Avatar } from '../Avatar';\nimport type { AddMemberModalProps, UserPickerUser } from '../../types';\n\nexport const AddMemberModal: React.FC<AddMemberModalProps> = ({\n channel,\n currentMembers,\n onClose,\n AvatarComponent = Avatar,\n title = 'Add Member',\n searchPlaceholder = 'Search by name, email or phone...',\n loadingText = 'Loading users...',\n emptyText = 'No users found.',\n addLabel = 'Add',\n addingLabel = 'Adding...',\n addedLabel = 'Added',\n UserItemComponent,\n SearchInputComponent,\n}) => {\n const [selectedUsers, setSelectedUsers] = useState<UserPickerUser[]>([]);\n const [isAdding, setIsAdding] = useState(false);\n\n // Exclude existing members from the picker\n const excludeUserIds = useMemo(\n () => currentMembers.map((m: any) => m.user_id),\n [currentMembers],\n );\n\n\n const handleSelectionChange = useCallback((users: UserPickerUser[]) => {\n setSelectedUsers(users);\n }, []);\n\n const handleAdd = useCallback(async () => {\n if (selectedUsers.length === 0 || isAdding) return;\n try {\n setIsAdding(true);\n await channel.addMembers(selectedUsers.map(u => u.id));\n onClose();\n } catch (err) {\n console.error('Failed to add members:', err);\n } finally {\n setIsAdding(false);\n }\n }, [selectedUsers, isAdding, channel, onClose]);\n\n const footer = (\n <button\n className=\"ermis-modal-add-btn\"\n onClick={handleAdd}\n disabled={selectedUsers.length === 0 || isAdding}\n >\n {isAdding\n ? addingLabel\n : `${addLabel} ${selectedUsers.length > 0 ? `(${selectedUsers.length})` : ''}`}\n </button>\n );\n\n return (\n <Modal isOpen onClose={onClose} title={title} maxWidth=\"480px\" footer={footer}>\n <UserPicker\n mode=\"checkbox\"\n onSelectionChange={handleSelectionChange}\n excludeUserIds={excludeUserIds}\n pageSize={30}\n AvatarComponent={AvatarComponent}\n UserItemComponent={UserItemComponent as any}\n SearchInputComponent={SearchInputComponent}\n searchPlaceholder={searchPlaceholder}\n loadingText={loadingText}\n emptyText={emptyText}\n selectedEmptyLabel=\"Select users to add...\"\n />\n </Modal>\n );\n};\n","import React, { useState, useEffect, useMemo, useCallback, useRef, useTransition } from 'react';\nimport { useChatClient } from '../hooks/useChatClient';\nimport { Avatar } from './Avatar';\nimport { VList, type VListHandle } from 'virtua';\nimport type {\n UserPickerProps,\n UserPickerItemProps,\n UserPickerSelectedBoxProps,\n UserPickerUser,\n} from '../types';\n\n/* ---------- Constants ---------- */\nconst DEFAULT_PAGE_SIZE = 30;\nconst SEARCH_DEBOUNCE_MS = 500;\n\n/* ---------- Static styles ---------- */\nconst LIST_STYLE: React.CSSProperties = { height: '100%' };\n\n/* ==========================================================\n Default Sub-Components\n ========================================================== */\n\n/** Check icon for selected state */\nconst CheckIcon: React.FC = () => (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n);\n\n/** Default user row */\nconst DefaultUserItem: React.FC<UserPickerItemProps> = React.memo(({\n user, selected, disabled, mode, onToggle, AvatarComponent,\n}) => {\n const handleClick = useCallback(() => {\n if (!disabled) onToggle(user);\n }, [disabled, onToggle, user]);\n\n const inputClass = [\n 'ermis-user-picker__input',\n mode === 'radio' ? 'ermis-user-picker__input--radio' : 'ermis-user-picker__input--checkbox',\n selected ? 'ermis-user-picker__input--checked' : '',\n ].join(' ');\n\n const itemClass = [\n 'ermis-user-picker__item',\n selected ? 'ermis-user-picker__item--selected' : '',\n disabled ? 'ermis-user-picker__item--disabled' : '',\n ].join(' ');\n\n const detail = user.email || user.phone || '';\n\n return (\n <div className={itemClass} onClick={handleClick} role=\"option\" aria-selected={selected}>\n <div className={inputClass}>\n {selected && <CheckIcon />}\n </div>\n <AvatarComponent image={user.avatar} name={user.name || user.id} size={36} />\n <div className=\"ermis-user-picker__info\">\n <span className=\"ermis-user-picker__name\">{user.name || user.id}</span>\n {detail && <span className=\"ermis-user-picker__detail\">{detail}</span>}\n </div>\n </div>\n );\n});\nDefaultUserItem.displayName = 'DefaultUserItem';\n\n/** Default search input */\nconst DefaultSearchInput: React.FC<{ value: string; onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; placeholder: string }> = ({ value, onChange, placeholder }) => (\n <div className=\"ermis-user-picker__search\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n type=\"text\"\n placeholder={placeholder}\n value={value}\n onChange={onChange}\n autoFocus\n />\n </div>\n);\n\n/** Default selected users chip box */\nconst DefaultSelectedBox: React.FC<UserPickerSelectedBoxProps> = React.memo(({\n users, onRemove, AvatarComponent, emptyLabel,\n}) => (\n <div className=\"ermis-user-picker__selected-box\">\n {users.length === 0 && emptyLabel && (\n <span className=\"ermis-user-picker__selected-empty\">{emptyLabel}</span>\n )}\n {users.map(u => (\n <div key={u.id} className=\"ermis-user-picker__chip\">\n <AvatarComponent image={u.avatar} name={u.name || u.id} size={20} />\n <span className=\"ermis-user-picker__chip-name\">{u.name || u.id}</span>\n <button\n className=\"ermis-user-picker__chip-remove\"\n onClick={() => onRemove(u.id)}\n aria-label={`Remove ${u.name || u.id}`}\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n ))}\n </div>\n));\nDefaultSelectedBox.displayName = 'DefaultSelectedBox';\n\n/* ==========================================================\n UserPicker Component\n ========================================================== */\n\nexport const UserPicker: React.FC<UserPickerProps> = ({\n mode,\n onSelectionChange,\n excludeUserIds,\n initialSelectedUsers,\n pageSize = DEFAULT_PAGE_SIZE,\n AvatarComponent = Avatar,\n UserItemComponent,\n SelectedBoxComponent,\n SearchInputComponent,\n searchPlaceholder = 'Search by name, email or phone...',\n loadingText = 'Loading users...',\n emptyText = 'No users found.',\n loadingMoreText = 'Loading more...',\n selectedEmptyLabel,\n}) => {\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n\n /* ---------- State ---------- */\n const [allUsers, setAllUsers] = useState<UserPickerUser[]>([]);\n const [page, setPage] = useState(1);\n const [hasMore, setHasMore] = useState(true);\n const [loading, setLoading] = useState(true);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const [remoteUsers, setRemoteUsers] = useState<UserPickerUser[]>([]);\n const [isSearching, setIsSearching] = useState(false);\n\n const [searchInput, setSearchInput] = useState('');\n const [search, setSearch] = useState('');\n const [isPendingFilter, startTransition] = useTransition();\n\n const [selectedMap, setSelectedMap] = useState<Map<string, UserPickerUser>>(() => {\n const map = new Map<string, UserPickerUser>();\n initialSelectedUsers?.forEach(u => map.set(u.id, u));\n return map;\n });\n\n const vlistRef = useRef<VListHandle>(null);\n\n /* ---------- Resolved sub-components ---------- */\n const UserRow = UserItemComponent || DefaultUserItem;\n const SearchInput = SearchInputComponent || DefaultSearchInput;\n const SelectedBox = SelectedBoxComponent || DefaultSelectedBox;\n\n /* ---------- Excluded IDs set ---------- */\n const excludeSet = useMemo(() => new Set(excludeUserIds || []), [excludeUserIds]);\n\n /* ---------- Search handler ---------- */\n const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n setSearchInput(val);\n startTransition(() => {\n setSearch(val);\n });\n }, [startTransition]);\n\n /* ---------- 1. Fetch initial page ---------- */\n useEffect(() => {\n let active = true;\n const fetchUsers = async () => {\n if (!client) return;\n try {\n setLoading(true);\n const response = await client.queryUsers(String(pageSize), 1);\n if (active && response.data) {\n setAllUsers(response.data);\n setHasMore(response.data.length >= pageSize);\n setPage(1);\n }\n } catch (err) {\n console.error('[UserPicker] Error fetching users:', err);\n } finally {\n if (active) setLoading(false);\n }\n };\n fetchUsers();\n return () => { active = false; };\n }, [client, pageSize]);\n\n /* ---------- 2. Load more (infinite scroll) ---------- */\n const loadMore = useCallback(async () => {\n if (!client || loadingMore || !hasMore || search.trim()) return;\n const nextPage = page + 1;\n setLoadingMore(true);\n try {\n const response = await client.queryUsers(String(pageSize), nextPage);\n if (response.data) {\n setAllUsers(prev => {\n const existingIds = new Set(prev.map(u => u.id));\n const newUsers = response.data.filter((u: UserPickerUser) => !existingIds.has(u.id));\n return [...prev, ...newUsers];\n });\n setHasMore(response.data.length >= pageSize);\n setPage(nextPage);\n }\n } catch (err) {\n console.error('[UserPicker] Error loading more users:', err);\n } finally {\n setLoadingMore(false);\n }\n }, [client, loadingMore, hasMore, page, pageSize, search]);\n\n /* ---------- 3. Local filter ---------- */\n const localFilteredUsers = useMemo(() => {\n const term = search.toLowerCase().trim();\n if (!term) return allUsers;\n return allUsers.filter(u => {\n const name = (u.name || '').toLowerCase();\n const email = (u.email || '').toLowerCase();\n const phone = (u.phone || '').toLowerCase();\n return name.includes(term) || email.includes(term) || phone.includes(term);\n });\n }, [search, allUsers]);\n\n /* ---------- 4. Remote search fallback ---------- */\n useEffect(() => {\n if (!search.trim() || localFilteredUsers.length > 0) {\n setRemoteUsers([]);\n setIsSearching(false);\n return;\n }\n\n let cancelled = false;\n const timer = setTimeout(async () => {\n setIsSearching(true);\n try {\n const response = await client.searchUsers(1, 25, search.trim());\n if (!cancelled && response.data) {\n setRemoteUsers(response.data);\n }\n } catch (err) {\n console.error('[UserPicker] Error searching remote users:', err);\n } finally {\n if (!cancelled) setIsSearching(false);\n }\n }, SEARCH_DEBOUNCE_MS);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n }, [search, localFilteredUsers.length, client]);\n\n /* ---------- 5. Derived display list ---------- */\n const usersToDisplay = (search.trim() && localFilteredUsers.length === 0)\n ? remoteUsers\n : localFilteredUsers;\n const isListLoading = loading || isSearching || isPendingFilter;\n\n /* ---------- 6. Selection handlers ---------- */\n const handleToggle = useCallback((user: UserPickerUser) => {\n // Don't allow toggling disabled users (current user or excluded)\n if (user.id === currentUserId || excludeSet.has(user.id)) return;\n\n setSelectedMap(prev => {\n const next = new Map(prev);\n if (mode === 'radio') {\n // Radio: clear all, set this one (or deselect if same)\n if (next.has(user.id)) {\n next.clear();\n } else {\n next.clear();\n next.set(user.id, user);\n }\n } else {\n // Checkbox: toggle\n if (next.has(user.id)) {\n next.delete(user.id);\n } else {\n next.set(user.id, user);\n }\n }\n return next;\n });\n }, [mode, currentUserId, excludeSet]);\n\n // Notify parent of selection changes\n useEffect(() => {\n onSelectionChange?.(Array.from(selectedMap.values()));\n }, [selectedMap, onSelectionChange]);\n\n const handleRemoveSelected = useCallback((userId: string) => {\n setSelectedMap(prev => {\n const next = new Map(prev);\n next.delete(userId);\n return next;\n });\n }, []);\n\n /* ---------- 7. Scroll handler for infinite scroll ---------- */\n const handleScroll = useCallback((offset: number) => {\n // VList provides scroll offset. We detect near-bottom using the ref\n const el = vlistRef.current;\n if (!el) return;\n // scrollSize = total scroll height, viewportSize = visible height\n const scrollSize = (el as any).scrollSize ?? 0;\n const viewportSize = (el as any).viewportSize ?? 0;\n if (scrollSize > 0 && offset + viewportSize >= scrollSize - 50) {\n loadMore();\n }\n }, [loadMore]);\n\n /* ---------- Render ---------- */\n const selectedArr = useMemo(() => Array.from(selectedMap.values()), [selectedMap]);\n\n return (\n <div className=\"ermis-user-picker\" role=\"listbox\" aria-multiselectable={mode === 'checkbox'}>\n {/* Selected Users Box (checkbox mode only) */}\n {mode === 'checkbox' && (\n <SelectedBox\n users={selectedArr}\n onRemove={handleRemoveSelected}\n AvatarComponent={AvatarComponent}\n emptyLabel={selectedEmptyLabel}\n />\n )}\n\n {/* Search Input */}\n <SearchInput\n value={searchInput}\n onChange={handleSearchChange}\n placeholder={searchPlaceholder}\n />\n\n {/* User List */}\n <div className=\"ermis-user-picker__list\">\n {isListLoading ? (\n <div className=\"ermis-user-picker__loading\">\n <span className=\"ermis-user-picker__spinner\" />\n {loadingText}\n </div>\n ) : usersToDisplay.length === 0 ? (\n <div className=\"ermis-user-picker__empty\">{emptyText}</div>\n ) : (\n <VList ref={vlistRef} style={LIST_STYLE} onScroll={handleScroll}>\n {usersToDisplay.map(user => (\n <UserRow\n key={user.id}\n user={user}\n selected={selectedMap.has(user.id)}\n disabled={user.id === currentUserId || excludeSet.has(user.id)}\n mode={mode}\n onToggle={handleToggle}\n AvatarComponent={AvatarComponent}\n />\n ))}\n {loadingMore && (\n <div className=\"ermis-user-picker__load-more\">\n <span className=\"ermis-user-picker__spinner\" />\n {loadingMoreText}\n </div>\n )}\n </VList>\n )}\n </div>\n </div>\n );\n};\n\nUserPicker.displayName = 'UserPicker';\n","import React, { useState, useRef, useCallback, useEffect } from 'react';\nimport { Modal } from '../Modal';\nimport type { EditChannelModalProps, EditChannelData } from '../../types';\nimport { isGroupChannel } from '../../channelTypeUtils';\n\nconst DEFAULT_MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5MB\n\nexport const EditChannelModal: React.FC<EditChannelModalProps> = React.memo(({\n channel,\n onClose,\n onSave,\n AvatarComponent,\n title = 'Edit Channel',\n nameLabel = 'Channel Name',\n descriptionLabel = 'Description',\n namePlaceholder = 'Enter channel name',\n descriptionPlaceholder = 'Enter channel description',\n publicLabel = 'Public Channel',\n saveLabel = 'Save',\n cancelLabel = 'Cancel',\n savingLabel = 'Saving...',\n changeAvatarLabel = 'Change Avatar',\n imageAccept = 'image/*',\n maxImageSize = DEFAULT_MAX_IMAGE_SIZE,\n maxImageSizeError = 'Image must be less than 5MB',\n}) => {\n // Original values from channel data\n const originalName = (channel.data?.name as string) || '';\n const originalImage = (channel.data?.image as string) || '';\n const originalDescription = (channel.data?.description as string) || '';\n const originalPublic = Boolean(channel.data?.public);\n const isTeamOrMeetingChannel = isGroupChannel(channel);\n\n // Form state\n const [name, setName] = useState(originalName);\n const [description, setDescription] = useState(originalDescription);\n const [isPublic, setIsPublic] = useState(originalPublic);\n const [previewUrl, setPreviewUrl] = useState<string | null>(null);\n const [selectedFile, setSelectedFile] = useState<File | null>(null);\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // Clean up object URL on unmount or when preview changes\n useEffect(() => {\n return () => {\n if (previewUrl) URL.revokeObjectURL(previewUrl);\n };\n }, [previewUrl]);\n\n const handleFileSelect = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n // Validate it's an image\n if (!file.type.startsWith('image/')) {\n setError('Only image files are allowed');\n return;\n }\n\n // Validate size\n if (file.size > maxImageSize) {\n setError(maxImageSizeError);\n return;\n }\n\n setError(null);\n // Revoke previous preview\n if (previewUrl) URL.revokeObjectURL(previewUrl);\n const url = URL.createObjectURL(file);\n setPreviewUrl(url);\n setSelectedFile(file);\n\n // Reset input so same file can be re-selected\n e.target.value = '';\n }, [maxImageSize, maxImageSizeError, previewUrl]);\n\n const handleAvatarClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n // Check if anything changed — only send changed fields\n const buildPayload = useCallback((): EditChannelData | null => {\n const payload: EditChannelData = {};\n let hasChanges = false;\n\n if (name.trim() !== originalName) {\n payload.name = name.trim();\n hasChanges = true;\n }\n if (description.trim() !== originalDescription) {\n payload.description = description.trim();\n hasChanges = true;\n }\n if (isTeamOrMeetingChannel && isPublic !== originalPublic) {\n payload.public = isPublic;\n hasChanges = true;\n }\n // Image is handled separately (upload first), but mark as changed\n if (selectedFile) {\n hasChanges = true;\n }\n\n return hasChanges ? payload : null;\n }, [name, description, isPublic, selectedFile, originalName, originalDescription, originalPublic, isTeamOrMeetingChannel]);\n\n const handleSave = useCallback(async () => {\n const payload = buildPayload();\n if (!payload && !selectedFile) {\n onClose();\n return;\n }\n\n setIsSaving(true);\n setError(null);\n\n try {\n // If consumer provides custom save handler, delegate entirely\n if (onSave) {\n if (selectedFile) {\n const response = await channel.sendFile(selectedFile, selectedFile.name, selectedFile.type);\n (payload || {} as EditChannelData).image = response.file;\n }\n await onSave(payload || {});\n onClose();\n return;\n }\n\n // Default save logic\n const finalPayload: EditChannelData = payload || {};\n\n // Upload image if changed\n if (selectedFile) {\n const response = await channel.sendFile(selectedFile, selectedFile.name, selectedFile.type);\n finalPayload.image = response.file;\n }\n\n // Only call update if there's something to update\n if (Object.keys(finalPayload).length > 0) {\n await channel.update(finalPayload as any);\n }\n\n onClose();\n } catch (err: any) {\n setError(err?.message || 'Failed to update channel');\n } finally {\n setIsSaving(false);\n }\n }, [buildPayload, selectedFile, onSave, channel, onClose]);\n\n // Determine displayed avatar image\n const displayImage = previewUrl || originalImage || undefined;\n\n const footerContent = (\n <div className=\"ermis-channel-info__edit-footer-buttons\">\n <button\n className=\"ermis-channel-info__edit-btn ermis-channel-info__edit-btn--cancel\"\n onClick={onClose}\n disabled={isSaving}\n >\n {cancelLabel}\n </button>\n <button\n className=\"ermis-channel-info__edit-btn ermis-channel-info__edit-btn--save\"\n onClick={handleSave}\n disabled={isSaving}\n >\n {isSaving ? savingLabel : saveLabel}\n </button>\n </div>\n );\n\n return (\n <Modal\n isOpen={true}\n onClose={isSaving ? () => {} : onClose}\n title={title}\n footer={footerContent}\n maxWidth=\"420px\"\n >\n <div className=\"ermis-channel-info__edit-body\">\n {/* Avatar section */}\n <div className=\"ermis-channel-info__edit-avatar-section\">\n <div className=\"ermis-channel-info__edit-avatar-wrap\" onClick={handleAvatarClick}>\n <AvatarComponent image={displayImage} name={name || originalName} size={80} />\n <div className=\"ermis-channel-info__edit-avatar-overlay\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z\" />\n <circle cx=\"12\" cy=\"13\" r=\"4\" />\n </svg>\n </div>\n </div>\n <button\n className=\"ermis-channel-info__edit-avatar-btn\"\n onClick={handleAvatarClick}\n type=\"button\"\n disabled={isSaving}\n >\n {changeAvatarLabel}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={imageAccept}\n onChange={handleFileSelect}\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n />\n </div>\n\n {/* Name field */}\n <div className=\"ermis-channel-info__edit-field\">\n <label className=\"ermis-channel-info__edit-label\">{nameLabel}</label>\n <input\n className=\"ermis-channel-info__edit-input\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={namePlaceholder}\n disabled={isSaving}\n maxLength={100}\n />\n </div>\n\n {/* Description field */}\n <div className=\"ermis-channel-info__edit-field\">\n <label className=\"ermis-channel-info__edit-label\">{descriptionLabel}</label>\n <textarea\n className=\"ermis-channel-info__edit-textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={descriptionPlaceholder}\n disabled={isSaving}\n rows={3}\n maxLength={500}\n />\n </div>\n\n {/* Public toggle — only for team channels */}\n {isTeamOrMeetingChannel && (\n <div className=\"ermis-channel-info__edit-field ermis-channel-info__edit-field--toggle\">\n <label className=\"ermis-channel-info__edit-label\">{publicLabel}</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPublic}\n className={`ermis-channel-info__edit-toggle ${isPublic ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => setIsPublic(v => !v)}\n disabled={isSaving}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"ermis-channel-info__edit-error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n </div>\n </Modal>\n );\n});\n\nEditChannelModal.displayName = 'EditChannelModal';\n","import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';\nimport type { Channel } from '@ermis-network/ermis-chat-sdk';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport { replaceMentionsForPreview, buildUserMap, formatRelativeDate } from '../../utils';\nimport { Avatar } from '../Avatar';\nimport { Panel } from '../Panel';\nimport type { AvatarProps, SearchResultMessage, MessageSearchPanelProps } from '../../types';\n\n/* ----------------------------------------------------------\n Highlight utility (Accent-insensitive)\n ---------------------------------------------------------- */\nconst removeAccents = (str: string) => str.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');\n\nconst HighlightedText: React.FC<{ text: string; term: string }> = React.memo(({ text, term }) => {\n if (!term.trim()) return <>{text}</>;\n\n const cleanTerm = removeAccents(term).toLowerCase();\n if (!cleanTerm) return <>{text}</>;\n\n const parts = [];\n let currentIndex = 0;\n const cleanText = removeAccents(text).toLowerCase();\n\n while (true) {\n const startMatch = cleanText.indexOf(cleanTerm, currentIndex);\n if (startMatch === -1) {\n if (currentIndex < text.length) {\n parts.push(<span key={currentIndex}>{text.slice(currentIndex)}</span>);\n }\n break;\n }\n\n if (startMatch > currentIndex) {\n parts.push(<span key={`text-${currentIndex}`}>{text.slice(currentIndex, startMatch)}</span>);\n }\n\n const endMatch = startMatch + cleanTerm.length;\n parts.push(\n <mark key={`mark-${startMatch}`} className=\"ermis-search-panel__highlight\">\n {text.slice(startMatch, endMatch)}\n </mark>\n );\n\n currentIndex = endMatch;\n }\n\n return <>{parts.length > 0 ? parts : text}</>;\n});\nHighlightedText.displayName = 'HighlightedText';\n\n/* ----------------------------------------------------------\n MessageSearchPanel\n ---------------------------------------------------------- */\nexport const MessageSearchPanel: React.FC<MessageSearchPanelProps> = React.memo(({\n isOpen,\n onClose,\n channel,\n AvatarComponent = Avatar,\n placeholder = 'Search messages...',\n title = 'Search Messages',\n emptyText = 'No messages found',\n loadingText = 'Searching...',\n debounceMs = 500,\n}) => {\n const { setJumpToMessageId } = useChatClient();\n\n const [query, setQuery] = useState('');\n const [results, setResults] = useState<SearchResultMessage[]>([]);\n const [loading, setLoading] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const offsetRef = useRef(0);\n const queryRef = useRef('');\n\n // Reset all state when the channel changes (or panel closes)\n useEffect(() => {\n setQuery('');\n setResults([]);\n setLoading(false);\n setHasMore(false);\n setLoadingMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n }, [channel?.cid, isOpen]);\n\n // Auto-focus the input when panel opens\n useEffect(() => {\n if (isOpen) {\n setTimeout(() => inputRef.current?.focus(), 300);\n }\n }, [isOpen]);\n\n // Debounced search\n const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value;\n setQuery(value);\n\n if (debounceRef.current) clearTimeout(debounceRef.current);\n\n if (!value.trim()) {\n setResults([]);\n setLoading(false);\n setHasMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n return;\n }\n\n setLoading(true);\n\n debounceRef.current = setTimeout(async () => {\n queryRef.current = value;\n offsetRef.current = 0;\n\n try {\n const response = await channel.searchMessage(value, 0);\n // Only apply if this is still the latest query\n if (queryRef.current !== value) return;\n\n if (!response) {\n setResults([]);\n setHasMore(false);\n } else {\n setResults(response.messages || []);\n setHasMore((response.messages?.length || 0) >= 25);\n }\n } catch (err) {\n console.error('Search failed:', err);\n setResults([]);\n setHasMore(false);\n } finally {\n setLoading(false);\n }\n }, debounceMs);\n }, [channel, debounceMs]);\n\n // Infinite scroll: load more results\n const handleLoadMore = useCallback(async () => {\n if (loadingMore || !hasMore || !queryRef.current) return;\n\n setLoadingMore(true);\n const nextOffset = offsetRef.current + 25; // offset skips records, limit is 25\n\n try {\n const response = await channel.searchMessage(queryRef.current, nextOffset);\n\n if (!response || !response.messages?.length) {\n setHasMore(false);\n } else {\n offsetRef.current = nextOffset;\n setResults((prev) => [...prev, ...response.messages]);\n setHasMore(response.messages.length >= 25);\n }\n } catch (err) {\n console.error('Load more search results failed:', err);\n } finally {\n setLoadingMore(false);\n }\n }, [channel, hasMore, loadingMore]);\n\n // Scroll handler for infinite scroll\n const handleScroll = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n const threshold = 100;\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - threshold) {\n handleLoadMore();\n }\n }, [handleLoadMore]);\n\n // Click a result -> jump to that message\n const handleResultClick = useCallback((messageId: string) => {\n setJumpToMessageId(messageId);\n }, [setJumpToMessageId]);\n\n // Derived userMap for resolving mentions, with a lowercase variant for fast lookup\n const userMaps = useMemo(() => {\n const original = buildUserMap(channel.state);\n const lower: typeof original = {};\n for (const [id, name] of Object.entries(original)) {\n lower[id.toLowerCase()] = name;\n }\n return { original, lower };\n }, [channel.state]);\n\n return (\n <Panel isOpen={isOpen} onClose={onClose} title={title} className=\"ermis-search-panel\">\n {/* Search Input now inside body */}\n <div className=\"ermis-search-panel__search-box\">\n <div className=\"ermis-search-panel__input-wrap\">\n <svg className=\"ermis-search-panel__input-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n ref={inputRef}\n className=\"ermis-search-panel__input\"\n type=\"text\"\n value={query}\n onChange={handleInputChange}\n placeholder={placeholder}\n />\n {query && (\n <button\n className=\"ermis-search-panel__input-clear\"\n onClick={() => {\n setQuery('');\n setResults([]);\n setHasMore(false);\n offsetRef.current = 0;\n queryRef.current = '';\n inputRef.current?.focus();\n }}\n aria-label=\"Clear\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n <div\n ref={scrollRef}\n className=\"ermis-search-panel__results\"\n onScroll={handleScroll}\n >\n {/* Initial state — no query yet */}\n {!query.trim() && !loading && results.length === 0 && (\n <div className=\"ermis-search-panel__idle\">\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <span>{placeholder}</span>\n </div>\n )}\n\n {/* Loading state */}\n {loading && (\n <div className=\"ermis-search-panel__loading\">\n <div className=\"ermis-search-panel__spinner\" />\n <span>{loadingText}</span>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && query.trim() && results.length === 0 && (\n <div className=\"ermis-search-panel__empty\">\n <span>{emptyText}</span>\n </div>\n )}\n\n {/* Results */}\n {!loading && results.map((msg) => {\n let parsedText = '';\n if (msg.text) {\n // Try standard replacement first\n parsedText = replaceMentionsForPreview(msg.text, msg as any, userMaps.original);\n // Fallback: search API may omit mentioned_users array, so we map @0x IDs efficiently\n if (/@0x[a-fA-F0-9]+/i.test(parsedText)) {\n parsedText = parsedText.replace(/@0x[a-fA-F0-9]+/gi, (match) => {\n const matchedId = match.slice(1).toLowerCase();\n return userMaps.lower[matchedId] ? `@${userMaps.lower[matchedId]}` : match;\n });\n }\n }\n\n return (\n <div\n key={msg.id}\n role=\"button\"\n tabIndex={0}\n className=\"ermis-search-panel__result-item\"\n onClick={() => handleResultClick(msg.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleResultClick(msg.id);\n }\n }}\n >\n <AvatarComponent\n image={msg.user?.avatar || msg.user?.image || msg.user?.avatar_url}\n name={msg.user?.name || msg.user_id}\n size={36}\n />\n <div className=\"ermis-search-panel__result-body\">\n <div className=\"ermis-search-panel__result-meta\">\n <span className=\"ermis-search-panel__result-name\">\n {msg.user?.name || msg.user_id || 'Unknown'}\n </span>\n <span className=\"ermis-search-panel__result-time\">\n {msg.created_at ? formatRelativeDate(msg.created_at) : ''}\n </span>\n </div>\n <p className=\"ermis-search-panel__result-text\">\n {parsedText ? (\n <HighlightedText text={parsedText} term={query} />\n ) : (\n <em>Attachment</em>\n )}\n </p>\n </div>\n </div>\n );\n })}\n\n {/* End of results indicator */}\n {!loading && !loadingMore && !hasMore && results.length > 0 && query.trim() && (\n <div className=\"ermis-search-panel__end-indicator\">\n <span>{emptyText}</span>\n </div>\n )}\n\n {/* Loading more indicator */}\n {loadingMore && (\n <div className=\"ermis-search-panel__loading-more\">\n <div className=\"ermis-search-panel__spinner ermis-search-panel__spinner--small\" />\n </div>\n )}\n </div>\n </Panel>\n );\n});\nMessageSearchPanel.displayName = 'MessageSearchPanel';\n","import React, { useEffect, useRef } from 'react';\n\nexport type PanelProps = {\n /** Whether the panel is visible */\n isOpen: boolean;\n /** Called when user clicks the back button */\n onClose: () => void;\n /** Panel title shown in the header */\n title?: string;\n /** Panel body content */\n children: React.ReactNode;\n /** Optional header content (replaces default title + back button) */\n headerContent?: React.ReactNode;\n /** Additional CSS class name */\n className?: string;\n};\n\n/**\n * Reusable sliding panel component.\n * Slides in from the right to overlay itself on whatever container it's placed in.\n * Use it like a Modal but inside a sidebar — call `isOpen` to show/hide.\n */\nexport const Panel: React.FC<PanelProps> = React.memo(({\n isOpen,\n onClose,\n title,\n children,\n headerContent,\n className,\n}) => {\n const panelRef = useRef<HTMLDivElement>(null);\n\n // Focus trap: focus the panel when it opens for accessibility\n useEffect(() => {\n if (isOpen && panelRef.current) {\n panelRef.current.focus();\n }\n }, [isOpen]);\n\n return (\n <div\n ref={panelRef}\n className={`ermis-panel${isOpen ? ' ermis-panel--open' : ''}${className ? ` ${className}` : ''}`}\n tabIndex={-1}\n >\n {headerContent ? (\n headerContent\n ) : (\n <div className=\"ermis-panel__header\">\n <button className=\"ermis-panel__back\" onClick={onClose} aria-label=\"Back\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n {title && <h3 className=\"ermis-panel__title\">{title}</h3>}\n </div>\n )}\n <div className=\"ermis-panel__body\">\n {children}\n </div>\n </div>\n );\n});\nPanel.displayName = 'Panel';\n","import React, { useState, useEffect } from 'react';\nimport { Panel } from '../Panel';\nimport { useChatClient } from '../../hooks/useChatClient';\nimport type { ChannelSettingsPanelProps } from '../../types';\nimport { isGroupChannel } from '../../channelTypeUtils';\nimport { CHANNEL_ROLES } from '../../channelRoleUtils';\n\nexport const ChannelSettingsPanel: React.FC<ChannelSettingsPanelProps> = React.memo(({\n isOpen,\n onClose,\n channel,\n title = 'Channel Settings',\n slowModeOptions = [\n { label: 'Off', value: 0 },\n { label: '10s', value: 10000 },\n { label: '30s', value: 30000 },\n { label: '1m', value: 60000 },\n { label: '5m', value: 300000 },\n { label: '15m', value: 900000 },\n { label: '1h', value: 3600000 },\n ],\n workspaceTopicsTitle = 'Workspace Topics',\n topicsFeatureName = 'Topics',\n topicsFeatureDescription = 'Enable sub-channels and discussions',\n}) => {\n // Config state\n const { client } = useChatClient();\n const currentUserId = client?.userID;\n const currentUserRole = currentUserId ? channel?.state?.members?.[currentUserId]?.channel_role : undefined;\n const isOwner = currentUserRole === CHANNEL_ROLES.OWNER;\n\n const [slowMode, setSlowMode] = useState<number>(0);\n const [topicsEnabled, setTopicsEnabled] = useState<boolean>(false);\n const [capabilities, setCapabilities] = useState<Record<string, boolean>>({\n 'send-message': true,\n 'send-links': true,\n 'update-own-message': true,\n 'delete-own-message': true,\n 'send-reaction': true,\n 'pin-message': true,\n 'create-poll': true,\n 'vote-poll': true,\n });\n\n const [keywords, setKeywords] = useState<string[]>([]);\n const [newKeyword, setNewKeyword] = useState('');\n const [isSaving, setIsSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Sync state when panel opens or channel updates\n useEffect(() => {\n if (!channel) return;\n\n const syncData = (dataToSync = channel.data) => {\n console.log('---syncData---', dataToSync);\n setSlowMode((dataToSync?.member_message_cooldown as number) || 0);\n setKeywords((dataToSync?.filter_words as string[]) || []);\n setTopicsEnabled(dataToSync?.topics_enabled === true);\n\n const caps = dataToSync?.member_capabilities as string[] || [];\n setCapabilities({\n 'send-message': caps.includes('send-message'),\n 'send-links': caps.includes('send-links'),\n 'update-own-message': caps.includes('update-own-message'),\n 'delete-own-message': caps.includes('delete-own-message'),\n 'send-reaction': caps.includes('send-reaction'),\n 'pin-message': caps.includes('pin-message'),\n 'create-poll': caps.includes('create-poll'),\n 'vote-poll': caps.includes('vote-poll'),\n });\n setError(null);\n };\n\n if (isOpen) {\n syncData();\n }\n\n // Listen to real-time changes\n const subscription = channel.on('channel.updated', (event: any) => {\n const latestData = event?.channel || channel.data;\n // Force mutating local channel.data to ensure future syncData hits cache\n if (event?.channel && channel.data) {\n Object.assign(channel.data, event.channel);\n }\n\n if (isOpen) {\n syncData(latestData);\n }\n });\n\n return () => {\n subscription?.unsubscribe();\n };\n }, [isOpen, channel]);\n\n const toggleCapability = (key: string) => {\n setCapabilities(prev => ({ ...prev, [key]: !prev[key] }));\n };\n\n // Compute dirty state\n const isSlowModeChanged = slowMode !== ((channel?.data?.member_message_cooldown as number) || 0);\n const isTopicsChanged = topicsEnabled !== (channel?.data?.topics_enabled === true);\n\n const currentKeywordsSorted = [...keywords].sort().join(',');\n const originalKeywordsSorted = [...((channel?.data?.filter_words as string[]) || [])].sort().join(',');\n const isKeywordsChanged = currentKeywordsSorted !== originalKeywordsSorted;\n\n const originalCapabilities = channel?.data?.member_capabilities as string[] || [];\n const initialCapabilities: Record<string, boolean> = {\n 'send-message': originalCapabilities.includes('send-message'),\n 'send-links': originalCapabilities.includes('send-links'),\n 'update-own-message': originalCapabilities.includes('update-own-message'),\n 'delete-own-message': originalCapabilities.includes('delete-own-message'),\n 'send-reaction': originalCapabilities.includes('send-reaction'),\n 'pin-message': originalCapabilities.includes('pin-message'),\n 'create-poll': originalCapabilities.includes('create-poll'),\n 'vote-poll': originalCapabilities.includes('vote-poll'),\n };\n const isCapabilitiesChanged = Object.keys(capabilities).some(k => capabilities[k] !== initialCapabilities[k]);\n\n const isDirty = isSlowModeChanged || isKeywordsChanged || isCapabilitiesChanged || isTopicsChanged;\n\n const handleAddNewKeyword = () => {\n if (newKeyword.trim()) {\n const keyword = newKeyword.trim().toLowerCase();\n if (!keywords.includes(keyword)) {\n setKeywords(prev => [...prev, keyword]);\n }\n setNewKeyword('');\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleAddNewKeyword();\n }\n };\n\n const handeRemoveKeyword = (kw: string) => {\n setKeywords(prev => prev.filter(k => k !== kw));\n };\n\n const handleSave = async () => {\n if (!channel) return;\n setIsSaving(true);\n setError(null);\n try {\n const dataUpdates: any = {};\n let capabilitiesArray: string[] | null = null;\n\n if (isSlowModeChanged) {\n dataUpdates.member_message_cooldown = slowMode;\n }\n\n if (isKeywordsChanged) {\n dataUpdates.filter_words = keywords;\n }\n\n if (isCapabilitiesChanged) {\n const controlledKeys = Object.keys(capabilities);\n const originalCaps = (channel.data?.member_capabilities as string[]) || [];\n\n // Preserve unmanaged original capabilities (e.g. create-call, join-call)\n const unmanagedCaps = originalCaps.filter(c => !controlledKeys.includes(c));\n\n // Extract managed capabilities that are currently enabled (true)\n const managedEnabledCaps = controlledKeys.filter(k => capabilities[k as keyof typeof capabilities]);\n\n // Merge into the final payload array\n capabilitiesArray = [...unmanagedCaps, ...managedEnabledCaps];\n }\n\n if (Object.keys(dataUpdates).length > 0 || capabilitiesArray !== null) {\n const payload: any = {};\n\n if (Object.keys(dataUpdates).length > 0) {\n payload.data = dataUpdates;\n if (channel.data) Object.assign(channel.data, dataUpdates);\n }\n\n if (capabilitiesArray !== null) {\n payload.capabilities = capabilitiesArray;\n if (channel.data) {\n // Local fallback naming to keep UI synchronous\n channel.data.member_capabilities = capabilitiesArray;\n }\n }\n\n // Use _update instead of update to safely construct root-level payloads\n await (channel as any)._update(payload);\n }\n\n if (isTopicsChanged) {\n if (topicsEnabled) {\n await channel.enableTopics();\n } else {\n await channel.disableTopics();\n }\n }\n\n onClose();\n } catch (err: any) {\n setError(err?.message || 'Failed to update settings');\n } finally {\n setIsSaving(false);\n }\n };\n\n // We do NOT return null based on !isOpen so the sliding CSS transition is preserved.\n return (\n <Panel isOpen={isOpen} onClose={onClose} title={title} className=\"ermis-settings-panel\">\n\n {/* \n This wrapper creates a neat scrollable area with subtle gray background\n which makes white cards pop out smoothly.\n */}\n <div\n className=\"ermis-settings-panel__body\"\n style={{\n flex: 1,\n minHeight: 0,\n padding: '16px',\n overflowY: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '16px',\n background: 'var(--ermis-bg-secondary)'\n }}\n >\n\n {/* Section 1: Permissions */}\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'var(--ermis-color-primary-light)', padding: '4px', borderRadius: '8px', color: 'var(--ermis-color-primary)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\" />\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n Member Permissions\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__field\" style={{ marginBottom: '16px' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Slow Mode\n </label>\n <div style={{ position: 'relative' }}>\n <select\n value={slowMode}\n onChange={e => setSlowMode(Number(e.target.value))}\n style={{\n width: '100%',\n padding: '10px 12px',\n borderRadius: '8px',\n border: '1px solid var(--ermis-border-color)',\n background: 'var(--ermis-bg-secondary)',\n color: 'var(--ermis-text-primary)',\n fontSize: '14px',\n fontWeight: 500,\n appearance: 'none',\n outline: 'none',\n cursor: isSaving ? 'not-allowed' : 'pointer',\n transition: 'border-color 0.2s'\n }}\n disabled={isSaving}\n >\n {slowModeOptions.map(opt => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n <div style={{ position: 'absolute', right: '14px', top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none', color: 'var(--ermis-text-secondary)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n </div>\n </div>\n\n <div className=\"ermis-settings-panel__toggles\" style={{ display: 'flex', flexDirection: 'column' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Capabilities\n </label>\n <div style={{ background: 'var(--ermis-bg-secondary)', borderRadius: '8px', overflow: 'hidden', border: '1px solid var(--ermis-border-color)' }}>\n {Object.entries(capabilities).map(([key, value], index, arr) => (\n <div\n key={key}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 14px',\n borderBottom: index < arr.length - 1 ? '1px solid var(--ermis-border-color)' : 'none'\n }}\n >\n <span style={{ fontSize: '14px', fontWeight: 500, color: 'var(--ermis-text-primary)' }}>\n {key.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}\n </span>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={value}\n className={`ermis-channel-info__edit-toggle ${value ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => toggleCapability(key)}\n disabled={isSaving}\n style={{ transform: 'scale(0.85)', transformOrigin: 'right center' }}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n ))}\n </div>\n </div>\n </section>\n\n {/* Section 2: Content Moderation */}\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'var(--ermis-color-danger-light)', padding: '4px', borderRadius: '8px', color: 'var(--ermis-color-danger)' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"></path>\n <line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"></line>\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line>\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n Content Moderation\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__field\" style={{ marginBottom: '16px' }}>\n <label style={{ display: 'block', marginBottom: '6px', fontWeight: 500, fontSize: '12px', color: 'var(--ermis-text-secondary)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>\n Keyword Filtering\n </label>\n <div style={{ display: 'flex', gap: '8px', position: 'relative' }}>\n <input\n type=\"text\"\n value={newKeyword}\n onChange={e => setNewKeyword(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type keyword and press Enter or Add...\"\n style={{\n flex: 1,\n minWidth: 0,\n padding: '10px 12px',\n borderRadius: '8px',\n border: '1px solid var(--ermis-border-color)',\n background: 'var(--ermis-bg-secondary)',\n color: 'var(--ermis-text-primary)',\n fontSize: '14px',\n outline: 'none'\n }}\n disabled={isSaving}\n />\n <button\n type=\"button\"\n onClick={handleAddNewKeyword}\n disabled={isSaving || !newKeyword.trim()}\n style={{\n padding: '0 12px',\n borderRadius: '8px',\n background: 'var(--ermis-color-primary-light)',\n color: 'var(--ermis-color-primary)',\n border: 'none',\n fontWeight: 600,\n fontSize: '13px',\n cursor: isSaving || !newKeyword.trim() ? 'not-allowed' : 'pointer',\n opacity: isSaving || !newKeyword.trim() ? 0.6 : 1,\n transition: 'opacity 0.2s',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center'\n }}\n >\n Add\n </button>\n </div>\n </div>\n\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', minHeight: '32px' }}>\n {keywords.map(kw => (\n <span\n key={kw}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n padding: '3px 8px',\n borderRadius: '16px',\n background: 'var(--ermis-color-danger-light)',\n color: 'var(--ermis-color-danger)',\n border: '1px solid rgba(239, 68, 68, 0.2)',\n fontSize: '12px',\n fontWeight: 600\n }}\n >\n {kw}\n <button\n onClick={() => handeRemoveKeyword(kw)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'transparent',\n border: 'none',\n cursor: 'pointer',\n padding: '2px',\n color: 'inherit',\n opacity: 0.8,\n }}\n disabled={isSaving}\n aria-label=\"Remove keyword\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </span>\n ))}\n {keywords.length === 0 && (\n <span style={{ fontSize: '14px', color: 'var(--ermis-text-secondary)', padding: '6px 0', fontStyle: 'italic' }}>\n No blacklisted keywords added.\n </span>\n )}\n </div>\n </section>\n\n {/* Section 3: Features */}\n {isGroupChannel(channel) && (\n <section\n className=\"ermis-settings-panel__section\"\n style={{\n background: 'var(--ermis-bg-primary)',\n padding: '16px',\n borderRadius: '12px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\n border: '1px solid var(--ermis-border-color)'\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', marginBottom: '16px', gap: '8px' }}>\n <div style={{ background: 'rgba(168, 85, 247, 0.1)', padding: '4px', borderRadius: '8px', color: '#a855f7' }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polygon points=\"12 2 2 7 12 12 22 7 12 2\"></polygon>\n <polyline points=\"2 17 12 22 22 17\"></polyline>\n <polyline points=\"2 12 12 17 22 12\"></polyline>\n </svg>\n </div>\n <h4 style={{ fontSize: '14px', color: 'var(--ermis-text-primary)', fontWeight: 600, margin: 0 }}>\n {workspaceTopicsTitle}\n </h4>\n </div>\n\n <div className=\"ermis-settings-panel__toggles\" style={{ display: 'flex', flexDirection: 'column' }}>\n <div style={{ background: 'var(--ermis-bg-secondary)', borderRadius: '8px', overflow: 'hidden', border: '1px solid var(--ermis-border-color)' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '10px 14px',\n }}\n >\n <div style={{ display: 'flex', flexDirection: 'column' }}>\n <span style={{ fontSize: '14px', fontWeight: 500, color: 'var(--ermis-text-primary)' }}>\n {topicsFeatureName}\n </span>\n <span style={{ fontSize: '12px', color: 'var(--ermis-text-secondary)', marginTop: '2px' }}>\n {topicsFeatureDescription}\n </span>\n {!isOwner && (\n <span style={{ fontSize: '11px', color: 'var(--ermis-color-danger)', marginTop: '4px', fontWeight: 500 }}>\n Only channel owner can change this.\n </span>\n )}\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={topicsEnabled}\n className={`ermis-channel-info__edit-toggle ${topicsEnabled ? 'ermis-channel-info__edit-toggle--on' : ''}`}\n onClick={() => isOwner && setTopicsEnabled(!topicsEnabled)}\n disabled={isSaving || !isOwner}\n style={{ transform: 'scale(0.85)', transformOrigin: 'right center', cursor: (!isOwner || isSaving) ? 'not-allowed' : 'pointer' }}\n >\n <span className=\"ermis-channel-info__edit-toggle-thumb\" />\n </button>\n </div>\n </div>\n </div>\n </section>\n )}\n\n\n </div>\n\n {/* Footer Area */}\n <div\n className=\"ermis-settings-panel__footer\"\n style={{\n flexShrink: 0,\n padding: '12px 16px',\n background: 'var(--ermis-bg-primary)',\n borderTop: '1px solid var(--ermis-border-color)',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px'\n }}\n >\n {error && (\n <div style={{ color: 'var(--ermis-color-danger)', fontSize: '13px', display: 'flex', alignItems: 'center', gap: '6px', fontWeight: 500 }}>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\" /><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" /><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" /></svg>\n {error}\n </div>\n )}\n <button\n onClick={handleSave}\n disabled={isSaving || !isDirty}\n style={{\n width: '100%',\n padding: '10px',\n borderRadius: '8px',\n background: 'var(--ermis-color-primary, #006eff)',\n color: '#ffffff',\n border: 'none',\n fontSize: '14px',\n fontWeight: 600,\n cursor: (isSaving || !isDirty) ? 'not-allowed' : 'pointer',\n opacity: (isSaving || !isDirty) ? 0.6 : 1,\n transition: 'all 0.2s ease',\n boxShadow: (isSaving || !isDirty) ? 'none' : '0 4px 12px rgba(0, 110, 255, 0.2)'\n }}\n >\n {isSaving ? (\n <span style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px' }}>\n <svg className=\"ermis-spinner\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\">\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\"></path>\n </svg>\n Saving...\n </span>\n ) : 'Save Updates'}\n </button>\n </div>\n\n </Panel>\n );\n});\n\nChannelSettingsPanel.displayName = 'ChannelSettingsPanel';\n","import React, { useState, useMemo, useCallback } from 'react';\nimport { Modal } from './Modal';\nimport { UserPicker } from './UserPicker';\nimport { Avatar } from './Avatar';\nimport { useChatClient } from '../hooks/useChatClient';\nimport type { CreateChannelModalProps, UserPickerUser } from '../types';\nimport { isDirectChannel } from '../channelTypeUtils';\n\n\nexport const CreateChannelModal: React.FC<CreateChannelModalProps> = ({\n isOpen,\n onClose,\n onSuccess,\n AvatarComponent = Avatar,\n UserItemComponent,\n title = 'New Message',\n directTabLabel = 'Direct',\n groupTabLabel = 'Group',\n groupNameLabel = 'Channel Name',\n groupNamePlaceholder = 'Enter channel name (required)',\n groupDescriptionLabel = 'Description',\n groupDescriptionPlaceholder = 'Optional description',\n groupPublicLabel = 'Public Channel',\n userSearchPlaceholder = 'Search users...',\n cancelButtonLabel = 'Cancel',\n createButtonLabel = 'Create',\n creatingButtonLabel = 'Creating...',\n messageButtonLabel = 'Message',\n}) => {\n const { client, setActiveChannel } = useChatClient();\n const currentUserId = client?.userID;\n\n /* ---------- State ---------- */\n const [tab, setTab] = useState<'messaging' | 'team'>('messaging');\n const [step, setStep] = useState<1 | 2>(1); // Only for team channel\n\n // Group specific\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [isPublic, setIsPublic] = useState(false);\n\n // Users\n const [selectedUsers, setSelectedUsers] = useState<UserPickerUser[]>([]);\n\n // Progress/Error\n const [isCreating, setIsCreating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /* ---------- Exclude IDs for Direct ---------- */\n const hasExistingDirectChannel = useMemo(() => {\n if (!client || !currentUserId || tab !== 'messaging' || selectedUsers.length === 0) return false;\n const targetUserId = selectedUsers[0].id;\n\n return Object.values(client.activeChannels).some((ch: any) => {\n if (isDirectChannel(ch) && ch.state?.members) {\n const membersList = Object.keys(ch.state.members);\n return membersList.length === 2 && \n membersList.includes(currentUserId) && \n membersList.includes(targetUserId);\n }\n return false;\n });\n }, [client, currentUserId, tab, selectedUsers]);\n\n /* ---------- Handlers ---------- */\n const handleCreate = useCallback(async () => {\n if (!client || !currentUserId || isCreating) return;\n\n // Validations\n if (selectedUsers.length === 0) {\n setError('Please select at least one user.');\n return;\n }\n\n if (tab === 'team' && !name.trim()) {\n setError('Group name is required.');\n return;\n }\n\n setIsCreating(true);\n setError(null);\n\n try {\n let createdChannel;\n\n if (tab === 'messaging') {\n const targetUserId = selectedUsers[0].id;\n\n // Try to find an existing direct channel locally\n const existingChannel = Object.values(client.activeChannels).find((ch: any) => {\n if (isDirectChannel(ch) && ch.state?.members) {\n const membersList = Object.keys(ch.state.members);\n return membersList.length === 2 && \n membersList.includes(currentUserId) && \n membersList.includes(targetUserId);\n }\n return false;\n });\n\n if (existingChannel) {\n if (setActiveChannel) setActiveChannel(existingChannel as any);\n if (onSuccess) {\n onSuccess(existingChannel as any);\n } else {\n onClose();\n }\n setIsCreating(false);\n return;\n }\n\n createdChannel = client.channel('messaging', {\n members: [currentUserId, targetUserId],\n } as any);\n const response = (await createdChannel.create()) as any;\n if (response?.channel?.id) {\n createdChannel = client.channel('messaging', response.channel.id);\n await createdChannel.watch();\n }\n } else {\n // Group Channel\n const memberIds = selectedUsers.map(member => member.id);\n // Ensure current user is in the group members\n if (!memberIds.includes(currentUserId)) {\n memberIds.push(currentUserId);\n }\n\n const payload: any = {\n name: name.trim(),\n members: memberIds,\n public: isPublic,\n };\n\n if (description.trim()) {\n payload.description = description.trim();\n }\n\n createdChannel = client.channel('team', payload);\n const response = (await createdChannel.create()) as any;\n if (response?.channel?.id) {\n createdChannel = client.channel('team', response.channel.id);\n await createdChannel.watch();\n }\n }\n\n if (setActiveChannel) {\n setActiveChannel(createdChannel);\n }\n\n // Cleanup and execute callback\n if (onSuccess) {\n onSuccess(createdChannel);\n } else {\n onClose();\n }\n\n } catch (err: any) {\n setError(err?.message || 'Failed to create channel');\n } finally {\n setIsCreating(false);\n }\n }, [client, currentUserId, isCreating, selectedUsers, tab, name, isPublic, description, onSuccess, onClose]);\n\n\n const isValid = useMemo(() => {\n if (tab === 'messaging' && selectedUsers.length === 0) return false;\n if (tab === 'team' && step === 1 && !name.trim()) return false;\n if (tab === 'team' && step === 2 && selectedUsers.length === 0) return false;\n return true;\n }, [selectedUsers, tab, name, step]);\n\n let footer;\n if (tab === 'messaging') {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={onClose} disabled={isCreating}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={handleCreate} disabled={isCreating || !isValid}>\n {isCreating ? creatingButtonLabel : (hasExistingDirectChannel ? messageButtonLabel : createButtonLabel)}\n </button>\n </div>\n );\n } else if (tab === 'team' && step === 1) {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={onClose} disabled={isCreating}>{cancelButtonLabel}</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={() => { setError(null); setStep(2); }} disabled={isCreating || !isValid}>\n Next\n </button>\n </div>\n );\n } else if (tab === 'team' && step === 2) {\n footer = (\n <div className=\"ermis-create-channel__footer\">\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--cancel\" onClick={() => { setError(null); setStep(1); }} disabled={isCreating}>Back</button>\n <button className=\"ermis-create-channel__btn ermis-create-channel__btn--create\" onClick={handleCreate} disabled={isCreating || !isValid}>\n {isCreating ? creatingButtonLabel : createButtonLabel}\n </button>\n </div>\n );\n }\n\n return (\n <Modal isOpen={isOpen} onClose={isCreating ? () => { } : onClose} title={title} maxWidth=\"480px\" footer={footer}>\n <div className=\"ermis-create-channel__body\">\n\n {/* Type Toggle */}\n <div className=\"ermis-create-channel__tabs\">\n <button\n className={`ermis-create-channel__tab ${tab === 'messaging' ? 'ermis-create-channel__tab--active' : ''}`}\n onClick={() => {\n setTab('messaging');\n setStep(1);\n setSelectedUsers([]);\n setError(null);\n }}\n disabled={isCreating}\n >\n {directTabLabel}\n </button>\n <button\n className={`ermis-create-channel__tab ${tab === 'team' ? 'ermis-create-channel__tab--active' : ''}`}\n onClick={() => {\n setTab('team');\n setStep(1);\n setSelectedUsers([]);\n setError(null);\n }}\n disabled={isCreating}\n >\n {groupTabLabel}\n </button>\n </div>\n\n {/* Group Specific Fields - Step 1 */}\n {tab === 'team' && step === 1 && (\n <>\n\n <div className=\"ermis-create-channel__field\">\n <label className=\"ermis-create-channel__label\">{groupNameLabel} <span style={{ color: 'var(--ermis-error)' }}>*</span></label>\n <input\n className=\"ermis-create-channel__input\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={groupNamePlaceholder}\n disabled={isCreating}\n maxLength={100}\n />\n </div>\n\n <div className=\"ermis-create-channel__field\">\n <label className=\"ermis-create-channel__label\">{groupDescriptionLabel}</label>\n <textarea\n className=\"ermis-create-channel__textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={groupDescriptionPlaceholder}\n disabled={isCreating}\n maxLength={500}\n rows={2}\n />\n </div>\n\n <div className=\"ermis-create-channel__field ermis-create-channel__field--toggle\">\n <label className=\"ermis-create-channel__label\">{groupPublicLabel}</label>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPublic}\n className={`ermis-create-channel__toggle ${isPublic ? 'ermis-create-channel__toggle--on' : ''}`}\n onClick={() => setIsPublic(v => !v)}\n disabled={isCreating}\n >\n <span className=\"ermis-create-channel__toggle-thumb\" />\n </button>\n </div>\n </>\n )}\n\n {/* User Selection - Step 2 (Group) or Step 1 (Messaging) */}\n {((tab === 'team' && step === 2) || tab === 'messaging') && (\n <div className=\"ermis-create-channel__users\">\n <div className=\"ermis-create-channel__users-title\">\n Members <span style={{ color: 'var(--ermis-error)' }}>*</span>\n </div>\n <div style={{ height: tab === 'team' ? '280px' : '400px', display: 'flex', flexDirection: 'column' }}>\n <UserPicker\n mode={tab === 'messaging' ? 'radio' : 'checkbox'}\n onSelectionChange={setSelectedUsers}\n initialSelectedUsers={selectedUsers}\n AvatarComponent={AvatarComponent}\n UserItemComponent={UserItemComponent as any}\n searchPlaceholder={userSearchPlaceholder}\n />\n </div>\n </div>\n )}\n\n {error && (\n <div className=\"ermis-create-channel__error\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n {error}\n </div>\n )}\n\n </div>\n </Modal>\n );\n};\n"],"mappings":"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","names":["import_react","import_react","React","import_react","import_react","import_react","import_jsx_runtime","import_react","import_react","import_react","import_jsx_runtime","React","ReactDOM","import_jsx_runtime","React","import_ermis_chat_sdk","import_jsx_runtime","React","import_jsx_runtime","import_react","import_react","ch","import_react","import_react","import_react","import_react","import_react","import_react","import_react","import_ermis_chat_sdk","import_react","import_jsx_runtime","React","import_react","import_react","import_react_dom","import_jsx_runtime","import_jsx_runtime","hasTopicsEnabled","React","import_jsx_runtime","React","image","import_react","import_react","import_ermis_chat_sdk","import_jsx_runtime","React","import_jsx_runtime","DefaultEmpty","React","import_react","import_jsx_runtime","React","import_react","import_virtua","import_react","import_ermis_chat_sdk","import_react","import_ermis_chat_sdk","import_react","client","import_react","import_react","import_react","import_jsx_runtime","React","import_react","import_react","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_ermis_chat_sdk","import_jsx_runtime","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_jsx_runtime","React","DefaultEmpty","import_react","import_react","import_react","import_ermis_chat_sdk","import_react","import_react","import_ermis_chat_sdk","import_react","import_jsx_runtime","React","import_react","import_virtua","import_jsx_runtime","React","import_react","import_ermis_chat_sdk","import_jsx_runtime","formatFileSize","getFileIcon","React","isImage","isVideo","import_react","import_jsx_runtime","MAX_PREVIEW_LENGTH","truncateText","React","import_react","import_jsx_runtime","MAX_PREVIEW_LENGTH","truncateText","getAttachmentSummary","React","import_jsx_runtime","React","import_react","import_react","import_virtua","import_react","import_jsx_runtime","React","isVideo","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_react","import_virtua","import_jsx_runtime","React","import_jsx_runtime","import_react","import_jsx_runtime","React","import_react","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_jsx_runtime","React","import_jsx_runtime","React","import_react","import_jsx_runtime"]}
|