UNPKG

stream-chat-react

Version:

React components to create chat conversations or livestream style chat

71 lines (70 loc) 6.29 kB
import React, { useCallback, useState } from 'react'; import { AttachmentSelector as DefaultAttachmentSelector, SimpleAttachmentSelector, } from './AttachmentSelector'; import { AttachmentPreviewList as DefaultAttachmentPreviewList } from './AttachmentPreviewList'; import { CooldownTimer as DefaultCooldownTimer } from './CooldownTimer'; import { SendButton as DefaultSendButton } from './SendButton'; import { StopAIGenerationButton as DefaultStopAIGenerationButton } from './StopAIGenerationButton'; import { AudioRecorder as DefaultAudioRecorder, RecordingPermissionDeniedNotification as DefaultRecordingPermissionDeniedNotification, StartRecordingAudioButton as DefaultStartRecordingAudioButton, RecordingPermission, } from '../MediaRecorder'; import { QuotedMessagePreview as DefaultQuotedMessagePreview, QuotedMessagePreviewHeader, } from './QuotedMessagePreview'; import { LinkPreviewList as DefaultLinkPreviewList } from './LinkPreviewList'; import { SendToChannelCheckbox as DefaultSendToChannelCheckbox } from './SendToChannelCheckbox'; import { TextareaComposer as DefaultTextareaComposer } from '../TextareaComposer'; import { AIStates, useAIState } from '../AIStateIndicator'; import { RecordingAttachmentType } from '../MediaRecorder/classes'; import { useChatContext } from '../../context/ChatContext'; import { useMessageInputContext } from '../../context/MessageInputContext'; import { useComponentContext } from '../../context/ComponentContext'; import { useAttachmentManagerState } from './hooks/useAttachmentManagerState'; import { useMessageContext } from '../../context'; import { WithDragAndDropUpload } from './WithDragAndDropUpload'; export const MessageInputFlat = () => { const { message } = useMessageContext(); const { asyncMessagesMultiSendEnabled, cooldownRemaining, handleSubmit, hideSendButton, recordingController, setCooldownRemaining, } = useMessageInputContext('MessageInputFlat'); const { AttachmentPreviewList = DefaultAttachmentPreviewList, AttachmentSelector = message ? SimpleAttachmentSelector : DefaultAttachmentSelector, AudioRecorder = DefaultAudioRecorder, CooldownTimer = DefaultCooldownTimer, EmojiPicker, LinkPreviewList = DefaultLinkPreviewList, QuotedMessagePreview = DefaultQuotedMessagePreview, RecordingPermissionDeniedNotification = DefaultRecordingPermissionDeniedNotification, SendButton = DefaultSendButton, SendToChannelCheckbox = DefaultSendToChannelCheckbox, StartRecordingAudioButton = DefaultStartRecordingAudioButton, StopAIGenerationButton: StopAIGenerationButtonOverride, TextareaComposer = DefaultTextareaComposer, } = useComponentContext(); const { channel } = useChatContext('MessageInputFlat'); const { aiState } = useAIState(channel); const stopGenerating = useCallback(() => channel?.stopAIResponse(), [channel]); const [showRecordingPermissionDeniedNotification, setShowRecordingPermissionDeniedNotification,] = useState(false); const closePermissionDeniedNotification = useCallback(() => { setShowRecordingPermissionDeniedNotification(false); }, []); const { attachments } = useAttachmentManagerState(); if (recordingController.recordingState) return React.createElement(AudioRecorder, null); const recordingEnabled = !!(recordingController.recorder && navigator.mediaDevices); // account for requirement on iOS as per this bug report: https://bugs.webkit.org/show_bug.cgi?id=252303 const isRecording = !!recordingController.recordingState; /** * This bit here is needed to make sure that we can get rid of the default behaviour * if need be. Essentially, this allows us to pass StopAIGenerationButton={null} and * completely circumvent the default logic if it's not what we want. We need it as a * prop because there is no other trivial way to override the SendMessage button otherwise. */ const StopAIGenerationButton = StopAIGenerationButtonOverride === undefined ? DefaultStopAIGenerationButton : StopAIGenerationButtonOverride; const shouldDisplayStopAIGeneration = [AIStates.Thinking, AIStates.Generating].includes(aiState) && !!StopAIGenerationButton; return (React.createElement(WithDragAndDropUpload, { className: 'str-chat__message-input', component: 'div' }, recordingEnabled && recordingController.permissionState === 'denied' && showRecordingPermissionDeniedNotification && (React.createElement(RecordingPermissionDeniedNotification, { onClose: closePermissionDeniedNotification, permissionName: RecordingPermission.MIC })), React.createElement(LinkPreviewList, null), React.createElement(QuotedMessagePreviewHeader, null), React.createElement("div", { className: 'str-chat__message-input-inner' }, React.createElement(AttachmentSelector, null), React.createElement("div", { className: 'str-chat__message-textarea-container' }, React.createElement(QuotedMessagePreview, null), React.createElement(AttachmentPreviewList, null), React.createElement("div", { className: 'str-chat__message-textarea-with-emoji-picker' }, React.createElement(TextareaComposer, null), EmojiPicker && React.createElement(EmojiPicker, null))), shouldDisplayStopAIGeneration ? (React.createElement(StopAIGenerationButton, { onClick: stopGenerating })) : (!hideSendButton && (React.createElement(React.Fragment, null, cooldownRemaining ? (React.createElement(CooldownTimer, { cooldownInterval: cooldownRemaining, setCooldownRemaining: setCooldownRemaining })) : (React.createElement(React.Fragment, null, React.createElement(SendButton, { sendMessage: handleSubmit }), recordingEnabled && (React.createElement(StartRecordingAudioButton, { disabled: isRecording || (!asyncMessagesMultiSendEnabled && attachments.some((a) => a.type === RecordingAttachmentType.VOICE_RECORDING)), onClick: () => { recordingController.recorder?.start(); setShowRecordingPermissionDeniedNotification(true); } })))))))), React.createElement(SendToChannelCheckbox, null))); };